Merge "Added onGesture(AccessibilityGestureInfo) for mulit-display"
diff --git a/Android.bp b/Android.bp
index ee3b396..7687270 100644
--- a/Android.bp
+++ b/Android.bp
@@ -136,7 +136,6 @@
         "core/java/android/content/pm/IDexModuleRegisterCallback.aidl",
         "core/java/android/content/pm/ILauncherApps.aidl",
         "core/java/android/content/pm/IOnAppsChangedListener.aidl",
-        "core/java/android/content/pm/IOnPermissionsChangeListener.aidl",
         "core/java/android/content/pm/IOtaDexopt.aidl",
         "core/java/android/content/pm/IPackageDataObserver.aidl",
         "core/java/android/content/pm/IPackageDeleteObserver.aidl",
@@ -278,6 +277,7 @@
         "core/java/android/os/storage/IStorageEventListener.aidl",
         "core/java/android/os/storage/IStorageShutdownObserver.aidl",
         "core/java/android/os/storage/IObbActionListener.aidl",
+        "core/java/android/permission/IOnPermissionsChangeListener.aidl",
         "core/java/android/permission/IPermissionController.aidl",
         "core/java/android/permission/IPermissionManager.aidl",
         ":keystore_aidl",
@@ -565,7 +565,7 @@
         "telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl",
         "telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl",
         "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
-        "telephony/java/android/telephony/ims/aidl/IRcs.aidl",
+        "telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl",
         "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
         "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
         "telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl",
@@ -1417,11 +1417,6 @@
     srcs_lib: "framework",
     srcs_lib_whitelist_dirs: frameworks_base_subdirs,
     srcs_lib_whitelist_pkgs: packages_to_document,
-    libs: [
-        "ext",
-        "framework",
-        "voip-common",
-    ],
     local_sourcepaths: frameworks_base_subdirs,
     installable: false,
     annotations_enabled: true,
diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
index 1f12ae6..f0c474b 100644
--- a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java
@@ -39,7 +39,6 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -51,9 +50,7 @@
 
 @RunWith(Parameterized.class)
 @LargeTest
-public class RelayoutPerfTest {
-    private static final IWindowSession sSession = WindowManagerGlobal.getWindowSession();
-
+public class RelayoutPerfTest extends WindowManagerPerfTestBase {
     private int mIteration;
 
     @Rule
@@ -85,12 +82,6 @@
         });
     }
 
-    @Before
-    public void setUp() {
-        getInstrumentation().getUiAutomation().executeShellCommand("input keyevent KEYCODE_WAKEUP");
-        getInstrumentation().getUiAutomation().executeShellCommand("wm dismiss-keyguard");
-    }
-
     @Test
     public void testRelayout() throws Throwable {
         final Activity activity = mActivityRule.getActivity();
@@ -154,8 +145,9 @@
         }
 
         void runBenchmark(BenchmarkState state) throws RemoteException {
+            final IWindowSession session = WindowManagerGlobal.getWindowSession();
             while (state.keepRunning()) {
-                sSession.relayout(mWindow, mSeq, mParams, mWidth, mHeight,
+                session.relayout(mWindow, mSeq, mParams, mWidth, mHeight,
                         mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame,
                         mOutOverscanInsets, mOutContentInsets, mOutVisibleInsets, mOutStableInsets,
                         mOutOutsets, mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration,
diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
new file mode 100644
index 0000000..a951869
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+
+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.view.Display;
+import android.view.DisplayCutout;
+import android.view.IWindowSession;
+import android.view.InputChannel;
+import android.view.InsetsState;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.internal.view.BaseIWindow;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+
+@LargeTest
+public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
+    @Rule
+    public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
+
+    @BeforeClass
+    public static void setUpClass() {
+        // Get the permission to use most window types.
+        sUiAutomation.adoptShellPermissionIdentity();
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        sUiAutomation.dropShellPermissionIdentity();
+    }
+
+    @Test
+    @ManualBenchmarkTest(warmupDurationNs = WARMUP_DURATION, targetTestDurationNs = TEST_DURATION)
+    public void testAddRemoveWindow() throws Throwable {
+        new TestWindow().runBenchmark(mPerfStatusReporter.getBenchmarkState());
+    }
+
+    private static class TestWindow extends BaseIWindow {
+        final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
+        final Rect mOutFrame = new Rect();
+        final Rect mOutContentInsets = new Rect();
+        final Rect mOutStableInsets = new Rect();
+        final Rect mOutOutsets = new Rect();
+        final DisplayCutout.ParcelableWrapper mOutDisplayCutout =
+                new DisplayCutout.ParcelableWrapper();
+        final InsetsState mOutInsetsState = new InsetsState();
+
+        TestWindow() {
+            mLayoutParams.setTitle(TestWindow.class.getName());
+            mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+            // Simulate as common phone window.
+            mLayoutParams.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+        }
+
+        void runBenchmark(ManualBenchmarkState state) throws RemoteException {
+            final IWindowSession session = WindowManagerGlobal.getWindowSession();
+            long elapsedTimeNs = 0;
+            while (state.keepRunning(elapsedTimeNs)) {
+                // InputChannel cannot be reused.
+                final InputChannel inputChannel = new InputChannel();
+
+                long startTime = SystemClock.elapsedRealtimeNanos();
+                session.addToDisplay(this, mSeq, mLayoutParams, View.VISIBLE,
+                        Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets,
+                        mOutOutsets, mOutDisplayCutout, inputChannel, mOutInsetsState);
+                final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
+                state.addExtraResult("add", elapsedTimeNsOfAdd);
+
+                startTime = SystemClock.elapsedRealtimeNanos();
+                session.remove(this);
+                final long elapsedTimeNsOfRemove = SystemClock.elapsedRealtimeNanos() - startTime;
+                state.addExtraResult("remove", elapsedTimeNsOfRemove);
+
+                elapsedTimeNs = elapsedTimeNsOfAdd + elapsedTimeNsOfRemove;
+            }
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
new file mode 100644
index 0000000..b2c6168
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
@@ -0,0 +1,37 @@
+/*
+ * 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 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.UiAutomation;
+
+import org.junit.Before;
+
+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;
+
+    @Before
+    public void setUp() {
+        // In order to be closer to the real use case.
+        sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        sUiAutomation.executeShellCommand("wm dismiss-keyguard");
+    }
+}
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 40778de..dd43ae7 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java
@@ -19,8 +19,13 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.os.Bundle;
+import android.util.ArrayMap;
 import android.util.Log;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.util.ArrayList;
 import java.util.concurrent.TimeUnit;
 
@@ -71,6 +76,8 @@
 
     private int mState = NOT_STARTED;  // Current benchmark state.
 
+    private long mWarmupDurationNs = WARMUP_DURATION_NS;
+    private long mTargetTestDurationNs = TARGET_TEST_DURATION_NS;
     private long mWarmupStartTime = 0;
     private int mWarmupIterations = 0;
 
@@ -79,12 +86,30 @@
     // Individual duration in nano seconds.
     private ArrayList<Long> mResults = new ArrayList<>();
 
+    /** @see #addExtraResult(String, long) */
+    private ArrayMap<String, ArrayList<Long>> mExtraResults;
+
     // Statistics. These values will be filled when the benchmark has finished.
     // The computation needs double precision, but long int is fine for final reporting.
     private Stats mStats;
 
+    void configure(ManualBenchmarkTest testAnnotation) {
+        if (testAnnotation == null) {
+            return;
+        }
+
+        final long warmupDurationNs = testAnnotation.warmupDurationNs();
+        if (warmupDurationNs >= 0) {
+            mWarmupDurationNs = warmupDurationNs;
+        }
+        final long targetTestDurationNs = testAnnotation.targetTestDurationNs();
+        if (targetTestDurationNs >= 0) {
+            mTargetTestDurationNs = targetTestDurationNs;
+        }
+    }
+
     private void beginBenchmark(long warmupDuration, int iterations) {
-        mMaxIterations = (int) (TARGET_TEST_DURATION_NS / (warmupDuration / iterations));
+        mMaxIterations = (int) (mTargetTestDurationNs / (warmupDuration / iterations));
         mMaxIterations = Math.min(MAX_TEST_ITERATIONS,
                 Math.max(mMaxIterations, MIN_TEST_ITERATIONS));
         mState = RUNNING;
@@ -108,7 +133,7 @@
                 final long timeSinceStartingWarmup = System.nanoTime() - mWarmupStartTime;
                 ++mWarmupIterations;
                 if (mWarmupIterations >= WARMUP_MIN_ITERATIONS
-                        && timeSinceStartingWarmup >= WARMUP_DURATION_NS) {
+                        && timeSinceStartingWarmup >= mWarmupDurationNs) {
                     beginBenchmark(timeSinceStartingWarmup, mWarmupIterations);
                 }
                 return true;
@@ -129,31 +154,69 @@
         }
     }
 
-    private String summaryLine() {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("Summary: ");
-        sb.append("median=").append(mStats.getMedian()).append("ns, ");
-        sb.append("mean=").append(mStats.getMean()).append("ns, ");
-        sb.append("min=").append(mStats.getMin()).append("ns, ");
-        sb.append("max=").append(mStats.getMax()).append("ns, ");
-        sb.append("sigma=").append(mStats.getStandardDeviation()).append(", ");
-        sb.append("iteration=").append(mResults.size()).append(", ");
-        sb.append("values=").append(mResults.toString());
+    /**
+     * Adds additional result while this benchmark is running. It is used when a sequence of
+     * operations is executed consecutively, the duration of each operation can also be recorded.
+     */
+    public void addExtraResult(String key, long duration) {
+        if (mState != RUNNING) {
+            return;
+        }
+        if (mExtraResults == null) {
+            mExtraResults = new ArrayMap<>();
+        }
+        mExtraResults.computeIfAbsent(key, k -> new ArrayList<>()).add(duration);
+    }
+
+    private static String summaryLine(String key, Stats stats, ArrayList<Long> results) {
+        final StringBuilder sb = new StringBuilder(key);
+        sb.append(" Summary: ");
+        sb.append("median=").append(stats.getMedian()).append("ns, ");
+        sb.append("mean=").append(stats.getMean()).append("ns, ");
+        sb.append("min=").append(stats.getMin()).append("ns, ");
+        sb.append("max=").append(stats.getMax()).append("ns, ");
+        sb.append("sigma=").append(stats.getStandardDeviation()).append(", ");
+        sb.append("iteration=").append(results.size()).append(", ");
+        sb.append("values=");
+        if (results.size() > 100) {
+            sb.append(results.subList(0, 100)).append(" ...");
+        } else {
+            sb.append(results);
+        }
         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());
+    }
+
     public void sendFullStatusReport(Instrumentation instrumentation, String key) {
         if (mState != FINISHED) {
             throw new IllegalStateException("The benchmark hasn't finished");
         }
-        Log.i(TAG, key + summaryLine());
+        Log.i(TAG, summaryLine(key, mStats, mResults));
         final Bundle status = new Bundle();
-        status.putLong(key + "_median", mStats.getMedian());
-        status.putLong(key + "_mean", (long) mStats.getMean());
-        status.putLong(key + "_percentile90", mStats.getPercentile90());
-        status.putLong(key + "_percentile95", mStats.getPercentile95());
-        status.putLong(key + "_stddev", (long) mStats.getStandardDeviation());
+        fillStatus(status, key, mStats);
+        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));
+                fillStatus(status, subKey, stats);
+            }
+        }
         instrumentation.sendStatus(Activity.RESULT_OK, status);
     }
-}
 
+    /** The annotation to customize the test, e.g. the duration of warm-up and target test. */
+    @Target(ElementType.METHOD)
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface ManualBenchmarkTest {
+        long warmupDurationNs() default -1;
+        long targetTestDurationNs() default -1;
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
index 8187c6f..8ff6a16 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
@@ -16,7 +16,7 @@
 
 package android.perftests.utils;
 
-import androidx.test.InstrumentationRegistry;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
@@ -59,15 +59,15 @@
 
     @Override
     public Statement apply(Statement base, Description description) {
+        mState.configure(description.getAnnotation(ManualBenchmarkState.ManualBenchmarkTest.class));
+
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
                 base.evaluate();
 
-                mState.sendFullStatusReport(InstrumentationRegistry.getInstrumentation(),
-                        description.getMethodName());
+                mState.sendFullStatusReport(getInstrumentation(), description.getMethodName());
             }
         };
     }
 }
-
diff --git a/api/current.txt b/api/current.txt
index 1ed8789..5d23b8f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2975,6 +2975,7 @@
   }
 
   public final class GestureDescription {
+    method public int getDisplayId();
     method public static long getMaxGestureDuration();
     method public static int getMaxStrokeCount();
     method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(@IntRange(from=0) int);
@@ -2985,6 +2986,7 @@
     ctor public GestureDescription.Builder();
     method public android.accessibilityservice.GestureDescription.Builder addStroke(@NonNull android.accessibilityservice.GestureDescription.StrokeDescription);
     method public android.accessibilityservice.GestureDescription build();
+    method @NonNull public android.accessibilityservice.GestureDescription.Builder setDisplayId(int);
   }
 
   public static class GestureDescription.StrokeDescription {
@@ -5851,12 +5853,19 @@
     method public boolean updateAutomaticZenRule(String, android.app.AutomaticZenRule);
     field public static final String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
     field public static final String ACTION_AUTOMATIC_ZEN_RULE = "android.app.action.AUTOMATIC_ZEN_RULE";
+    field public static final String ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED = "android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED";
     field public static final String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
     field public static final String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
     field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
+    field public static final int AUTOMATIC_RULE_STATUS_DISABLED = 2; // 0x2
+    field public static final int AUTOMATIC_RULE_STATUS_ENABLED = 1; // 0x1
+    field public static final int AUTOMATIC_RULE_STATUS_REMOVED = 3; // 0x3
+    field public static final int AUTOMATIC_RULE_STATUS_UNKNOWN = -1; // 0xffffffff
     field public static final String EXTRA_AUTOMATIC_RULE_ID = "android.app.extra.AUTOMATIC_RULE_ID";
+    field public static final String EXTRA_AUTOMATIC_ZEN_RULE_ID = "android.app.extra.AUTOMATIC_ZEN_RULE_ID";
+    field public static final String EXTRA_AUTOMATIC_ZEN_RULE_STATUS = "android.app.extra.AUTOMATIC_ZEN_RULE_STATUS";
     field public static final String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
     field public static final String EXTRA_NOTIFICATION_CHANNEL_GROUP_ID = "android.app.extra.NOTIFICATION_CHANNEL_GROUP_ID";
     field public static final String EXTRA_NOTIFICATION_CHANNEL_ID = "android.app.extra.NOTIFICATION_CHANNEL_ID";
@@ -10836,7 +10845,9 @@
     method @Nullable public String getString(String, @Nullable String);
     method @Nullable public java.util.Set<java.lang.String> getStringSet(String, @Nullable java.util.Set<java.lang.String>);
     method public void registerOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
+    method public default void registerOnSharedPreferencesClearListener(@NonNull android.content.SharedPreferences.OnSharedPreferencesClearListener);
     method public void unregisterOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
+    method public default void unregisterOnSharedPreferencesClearListener(@NonNull android.content.SharedPreferences.OnSharedPreferencesClearListener);
   }
 
   public static interface SharedPreferences.Editor {
@@ -10856,6 +10867,10 @@
     method public void onSharedPreferenceChanged(android.content.SharedPreferences, String);
   }
 
+  public static interface SharedPreferences.OnSharedPreferencesClearListener {
+    method public void onSharedPreferencesClear(@NonNull android.content.SharedPreferences, @NonNull java.util.Set<java.lang.String>);
+  }
+
   public class SyncAdapterType implements android.os.Parcelable {
     ctor public SyncAdapterType(String, String, boolean, boolean);
     ctor public SyncAdapterType(android.os.Parcel);
@@ -11753,6 +11768,9 @@
     field public static final String FEATURE_SENSOR_RELATIVE_HUMIDITY = "android.hardware.sensor.relative_humidity";
     field public static final String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
     field public static final String FEATURE_SENSOR_STEP_DETECTOR = "android.hardware.sensor.stepdetector";
+    field public static final String FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+    field public static final String FEATURE_SE_OMAPI_SD = "android.hardware.se.omapi.sd";
+    field public static final String FEATURE_SE_OMAPI_UICC = "android.hardware.se.omapi.uicc";
     field public static final String FEATURE_SIP = "android.software.sip";
     field public static final String FEATURE_SIP_VOIP = "android.software.sip.voip";
     field public static final String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
@@ -13125,8 +13143,11 @@
     method @Nullable public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
     method @Nullable public java.util.Map<java.lang.String,java.lang.String> getProjectionMap();
     method @Nullable public String getTables();
+    method public long insert(@NonNull android.database.sqlite.SQLiteDatabase, @NonNull android.content.ContentValues);
     method public boolean isDistinct();
     method public boolean isStrict();
+    method public boolean isStrictColumns();
+    method public boolean isStrictGrammar();
     method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String);
     method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String, String);
     method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String, String, android.os.CancellationSignal);
@@ -13134,6 +13155,8 @@
     method public void setDistinct(boolean);
     method public void setProjectionMap(@Nullable java.util.Map<java.lang.String,java.lang.String>);
     method public void setStrict(boolean);
+    method public void setStrictColumns(boolean);
+    method public void setStrictGrammar(boolean);
     method public void setTables(@Nullable String);
     method public int update(@NonNull android.database.sqlite.SQLiteDatabase, @NonNull android.content.ContentValues, @Nullable String, @Nullable String[]);
   }
@@ -41055,6 +41078,7 @@
     method public int getType();
     field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
     field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4
+    field public static final int TYPE_DATASETS_SHOWN = 5; // 0x5
     field public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; // 0x1
     field public static final int TYPE_DATASET_SELECTED = 0; // 0x0
     field public static final int TYPE_SAVE_SHOWN = 3; // 0x3
@@ -43981,6 +44005,7 @@
 
   public class CarrierConfigManager {
     method @Nullable public android.os.PersistableBundle getConfig();
+    method @Nullable public android.os.PersistableBundle getConfigByComponentForSubId(String, int);
     method @Nullable public android.os.PersistableBundle getConfigForSubId(int);
     method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
     method public void notifyConfigChangedForSubId(int);
@@ -44158,6 +44183,10 @@
     field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
 
+  public static final class CarrierConfigManager.Ims {
+    field public static final String KEY_PREFIX = "ims.";
+  }
+
   public abstract class CellIdentity implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public CharSequence getOperatorAlphaLong();
@@ -52437,6 +52466,7 @@
     method public int getId();
     method public int getLayer();
     method public android.view.accessibility.AccessibilityWindowInfo getParent();
+    method public void getRegionInScreen(@NonNull android.graphics.Region);
     method public android.view.accessibility.AccessibilityNodeInfo getRoot();
     method @Nullable public CharSequence getTitle();
     method public int getType();
diff --git a/api/removed.txt b/api/removed.txt
index 7b1d241..b075f9e 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -73,10 +73,6 @@
 
 package android.content {
 
-  public class ClipData implements android.os.Parcelable {
-    method @Deprecated public void addItem(android.content.ClipData.Item, android.content.ContentResolver);
-  }
-
   public abstract class Context {
     method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
     method public abstract java.io.File getSharedPreferencesPath(String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 6fcf055..eef6b3f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5179,7 +5179,8 @@
     method @NonNull public static java.io.File getOdmDirectory();
     method @NonNull public static java.io.File getOemDirectory();
     method @NonNull public static java.io.File getProductDirectory();
-    method @NonNull public static java.io.File getProductServicesDirectory();
+    method @Deprecated @NonNull public static java.io.File getProductServicesDirectory();
+    method @NonNull public static java.io.File getSystemExtDirectory();
     method @NonNull public static java.io.File getVendorDirectory();
   }
 
@@ -5483,6 +5484,7 @@
   public class UpdateEngine {
     ctor public UpdateEngine();
     method public void applyPayload(String, long, long, String[]);
+    method public void applyPayload(java.io.FileDescriptor, long, long, String[]);
     method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler);
     method public boolean bind(android.os.UpdateEngineCallback);
     method public void cancel();
diff --git a/api/test-current.txt b/api/test-current.txt
index 50d1f53..8e6ff30 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -62,6 +62,7 @@
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
     method public long getTotalRam();
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
+    method public static boolean isHighEndGfx();
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
     method public static void resumeAppSwitches() throws android.os.RemoteException;
     method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
@@ -704,6 +705,7 @@
     method public void setEnableRollback(boolean);
     method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
+    method public void setRequestDowngrade(boolean);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
   }
 
@@ -3034,6 +3036,7 @@
     field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
     field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
+    field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
   }
 
   public class TimeUtils {
@@ -3500,11 +3503,6 @@
     method public boolean isInputMethodPickerShown();
   }
 
-  public class InputMethodSystemProperty {
-    ctor public InputMethodSystemProperty();
-    field public static final boolean MULTI_CLIENT_IME_ENABLED;
-  }
-
 }
 
 package android.view.inspector {
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 680ccfc..76b905d 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -64,6 +64,10 @@
 
     private static final String BMGR_NOT_RUNNING_ERR =
             "Error: Could not access the Backup Manager.  Is the system running?";
+    private static final String BMGR_NOT_ACTIVATED_FOR_USER =
+            "Error: Backup Manager is not activated for user ";
+    private static final String BMGR_ERR_NO_RESTORESESSION_FOR_USER =
+            "Error: Could not get restore session for user ";
     private static final String TRANSPORT_NOT_RUNNING_ERR =
             "Error: Could not access the backup transport.  Is the system running?";
     private static final String PM_NOT_RUNNING_ERR =
@@ -190,15 +194,19 @@
         showUsage();
     }
 
-    boolean isBackupActive(@UserIdInt int userId) {
+    private void handleRemoteException(RemoteException e) {
+        System.err.println(e.toString());
+        System.err.println(BMGR_NOT_RUNNING_ERR);
+    }
+
+    private boolean isBackupActive(@UserIdInt int userId) {
         try {
             if (!mBmgr.isBackupServiceActive(userId)) {
-                System.err.println(BMGR_NOT_RUNNING_ERR);
+                System.err.println(BMGR_NOT_ACTIVATED_FOR_USER + userId);
                 return false;
             }
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
             return false;
         }
 
@@ -214,8 +222,7 @@
             System.out.println("Backup Manager currently "
                     + activatedToString(mBmgr.isBackupServiceActive(userId)));
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
 
     }
@@ -230,8 +237,7 @@
             System.out.println("Backup Manager currently "
                     + enableToString(isEnabled));
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -250,8 +256,7 @@
             showUsage();
             return;
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -259,8 +264,7 @@
         try {
             mBmgr.backupNowForUser(userId);
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -274,8 +278,7 @@
         try {
             mBmgr.dataChangedForUser(userId, pkg);
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -292,8 +295,7 @@
                 mBmgr.fullTransportBackupForUser(
                         userId, allPkgs.toArray(new String[allPkgs.size()]));
             } catch (RemoteException e) {
-                System.err.println(e.toString());
-                System.err.println(BMGR_NOT_RUNNING_ERR);
+                handleRemoteException(e);
             }
         }
     }
@@ -421,8 +423,7 @@
             try {
                 filteredPackages = mBmgr.filterAppsEligibleForBackupForUser(userId, packages);
             } catch (RemoteException e) {
-                System.err.println(e.toString());
-                System.err.println(BMGR_NOT_RUNNING_ERR);
+                handleRemoteException(e);
             }
             backupNowPackages(userId, Arrays.asList(filteredPackages), nonIncrementalBackup,
                     monitorState);
@@ -455,8 +456,7 @@
                 System.err.println("Unable to run backup");
             }
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -506,8 +506,7 @@
             try {
                 mBmgr.cancelBackupsForUser(userId);
             } catch (RemoteException e) {
-                System.err.println(e.toString());
-                System.err.println(BMGR_NOT_RUNNING_ERR);
+                handleRemoteException(e);
             }
             return;
         }
@@ -537,8 +536,7 @@
             }
 
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -569,8 +567,7 @@
                         }
                     });
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
             return;
         }
 
@@ -598,8 +595,7 @@
             mBmgr.clearBackupDataForUser(userId, transport, pkg);
             System.out.println("Wiped backup data for " + pkg + " on " + transport);
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -632,8 +628,7 @@
             observer.waitForCompletion(30*1000L);
             System.out.println("Initialization result: " + observer.result);
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -648,7 +643,7 @@
         try {
             mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
             if (mRestore == null) {
-                System.err.println(BMGR_NOT_RUNNING_ERR);
+                System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
                 return;
             }
 
@@ -658,8 +653,7 @@
 
             mRestore.endRestoreSession();
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -686,8 +680,7 @@
                 System.out.println(pad + t);
             }
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -805,7 +798,7 @@
             boolean didRestore = false;
             mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null);
             if (mRestore == null) {
-                System.err.println(BMGR_NOT_RUNNING_ERR);
+                System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId);
                 return;
             }
             RestoreSet[] sets = null;
@@ -851,8 +844,7 @@
 
             System.out.println("done");
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -865,8 +857,7 @@
                 }
             }
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
@@ -886,8 +877,7 @@
                             + " for user "
                             + userId);
         } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(BMGR_NOT_RUNNING_ERR);
+            handleRemoteException(e);
         }
     }
 
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index 31bd612..c1f8654 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -79,7 +79,6 @@
         "libEGL",
         "libGLESv1_CM",
         "libgui",
-        "libtinyalsa",
     ],
 
     product_variables: {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 30f4ad4..db384ba 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -63,6 +63,10 @@
 
 #include "BootAnimation.h"
 
+#define ANIM_PATH_MAX 255
+#define STR(x)   #x
+#define STRTO(x) STR(x)
+
 namespace android {
 
 static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
@@ -96,7 +100,7 @@
 static const int TEXT_CENTER_VALUE = INT_MAX;
 static const int TEXT_MISSING_VALUE = INT_MIN;
 static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
-static const int ANIM_ENTRY_NAME_MAX = 256;
+static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
 static constexpr size_t TEXT_POS_LEN_MAX = 16;
 
 // ---------------------------------------------------------------------------
@@ -694,7 +698,7 @@
             animation.width = width;
             animation.height = height;
             animation.fps = fps;
-        } else if (sscanf(l, " %c %d %d %s #%6s %16s %16s",
+        } else if (sscanf(l, " %c %d %d %" STRTO(ANIM_PATH_MAX) "s #%6s %16s %16s",
                           &pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) {
             //SLOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s",
             //    pathType, count, pause, path, color, clockPos1, clockPos2);
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index cfac5f3..0b349e1 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -103,6 +103,7 @@
       {"/oem/", kPolicyOem},
       {"/product/", kPolicyProduct},
       {"/system/", kPolicySystem},
+      {"/system_ext/", kPolicySystem},
       {"/vendor/", kPolicyVendor},
   };
 
diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING
new file mode 100644
index 0000000..c1cba5f
--- /dev/null
+++ b/cmds/locksettings/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+    "presubmit": [
+        {
+            "name": "CtsDevicePolicyManagerTestCases",
+            "options": [
+                {
+                    "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
+                },
+                {
+                    "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                }
+            ]
+        }
+    ]
+}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 2f0dc3c..6df0a8e 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -71,7 +71,6 @@
         "src/config/ConfigManager.cpp",
         "src/external/GpuStatsPuller.cpp",
         "src/external/Perfetto.cpp",
-        "src/external/Perfprofd.cpp",
         "src/external/StatsPuller.cpp",
         "src/external/StatsCallbackPuller.cpp",
         "src/external/StatsCompanionServicePuller.cpp",
@@ -109,8 +108,6 @@
         "src/socket/StatsSocketListener.cpp",
         "src/shell/ShellSubscriber.cpp",
         "src/shell/shell_config.proto",
-
-        ":perfprofd_aidl",
     ],
 
     local_include_dirs: [
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
index 548a686..e09d575 100644
--- a/cmds/statsd/src/anomaly/subscriber_util.cpp
+++ b/cmds/statsd/src/anomaly/subscriber_util.cpp
@@ -22,7 +22,6 @@
 #include <binder/IServiceManager.h>
 
 #include "external/Perfetto.h"
-#include "external/Perfprofd.h"
 #include "subscriber/IncidentdReporter.h"
 #include "subscriber/SubscriberReporter.h"
 
@@ -64,12 +63,6 @@
                 SubscriberReporter::getInstance().alertBroadcastSubscriber(configKey, subscription,
                                                                            dimensionKey);
                 break;
-            case Subscription::SubscriberInformationCase::kPerfprofdDetails:
-                if (!CollectPerfprofdTraceAndUploadToDropbox(subscription.perfprofd_details(),
-                                                             ruleId, configKey)) {
-                    ALOGW("Failed to generate perfprofd traces.");
-                }
-                break;
             default:
                 break;
         }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index ceabd39..f6c72ea 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5309,6 +5309,9 @@
     // Additional pass-through fields opaque to statsd.
     // The DNS resolver Mainline module can add new fields here without requiring an OS update.
     optional android.stats.dnsresolver.DnsQueryEvents dns_query_events = 8 [(log_mode) = MODE_BYTES];
+
+    // The sample rate of DNS stats (to statsd) is 1/sampling_rate_denom.
+    optional int32 sampling_rate_denom = 9;
 }
 
 /**
diff --git a/cmds/statsd/src/external/Perfprofd.cpp b/cmds/statsd/src/external/Perfprofd.cpp
deleted file mode 100644
index 1678f10..0000000
--- a/cmds/statsd/src/external/Perfprofd.cpp
+++ /dev/null
@@ -1,74 +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 "Perfprofd.h"
-
-#define DEBUG false  // STOPSHIP if true
-#include "config/ConfigKey.h"
-#include "Log.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <binder/IServiceManager.h>
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // Alert
-
-#include "android/os/IPerfProfd.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-bool CollectPerfprofdTraceAndUploadToDropbox(const PerfprofdDetails& config,
-                                             int64_t alert_id,
-                                             const ConfigKey& configKey) {
-    VLOG("Starting trace collection through perfprofd");
-
-    if (!config.has_perfprofd_config()) {
-      ALOGE("The perfprofd trace config is empty, aborting");
-      return false;
-    }
-
-    sp<IPerfProfd> service = interface_cast<IPerfProfd>(
-        defaultServiceManager()->getService(android::String16("perfprofd")));
-    if (service == NULL) {
-      ALOGE("Could not find perfprofd service");
-      return false;
-    }
-
-    auto* data = reinterpret_cast<const uint8_t*>(config.perfprofd_config().data());
-    std::vector<uint8_t> proto_serialized(data, data + config.perfprofd_config().size());
-
-    // TODO: alert-id etc?
-
-    binder::Status status = service->startProfilingProtobuf(proto_serialized);
-    if (status.isOk()) {
-      return true;
-    }
-
-    ALOGE("Error starting perfprofd profiling: %s", status.toString8().c_str());
-    return false;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/Perfprofd.h b/cmds/statsd/src/external/Perfprofd.h
deleted file mode 100644
index b93fdf8..0000000
--- a/cmds/statsd/src/external/Perfprofd.h
+++ /dev/null
@@ -1,38 +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.
- */
-
-#pragma once
-
-#include <inttypes.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class ConfigKey;
-class PerfprofdDetails;  // Declared in statsd_config.pb.h
-
-// Starts the collection of a Perfprofd trace with the given |config|.
-// The trace is uploaded to Dropbox by the perfprofd service once done.
-// This method returns immediately after passing the config and does NOT wait
-// for the full duration of the trace.
-bool CollectPerfprofdTraceAndUploadToDropbox(const PerfprofdDetails& config,
-                                             int64_t alert_id,
-                                             const ConfigKey& configKey);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index a2fd9d4..79c06b9 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -343,15 +343,6 @@
   optional bytes trace_config = 1;
 }
 
-message PerfprofdDetails {
-  // The |perfprofd_config| field is a proto-encoded message of type
-  // android.perfprofd.ProfilingConfig defined in
-  // //system/extras/perfprofd/. On device, statsd doesn't need to
-  // deserialize the message as it's just passed binary-encoded to
-  // the perfprofd service.
-  optional bytes perfprofd_config = 1;
-}
-
 message BroadcastSubscriberDetails {
   optional int64 subscriber_id = 1;
   repeated string cookie = 2;
@@ -373,10 +364,12 @@
     IncidentdDetails incidentd_details = 4;
     PerfettoDetails perfetto_details = 5;
     BroadcastSubscriberDetails broadcast_subscriber_details = 6;
-    PerfprofdDetails perfprofd_details = 8;
   }
 
   optional float probability_of_informing = 7 [default = 1.1];
+
+  // This was used for perfprofd historically.
+  reserved 8;
 }
 
 enum ActivationType {
diff --git a/cmds/statsd/tools/dogfood/AndroidManifest.xml b/cmds/statsd/tools/dogfood/AndroidManifest.xml
deleted file mode 100644
index 52673fb..0000000
--- a/cmds/statsd/tools/dogfood/AndroidManifest.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.statsd.dogfood"
-    android:sharedUserId="android.uid.system"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-    <uses-permission android:name="android.permission.DUMP" />
-
-    <application
-        android:allowBackup="true"
-        android:icon="@drawable/ic_launcher"
-        android:label="@string/app_name" >
-        <activity
-            android:name=".MainActivity"
-            android:label="@string/app_name"
-            android:launchMode="singleTop" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-
-        <service android:name=".MainActivity$ReceiverIntentService" android:exported="true" />
-    </application>
-</manifest>
diff --git a/cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 55621cc..0000000
--- a/cmds/statsd/tools/dogfood/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 11ec206..0000000
--- a/cmds/statsd/tools/dogfood/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 7c02b78..0000000
--- a/cmds/statsd/tools/dogfood/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.png b/cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 915d914..0000000
--- a/cmds/statsd/tools/dogfood/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/layout/activity_main.xml b/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
deleted file mode 100644
index 784ed40..0000000
--- a/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
+++ /dev/null
@@ -1,162 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
-
-        <Button
-            android:id="@+id/push_config"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:background="@android:color/holo_green_light"
-            android:text="@string/push_config"/>
-        <Button
-                android:id="@+id/set_receiver"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:background="@android:color/holo_green_light"
-                android:text="@string/set_receiver"/>
-        <Button
-                android:id="@+id/remove_receiver"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:background="@android:color/holo_green_light"
-                android:text="@string/remove_receiver"/>
-
-        <LinearLayout android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-            <Button android:id="@+id/app_a_wake_lock_acquire1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/app_a_get_wl1"/>
-            <Button android:id="@+id/app_a_wake_lock_release1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/app_a_release_wl1"/>
-        </LinearLayout>
-
-        <LinearLayout android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-            <Button android:id="@+id/app_a_wake_lock_acquire2"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/app_a_get_wl2"/>
-            <Button android:id="@+id/app_a_wake_lock_release2"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/app_a_release_wl2"/>
-        </LinearLayout>
-
-        <LinearLayout android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-            <Button android:id="@+id/app_b_wake_lock_acquire1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/app_b_get_wl1"/>
-            <Button android:id="@+id/app_b_wake_lock_release1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/app_b_release_wl1"/>
-        </LinearLayout>
-        <LinearLayout android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-            <Button android:id="@+id/app_b_wake_lock_acquire2"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/app_b_get_wl2"/>
-            <Button android:id="@+id/app_b_wake_lock_release2"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/app_b_release_wl2"/>
-        </LinearLayout>
-
-    <LinearLayout android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <Button android:id="@+id/plug"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/plug"/>
-
-        <Button android:id="@+id/unplug"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/unplug"/>
-    </LinearLayout>
-
-        <LinearLayout android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-            <Button android:id="@+id/screen_on"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/screen_on"/>
-
-            <Button android:id="@+id/screen_off"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/screen_off"/>
-        </LinearLayout>
-
-        <LinearLayout android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-
-            <Button
-                android:id="@+id/custom_start"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/custom_start" />
-
-            <Button
-                android:id="@+id/custom_stop"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/custom_stop" />
-        </LinearLayout>
-
-        <Button android:id="@+id/dump"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:background="@android:color/holo_purple"
-            android:text="@string/dump"/>
-
-        <TextView
-            android:id="@+id/header"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/report_header"/>
-
-        <TextView
-            android:id="@+id/report_text"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-
-    </LinearLayout>
-
-</ScrollView>
\ No newline at end of file
diff --git a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config b/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
deleted file mode 100644
index d050061..0000000
--- a/cmds/statsd/tools/dogfood/res/raw/statsd_baseline_config
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/dogfood/res/values/strings.xml b/cmds/statsd/tools/dogfood/res/values/strings.xml
deleted file mode 100644
index 60948a1..0000000
--- a/cmds/statsd/tools/dogfood/res/values/strings.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources>
-
-    <string name="app_name">Statsd Dogfood</string>
-
-    <string name="statsd_running">Statsd Running</string>
-    <string name="statsd_not_running">Statsd NOT Running</string>
-
-    <string name="push_config">Push baseline config</string>
-    <string name="set_receiver">Set pendingintent</string>
-    <string name="remove_receiver">Remove pendingintent</string>
-
-    <string name="app_a_foreground">App A foreground</string>
-    <string name="app_b_foreground">App B foreground</string>
-
-
-    <string name="app_a_get_wl1">App A get wl_1</string>
-    <string name="app_a_release_wl1">App A release wl_1</string>
-
-    <string name="app_a_get_wl2">App A get wl_2</string>
-    <string name="app_a_release_wl2">App A release wl_2</string>
-
-    <string name="app_b_get_wl1">App B get wl_1</string>
-    <string name="app_b_release_wl1">App B release wl_1</string>
-
-    <string name="app_b_get_wl2">App B get wl_2</string>
-    <string name="app_b_release_wl2">App B release wl_2</string>
-
-    <string name="plug">Plug</string>
-    <string name="unplug">Unplug</string>
-
-    <string name="screen_on">Screen On</string>
-    <string name="screen_off">Screen Off</string>
-
-    <string name="custom_start">App hook start</string>
-    <string name="custom_stop">App hook stop</string>
-
-    <string name="dump">DumpReport</string>
-    <string name="report_header">Report details</string>
-</resources>
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
deleted file mode 100644
index b6b16e4..0000000
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.dogfood;
-
-import android.text.format.DateFormat;
-
-import com.android.os.StatsLog;
-
-import java.util.List;
-
-public class DisplayProtoUtils {
-    public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
-        sb.append("ConfigKey: ");
-        if (reports.hasConfigKey()) {
-            com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
-            sb.append("\tuid: ").append(key.getUid()).append(" name: ").append(key.getId())
-                    .append("\n");
-        }
-
-        for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
-            sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
-            sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
-                    append("\n");
-            sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
-                    append("\n");
-            for (StatsLog.StatsLogReport log : report.getMetricsList()) {
-                sb.append("\n\n");
-                sb.append("metric id: ").append(log.getMetricId()).append("\n");
-
-                switch (log.getDataCase()) {
-                    case DURATION_METRICS:
-                        sb.append("Duration metric data\n");
-                        displayDurationMetricData(sb, log);
-                        break;
-                    case EVENT_METRICS:
-                        sb.append("Event metric data\n");
-                        displayEventMetricData(sb, log);
-                        break;
-                    case COUNT_METRICS:
-                        sb.append("Count metric data\n");
-                        displayCountMetricData(sb, log);
-                        break;
-                    case GAUGE_METRICS:
-                        sb.append("Gauge metric data\n");
-                        displayGaugeMetricData(sb, log);
-                        break;
-                    case VALUE_METRICS:
-                        sb.append("Value metric data\n");
-                        displayValueMetricData(sb, log);
-                        break;
-                    case DATA_NOT_SET:
-                        sb.append("No metric data\n");
-                        break;
-                }
-            }
-        }
-    }
-
-    public static String getDateStr(long nanoSec) {
-        return DateFormat.format("dd/MM hh:mm:ss", nanoSec/1000000).toString();
-    }
-
-    private static void displayDimension(StringBuilder sb, StatsLog.DimensionsValue dimensionValue) {
-        sb.append(dimensionValue.getField()).append(":");
-        if (dimensionValue.hasValueBool()) {
-            sb.append(dimensionValue.getValueBool());
-        } else if (dimensionValue.hasValueFloat()) {
-            sb.append(dimensionValue.getValueFloat());
-        } else if (dimensionValue.hasValueInt()) {
-            sb.append(dimensionValue.getValueInt());
-        } else if (dimensionValue.hasValueStr()) {
-            sb.append(dimensionValue.getValueStr());
-        } else if (dimensionValue.hasValueTuple()) {
-            sb.append("{");
-            for (StatsLog.DimensionsValue child :
-                    dimensionValue.getValueTuple().getDimensionsValueList()) {
-                displayDimension(sb, child);
-            }
-            sb.append("}");
-        }
-        sb.append(" ");
-    }
-
-    public static void displayDurationMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        StatsLog.StatsLogReport.DurationMetricDataWrapper durationMetricDataWrapper
-                = log.getDurationMetrics();
-        sb.append("Dimension size: ").append(durationMetricDataWrapper.getDataCount()).append("\n");
-        for (StatsLog.DurationMetricData duration : durationMetricDataWrapper.getDataList()) {
-            sb.append("dimension_in_what: ");
-            displayDimension(sb, duration.getDimensionsInWhat());
-            sb.append("\n");
-            if (duration.hasDimensionsInCondition()) {
-                sb.append("dimension_in_condition: ");
-                displayDimension(sb, duration.getDimensionsInCondition());
-                sb.append("\n");
-            }
-
-            for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList())  {
-                sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
-                        .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
-                        .append(info.getDurationNanos()).append(" ns\n");
-            }
-        }
-    }
-
-    public static void displayEventMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        sb.append("Contains ").append(log.getEventMetrics().getDataCount()).append(" events\n");
-        StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
-                log.getEventMetrics();
-        for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
-            sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
-            sb.append(event.getAtom().getPushedCase().toString()).append("\n");
-        }
-    }
-
-    public static void displayCountMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        StatsLog.StatsLogReport.CountMetricDataWrapper countMetricDataWrapper
-                = log.getCountMetrics();
-        sb.append("Dimension size: ").append(countMetricDataWrapper.getDataCount()).append("\n");
-        for (StatsLog.CountMetricData count : countMetricDataWrapper.getDataList()) {
-            sb.append("dimension_in_what: ");
-            displayDimension(sb, count.getDimensionsInWhat());
-            sb.append("\n");
-            if (count.hasDimensionsInCondition()) {
-                sb.append("dimension_in_condition: ");
-                displayDimension(sb, count.getDimensionsInCondition());
-                sb.append("\n");
-            }
-
-            for (StatsLog.CountBucketInfo info : count.getBucketInfoList())  {
-                sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
-                        .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
-                        .append(info.getCount()).append("\n");
-            }
-        }
-    }
-
-    public static void displayGaugeMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        sb.append("Display me!");
-    }
-
-    public static void displayValueMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        sb.append("Display me!");
-    }
-}
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
deleted file mode 100644
index 4f4dd01..0000000
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.dogfood;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.app.IntentService;
-import android.app.StatsManager;
-import android.app.StatsManager.StatsUnavailableException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.StatsLog;
-import android.view.View;
-import android.widget.TextView;
-import android.widget.Toast;
-import android.os.IStatsManager;
-import android.os.ServiceManager;
-
-import java.io.InputStream;
-
-import static com.android.statsd.dogfood.DisplayProtoUtils.displayLogReport;
-
-public class MainActivity extends Activity {
-    private final static String TAG = "StatsdDogfood";
-    private final static long CONFIG_ID = 987654321;
-
-    final int[] mUids = {11111111, 2222222};
-    StatsManager mStatsManager;
-    TextView mReportText;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.activity_main);
-
-        findViewById(R.id.app_a_wake_lock_acquire1).setOnClickListener(
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        onWakeLockAcquire(0, "wl_1");
-                    }
-                });
-
-        findViewById(R.id.app_b_wake_lock_acquire1).setOnClickListener(
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        onWakeLockAcquire(1, "wl_1");
-                    }
-                });
-
-        findViewById(R.id.app_a_wake_lock_acquire2).setOnClickListener(
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        onWakeLockAcquire(0, "wl_2");
-                    }
-                });
-
-        findViewById(R.id.app_b_wake_lock_acquire2).setOnClickListener(
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        onWakeLockAcquire(1, "wl_2");
-                    }
-                });
-
-        findViewById(R.id.app_a_wake_lock_release1).setOnClickListener(
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        onWakeLockRelease(0, "wl_1");
-                    }
-                });
-
-
-        findViewById(R.id.app_b_wake_lock_release1).setOnClickListener(
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        onWakeLockRelease(1, "wl_1");
-                    }
-                });
-
-        findViewById(R.id.app_a_wake_lock_release2).setOnClickListener(
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        onWakeLockRelease(0, "wl_2");
-                    }
-                });
-
-
-        findViewById(R.id.app_b_wake_lock_release2).setOnClickListener(
-                new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        onWakeLockRelease(1, "wl_2");
-                    }
-                });
-
-
-        findViewById(R.id.plug).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED,
-                        StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_AC);
-            }
-        });
-
-        findViewById(R.id.unplug).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED,
-                        StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_NONE);
-            }
-        });
-
-        findViewById(R.id.screen_on).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
-                        StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON);
-            }
-        });
-
-        findViewById(R.id.screen_off).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
-                        StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF);
-            }
-        });
-
-        findViewById(R.id.custom_start).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                StatsLog.logStart(8);
-            }
-        });
-
-        findViewById(R.id.custom_stop).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                StatsLog.logStop(8);
-            }
-        });
-
-        mReportText = (TextView) findViewById(R.id.report_text);
-
-        findViewById(R.id.dump).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                if (!statsdRunning()) {
-                    return;
-                }
-                if (mStatsManager != null) {
-                    try {
-                        byte[] data = mStatsManager.getReports(CONFIG_ID);
-                        if (data != null) {
-                            displayData(data);
-                            return;
-                        }
-                    } catch (StatsUnavailableException e) {
-                        Log.e(TAG, "Failed to get data from statsd", e);
-                    }
-                    mReportText.setText("Failed!");
-                }
-            }
-        });
-
-        findViewById(R.id.push_config).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                try {
-                    if (!statsdRunning()) {
-                        return;
-                    }
-                    Resources res = getResources();
-                    InputStream inputStream = res.openRawResource(R.raw.statsd_baseline_config);
-
-                    byte[] config = new byte[inputStream.available()];
-                    inputStream.read(config);
-                    if (mStatsManager != null) {
-                        try {
-                            mStatsManager.addConfig(CONFIG_ID, config);
-                            Toast.makeText(
-                                    MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show();
-                        } catch (StatsUnavailableException | IllegalArgumentException e) {
-                            Toast.makeText(MainActivity.this, "Config push FAILED!",
-                                    Toast.LENGTH_LONG).show();
-                        }
-                    }
-                } catch (Exception e) {
-                    Toast.makeText(MainActivity.this, "failed to read config", Toast.LENGTH_LONG);
-                }
-            }
-        });
-
-        PendingIntent pi = PendingIntent.getService(this, 0,
-                new Intent(this, ReceiverIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
-        findViewById(R.id.set_receiver).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                try {
-                    if (!statsdRunning()) {
-                        return;
-                    }
-                    if (mStatsManager != null) {
-                        try {
-                            mStatsManager.setFetchReportsOperation(pi, CONFIG_ID);
-                            Toast.makeText(MainActivity.this,
-                                    "Receiver specified to pending intent", Toast.LENGTH_LONG)
-                                    .show();
-                        } catch (StatsUnavailableException e) {
-                            Toast.makeText(MainActivity.this, "Statsd did not set receiver",
-                                    Toast.LENGTH_LONG)
-                                    .show();
-                        }
-                    }
-                } catch (Exception e) {
-                    Toast.makeText(MainActivity.this, "failed to set receiver", Toast.LENGTH_LONG);
-                }
-            }
-        });
-        findViewById(R.id.remove_receiver).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                try {
-                    if (!statsdRunning()) {
-                        return;
-                    }
-                    if (mStatsManager != null) {
-                        try {
-                            mStatsManager.setFetchReportsOperation(null, CONFIG_ID);
-                            Toast.makeText(MainActivity.this, "Receiver remove", Toast.LENGTH_LONG)
-                                    .show();
-                        } catch (StatsUnavailableException e) {
-                            Toast.makeText(MainActivity.this, "Statsd did not remove receiver",
-                                    Toast.LENGTH_LONG)
-                                    .show();
-                        }
-                    }
-                } catch (Exception e) {
-                    Toast.makeText(
-                            MainActivity.this, "failed to remove receiver", Toast.LENGTH_LONG);
-                }
-            }
-        });
-        mStatsManager = (StatsManager) getSystemService("stats");
-    }
-
-    private boolean statsdRunning() {
-        if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) {
-            Log.d(TAG, "Statsd not running");
-            Toast.makeText(MainActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show();
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public void onNewIntent(Intent intent) {
-        Log.d(TAG, "new intent: " + intent.getIntExtra("pkg", 0));
-        int pkg = intent.getIntExtra("pkg", 0);
-        String name = intent.getStringExtra("name");
-        if (intent.hasExtra("acquire")) {
-            onWakeLockAcquire(pkg, name);
-        } else if (intent.hasExtra("release")) {
-            onWakeLockRelease(pkg, name);
-        }
-    }
-
-    private void displayData(byte[] data) {
-        com.android.os.StatsLog.ConfigMetricsReportList reports = null;
-        boolean good = false;
-        if (data != null) {
-            try {
-                reports = com.android.os.StatsLog.ConfigMetricsReportList.parseFrom(data);
-                good = true;
-            } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-                // display it in the text view.
-            }
-        }
-        int size = data == null ? 0 : data.length;
-        StringBuilder sb = new StringBuilder();
-        sb.append(good ? "Proto parsing OK!" : "Proto parsing Error!");
-        sb.append(" size:").append(size).append("\n");
-
-        if (good && reports != null) {
-            displayLogReport(sb, reports);
-            mReportText.setText(sb.toString());
-        }
-    }
-
-
-    private void onWakeLockAcquire(int id, String name) {
-        if (id > 1) {
-            Log.d(TAG, "invalid pkg id");
-            return;
-        }
-        int[] uids = new int[]{mUids[id]};
-        String[] tags = new String[]{"acquire"};
-        StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
-                StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
-                StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
-        StringBuilder sb = new StringBuilder();
-        sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
-                .append(", ").append(name).append(", 1);");
-        Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
-    }
-
-    private void onWakeLockRelease(int id, String name) {
-        if (id > 1) {
-            Log.d(TAG, "invalid pkg id");
-            return;
-        }
-        int[] uids = new int[]{mUids[id]};
-        String[] tags = new String[]{"release"};
-        StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
-                StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
-                StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
-        StringBuilder sb = new StringBuilder();
-        sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
-                .append(", ").append(name).append(", 0);");
-        Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
-    }
-
-    public static class ReceiverIntentService extends IntentService {
-        public ReceiverIntentService() {
-            super("ReceiverIntentService");
-        }
-
-        /**
-         * The IntentService calls this method from the default worker thread with
-         * the intent that started the service. When this method returns, IntentService
-         * stops the service, as appropriate.
-         */
-        @Override
-        protected void onHandleIntent(Intent intent) {
-            Log.i(TAG, "Received notification that we should call getData");
-        }
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/Android.bp b/cmds/statsd/tools/loadtest/Android.bp
deleted file mode 100644
index bf87fc5..0000000
--- a/cmds/statsd/tools/loadtest/Android.bp
+++ /dev/null
@@ -1,37 +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.
-//
-//
-
-android_app {
-    name: "StatsdLoadtest",
-    platform_apis: true,
-
-    srcs: ["src/**/*.java"],
-
-    resource_dirs: ["res"],
-    static_libs: [
-        "platformprotoslite",
-        "statsdprotolite",
-    ],
-
-    certificate: "platform",
-    privileged: true,
-    dex_preopt: {
-        enabled: false,
-    },
-    optimize: {
-        enabled: false,
-    },
-}
diff --git a/cmds/statsd/tools/loadtest/AndroidManifest.xml b/cmds/statsd/tools/loadtest/AndroidManifest.xml
deleted file mode 100644
index 2bf8ca9..0000000
--- a/cmds/statsd/tools/loadtest/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.statsd.loadtest"
-    android:sharedUserId="android.uid.system"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-  <uses-permission android:name="android.permission.DUMP" />
-  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-  <application
-      android:allowBackup="true"
-      android:icon="@drawable/ic_launcher"
-      android:label="@string/app_name" >
-    <activity
-        android:name=".LoadtestActivity"
-        android:label="@string/app_name"
-        android:launchMode="singleTop" >
-      <intent-filter>
-        <action android:name="android.intent.action.MAIN" />
-        <category android:name="android.intent.category.LAUNCHER" />
-      </intent-filter>
-    </activity>
-    <receiver android:name=".LoadtestActivity$PusherAlarmReceiver" />
-    <receiver android:name=".LoadtestActivity$StopperAlarmReceiver"/>
-    <receiver android:name=".PerfData$PerfAlarmReceiver"/>
-  </application>
-</manifest>
diff --git a/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 55621cc..0000000
--- a/cmds/statsd/tools/loadtest/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 11ec206..0000000
--- a/cmds/statsd/tools/loadtest/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 7c02b78..0000000
--- a/cmds/statsd/tools/loadtest/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png b/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png
deleted file mode 100644
index 915d914..0000000
--- a/cmds/statsd/tools/loadtest/res/drawable-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
deleted file mode 100644
index d6f8047..0000000
--- a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
+++ /dev/null
@@ -1,208 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
-
-    <LinearLayout
-        android:id="@+id/outside"
-        android:clickable="true"
-        android:focusable="true"
-        android:focusableInTouchMode="true"
-        android:gravity="center"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginRight="10dp"
-        android:layout_marginLeft="10dp"
-        android:orientation="vertical">
-      <requestFocus />
-
-        <LinearLayout
-            android:gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal">
-            <TextView
-                android:textSize="30dp"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/replication_label" />
-            <EditText
-                android:id="@+id/replication"
-                android:inputType="number"
-                android:layout_weight="1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:maxLength="4"
-                android:text="@integer/replication_default"
-                android:textSize="30dp"/>
-        </LinearLayout>
-
-        <LinearLayout
-            android:gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal">
-            <TextView
-                android:textSize="30dp"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/bucket_label" />
-             <Spinner
-                 android:id="@+id/bucket_spinner"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:prompt="@string/bucket_label"/>
-        </LinearLayout>
-
-        <LinearLayout
-            android:gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal">
-            <TextView
-                android:textSize="30dp"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/period_label" />
-            <EditText
-                android:id="@+id/period"
-                android:inputType="number"
-                android:layout_weight="1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:maxLength="3"
-                android:text="@integer/period_default"
-                android:textSize="30dp"/>
-        </LinearLayout>
-
-        <LinearLayout
-            android:gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal">
-            <TextView
-                android:textSize="30dp"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/burst_label" />
-            <EditText
-                android:id="@+id/burst"
-                android:inputType="number"
-                android:layout_weight="1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:maxLength="4"
-                android:text="@integer/burst_default"
-                android:textSize="30dp"/>
-        </LinearLayout>
-
-        <LinearLayout
-            android:gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal">
-            <TextView
-                android:textSize="30dp"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/duration_label" />
-            <EditText
-                android:id="@+id/duration"
-                android:inputType="number"
-                android:layout_weight="1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:maxLength="4"
-                android:text="@integer/duration_default"
-                android:textSize="30dp"/>
-        </LinearLayout>
-        <CheckBox
-            android:id="@+id/placebo"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/placebo"
-            android:checked="false" />
-
-        <LinearLayout
-            android:gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-            <CheckBox
-                android:id="@+id/include_count"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/count"
-                android:checked="true"/>
-            <CheckBox
-                android:id="@+id/include_duration"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/duration"
-                android:checked="true"/>
-            <CheckBox
-                android:id="@+id/include_event"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/event"
-                android:checked="true"/>
-            <CheckBox
-                android:id="@+id/include_value"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/value"
-                android:checked="true"/>
-            <CheckBox
-                android:id="@+id/include_gauge"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/gauge"
-                android:checked="true"/>
-        </LinearLayout>
-
-        <Space
-            android:layout_width="1dp"
-            android:layout_height="30dp"/>
-
-        <Button
-            android:id="@+id/start_stop"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:background="#ffff0000"
-            android:text="@string/start"
-            android:textSize="50dp"/>
-
-        <Space
-            android:layout_width="1dp"
-            android:layout_height="30dp"/>
-
-        <Space
-            android:layout_width="1dp"
-            android:layout_height="30dp"/>
-
-        <TextView
-            android:id="@+id/report_text"
-            android:gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-
-    </LinearLayout>
-
-</ScrollView>
diff --git a/cmds/statsd/tools/loadtest/res/layout/spinner_item.xml b/cmds/statsd/tools/loadtest/res/layout/spinner_item.xml
deleted file mode 100644
index b03da06..0000000
--- a/cmds/statsd/tools/loadtest/res/layout/spinner_item.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:textSize="30dp"
-    android:gravity="left"
-    android:padding="5dip"
-    />
diff --git a/cmds/statsd/tools/loadtest/res/raw/loadtest_config b/cmds/statsd/tools/loadtest/res/raw/loadtest_config
deleted file mode 100755
index 2422190..0000000
--- a/cmds/statsd/tools/loadtest/res/raw/loadtest_config
+++ /dev/null
Binary files differ
diff --git a/cmds/statsd/tools/loadtest/res/values/integers.xml b/cmds/statsd/tools/loadtest/res/values/integers.xml
deleted file mode 100644
index c2407d3..0000000
--- a/cmds/statsd/tools/loadtest/res/values/integers.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources>
-    <integer name="burst_default">1</integer>
-    <integer name="period_default">2</integer>
-    <integer name="replication_default">1</integer>
-    <integer name="duration_default">240</integer>
-</resources>
diff --git a/cmds/statsd/tools/loadtest/res/values/strings.xml b/cmds/statsd/tools/loadtest/res/values/strings.xml
deleted file mode 100644
index e8ae3f8..0000000
--- a/cmds/statsd/tools/loadtest/res/values/strings.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources>
-    <string name="app_name">Statsd Loadtest</string>
-    <string name="bucket_label">bucket size (mins):&#160;</string>
-    <string name="burst_label">burst:&#160;</string>
-    <string name="bucket_default">FIVE_MINUTES</string>
-    <string name="placebo">placebo</string>
-    <string name="period_label">logging period (secs):&#160;</string>
-    <string name="replication_label">metric replication:&#160;</string>
-    <string name="duration_label">test duration (mins):&#160;</string>
-    <string name="start"> &#160;Start&#160; </string>
-    <string name="stop"> &#160;Stop&#160; </string>
-    <string name="count"> count </string>
-    <string name="duration"> duration </string>
-    <string name="event"> event </string>
-    <string name="value"> value </string>
-    <string name="gauge"> gauge </string>
-
-</resources>
diff --git a/cmds/statsd/tools/loadtest/run_loadtest.sh b/cmds/statsd/tools/loadtest/run_loadtest.sh
deleted file mode 100755
index 3c93a06..0000000
--- a/cmds/statsd/tools/loadtest/run_loadtest.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/sh
-#
-# Script that measures statsd's PSS under an increasing number of metrics.
-
-# Globals.
-pss=""
-pid=""
-
-# Starts the loadtest.
-start_loadtest() {
-    echo "Starting loadtest"
-    adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "start"
-}
-
-# Stops the loadtest.
-stop_loadtest() {
-    echo "Stopping loadtest"
-    adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "stop"
-}
-
-# Sets the metrics replication.
-# Arguments:
-#   $1: The replication factor.
-set_replication() {
-    adb shell am start -n com.android.statsd.loadtest/.LoadtestActivity --es "type" "set_replication" --ei "replication" "${1}"
-    echo "Replication set to ${1}"
-}
-
-# Reads statsd's pid and PSS.
-update_pid_and_pss() {
-    # Command that reads the PSS for statsd. This also gives us its pid.
-    get_mem=$(adb shell dumpsys meminfo |grep statsd)
-    # Looks for statsd's pid.
-    regex="([0-9,]+)K: statsd \(pid ([0-9]+)\).*"
-    if [[ $get_mem =~ $regex ]]; then
-        pss=$(echo "${BASH_REMATCH[1]}" | tr -d , | sed 's/\.//g')
-        pid=$(echo "${BASH_REMATCH[2]}")
-    else
-        echo $cmd doesnt match $regex
-    fi
-}
-
-# Kills statsd.
-# Assumes the pid has been set.
-kill_statsd() {
-    echo "Killing statsd (pid ${pid})"
-    adb shell kill -9 "${pid}"
-}
-
-# Main loop.
-main() {
-    start_time=$(date +%s)
-    values=()
-    stop_loadtest
-
-    echo ""
-    echo "********************* NEW LOADTEST ************************"
-    update_pid_and_pss
-    for replication in 1 2 4 8 16 32 64 128 256 512 1024 2048 4096
-    do
-        echo "**** Starting test at replication ${replication} ****"
-
-        # (1) Restart statsd. This will ensure its state is empty.
-        kill_statsd
-        sleep 3 # wait a bit for it to restart
-        update_pid_and_pss
-        echo "Before the test, statsd's PSS is ${pss}"
-
-        # (2) Set the replication.
-        set_replication "${replication}"
-        sleep 1 # wait a bit
-
-        # (3) Start the loadtest.
-        start_loadtest
-
-        # (4) Wait several seconds, then read the PSS.
-        sleep 100 && update_pid_and_pss
-        echo "During the test, statsd's PSS is ${pss}"
-        values+=(${pss})
-
-        echo "Values: ${values[@]}"
-
-        # (5) Stop loadtest.
-        stop_loadtest
-        sleep 2
-
-        echo ""
-    done
-
-    end_time=$(date +%s)
-    echo "Completed loadtest in $((${end_time} - ${start_time})) seconds."
-
-    values_as_str=$(IFS=$'\n'; echo "${values[*]}")
-    echo "The PSS values are:"
-    echo "${values_as_str}"
-    echo ""
-}
-
-main
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
deleted file mode 100644
index bab0c1e..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.util.Log;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import java.text.ParseException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class BatteryDataRecorder extends PerfDataRecorder {
-    private static final String TAG = "loadtest.BatteryDataRecorder";
-    private static final String DUMP_FILENAME = TAG + "_dump.tmp";
-
-    public BatteryDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
-        int burst, boolean includeCountMetric, boolean includeDurationMetric,
-        boolean includeEventMetric,  boolean includeValueMetric, boolean includeGaugeMetric) {
-      super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
-          includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
-    }
-
-    @Override
-    public void startRecording(Context context) {
-        // Reset batterystats.
-        runDumpsysStats(context, DUMP_FILENAME, "batterystats", "--reset");
-    }
-
-    @Override
-    public void onAlarm(Context context) {
-        // Nothing to do as for battery, the whole data is in the final dumpsys call.
-    }
-
-    @Override
-    public void stopRecording(Context context) {
-        StringBuilder sb = new StringBuilder();
-        // Don't use --checkin.
-        runDumpsysStats(context, DUMP_FILENAME, "batterystats");
-        readDumpData(context, DUMP_FILENAME, new BatteryStatsParser(), sb);
-        writeData(context, "battery_", "time,battery_level", sb);
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
deleted file mode 100644
index 203d97a..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.util.Log;
-import java.text.ParseException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class BatteryStatsParser implements PerfParser {
-
-    private static final Pattern LINE_PATTERN =
-        Pattern.compile("\\s*\\+*(\\S*)\\s\\(\\d+\\)\\s(\\d\\d\\d)\\s.*");
-    private static final Pattern TIME_PATTERN =
-        Pattern.compile("(\\d+)?(h)?(\\d+)?(m)?(\\d+)?(s)?(\\d+)?(ms)?");
-    private static final String TAG = "loadtest.BatteryStatsParser";
-
-    private boolean mHistoryStarted;
-    private boolean mHistoryEnded;
-
-    public BatteryStatsParser() {
-    }
-
-    @Override
-    @Nullable
-    public String parseLine(String line) {
-        if (mHistoryEnded) {
-            return null;
-        }
-        if (!mHistoryStarted) {
-            if (line.contains("Battery History")) {
-                mHistoryStarted = true;
-            }
-            return null;
-        }
-        if (line.isEmpty()) {
-            mHistoryEnded = true;
-            return null;
-        }
-        Matcher lineMatcher = LINE_PATTERN.matcher(line);
-        if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
-            if (lineMatcher.group(1).equals("0")) {
-                return "0," + lineMatcher.group(2) + "\n";
-            } else {
-                Matcher timeMatcher = TIME_PATTERN.matcher(lineMatcher.group(1));
-                if (timeMatcher.find()) {
-                    Long time = getTime(lineMatcher.group(1));
-                    if (time != null) {
-                        return time + "," + lineMatcher.group(2) + "\n";
-                      } else {
-                        return null; // bad time
-                    }
-                } else {
-                  return null;  // bad or no time
-                }
-            }
-        }
-        return null;
-    }
-
-    @Nullable
-    private Long getTime(String group) {
-        if ("0".equals(group)) {
-            return 0L;
-        }
-        Matcher timeMatcher = TIME_PATTERN.matcher(group);
-        if (!timeMatcher.find()) {
-            return null;
-        }
-
-        // Get rid of "ms".
-        String[] matches = group.split("ms", -1);
-        if (matches.length > 1) {
-            group = matches[0];
-        }
-
-        long time = 0L;
-        matches = group.split("h");
-        if (matches.length > 1) {
-            time += Long.parseLong(matches[0]) * 60 * 60 * 1000;  // hours
-            group = matches[1];
-        }
-        matches = group.split("m");
-        if (matches.length > 1) {
-            time += Long.parseLong(matches[0]) * 60 * 1000;  // minutes
-            group = matches[1];
-        }
-        matches = group.split("s");
-        if (matches.length > 1) {
-            time += Long.parseLong(matches[0]) * 1000; // seconds
-            group = matches[1];
-        }
-
-        if (!group.isEmpty()) {
-            time += Long.parseLong(group); // milliseconds
-        }
-        return time;
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
deleted file mode 100644
index 2e0161b..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-import com.android.internal.os.StatsdConfigProto.Predicate;
-import com.android.internal.os.StatsdConfigProto.CountMetric;
-import com.android.internal.os.StatsdConfigProto.DurationMetric;
-import com.android.internal.os.StatsdConfigProto.MetricConditionLink;
-import com.android.internal.os.StatsdConfigProto.EventMetric;
-import com.android.internal.os.StatsdConfigProto.GaugeMetric;
-import com.android.internal.os.StatsdConfigProto.ValueMetric;
-import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
-import com.android.internal.os.StatsdConfigProto.AtomMatcher;
-import com.android.internal.os.StatsdConfigProto.SimplePredicate;
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Creates StatsdConfig protos for loadtesting.
- */
-public class ConfigFactory {
-    public static class ConfigMetadata {
-        public final byte[] bytes;
-        public final int numMetrics;
-
-        public ConfigMetadata(byte[] bytes, int numMetrics) {
-            this.bytes = bytes;
-            this.numMetrics = numMetrics;
-        }
-    }
-
-    public static final long CONFIG_ID = 123456789;
-
-    private static final String TAG = "loadtest.ConfigFactory";
-
-    private final StatsdConfig mTemplate;
-
-    public ConfigFactory(Context context) {
-        // Read the config template from the resoures.
-        Resources res = context.getResources();
-        byte[] template = null;
-        StatsdConfig templateProto = null;
-        try {
-            InputStream inputStream = res.openRawResource(R.raw.loadtest_config);
-            template = new byte[inputStream.available()];
-            inputStream.read(template);
-            templateProto = StatsdConfig.parseFrom(template);
-        } catch (IOException e) {
-            Log.e(TAG, "Unable to read or parse loadtest config template. Using an empty config.");
-        }
-        mTemplate = templateProto == null ? StatsdConfig.newBuilder().build() : templateProto;
-
-        Log.d(TAG, "Loadtest template config: " + mTemplate);
-    }
-
-    /**
-     * Generates a config.
-     *
-     * All configs are based on the same template.
-     * That template is designed to make the most use of the set of atoms that {@code SequencePusher}
-     * pushes, and to exercise as many of the metrics features as possible.
-     * Furthermore, by passing a replication factor to this method, one can artificially inflate
-     * the number of metrics in the config. One can also adjust the bucket size for aggregate
-     * metrics.
-     *
-     * @param replication The number of times each metric is replicated in the config.
-     *        If the config template has n metrics, the generated config will have n * replication
-     *        ones
-     * @param bucketMillis The bucket size, in milliseconds, for aggregate metrics
-     * @param placebo If true, only return an empty config
-     * @return The serialized config and the number of metrics.
-     */
-    public ConfigMetadata getConfig(int replication, TimeUnit bucket, boolean placebo,
-            boolean includeCount, boolean includeDuration, boolean includeEvent,
-            boolean includeValue, boolean includeGauge) {
-        StatsdConfig.Builder config = StatsdConfig.newBuilder()
-            .setId(CONFIG_ID);
-        if (placebo) {
-          replication = 0;  // Config will be empty, aside from a name.
-        }
-        int numMetrics = 0;
-        for (int i = 0; i < replication; i++) {
-            // metrics
-            if (includeEvent) {
-                for (EventMetric metric : mTemplate.getEventMetricList()) {
-                    addEventMetric(metric, i, config);
-                    numMetrics++;
-                }
-            }
-            if (includeCount) {
-                for (CountMetric metric : mTemplate.getCountMetricList()) {
-                    addCountMetric(metric, i, bucket, config);
-                    numMetrics++;
-                }
-            }
-            if (includeDuration) {
-                for (DurationMetric metric : mTemplate.getDurationMetricList()) {
-                    addDurationMetric(metric, i, bucket, config);
-                    numMetrics++;
-                }
-            }
-            if (includeGauge) {
-                for (GaugeMetric metric : mTemplate.getGaugeMetricList()) {
-                    addGaugeMetric(metric, i, bucket, config);
-                    numMetrics++;
-                }
-            }
-            if (includeValue) {
-                for (ValueMetric metric : mTemplate.getValueMetricList()) {
-                    addValueMetric(metric, i, bucket, config);
-                    numMetrics++;
-                }
-            }
-            // predicates
-            for (Predicate predicate : mTemplate.getPredicateList()) {
-              addPredicate(predicate, i, config);
-            }
-            // matchers
-            for (AtomMatcher matcher : mTemplate.getAtomMatcherList()) {
-              addMatcher(matcher, i, config);
-            }
-        }
-
-        Log.d(TAG, "Loadtest config is : " + config.build());
-        Log.d(TAG, "Generated config has " + numMetrics + " metrics");
-
-        return new ConfigMetadata(config.build().toByteArray(), numMetrics);
-    }
-
-    /**
-     * Creates {@link MetricConditionLink}s that are identical to the one passed to this method,
-     * except that the names are appended with the provided suffix.
-     */
-    private List<MetricConditionLink> getLinks(
-        List<MetricConditionLink> links, int suffix) {
-        List<MetricConditionLink> newLinks = new ArrayList();
-        for (MetricConditionLink link : links) {
-            newLinks.add(link.toBuilder()
-                .setCondition(link.getCondition() + suffix)
-                .build());
-        }
-        return newLinks;
-    }
-
-    /**
-     * Creates an {@link EventMetric} based on the template. Makes sure that all names are appended
-     * with the provided suffix. Then adds that metric to the config.
-     */
-    private void addEventMetric(EventMetric template, int suffix, StatsdConfig.Builder config) {
-        EventMetric.Builder metric = template.toBuilder()
-            .setId(template.getId() + suffix)
-            .setWhat(template.getWhat() + suffix);
-        if (template.hasCondition()) {
-            metric.setCondition(template.getCondition() + suffix);
-        }
-        if (template.getLinksCount() > 0) {
-            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
-            metric.clearLinks();
-            metric.addAllLinks(links);
-        }
-        config.addEventMetric(metric);
-    }
-
-    /**
-     * Creates a {@link CountMetric} based on the template. Makes sure that all names are appended
-     * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
-     */
-    private void addCountMetric(CountMetric template, int suffix, TimeUnit bucket,
-        StatsdConfig.Builder config) {
-        CountMetric.Builder metric = template.toBuilder()
-            .setId(template.getId() + suffix)
-            .setWhat(template.getWhat() + suffix);
-        if (template.hasCondition()) {
-            metric.setCondition(template.getCondition() + suffix);
-        }
-        if (template.getLinksCount() > 0) {
-            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
-            metric.clearLinks();
-            metric.addAllLinks(links);
-        }
-        metric.setBucket(bucket);
-        config.addCountMetric(metric);
-    }
-
-    /**
-     * Creates a {@link DurationMetric} based on the template. Makes sure that all names are appended
-     * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
-     */
-    private void addDurationMetric(DurationMetric template, int suffix, TimeUnit bucket,
-        StatsdConfig.Builder config) {
-        DurationMetric.Builder metric = template.toBuilder()
-            .setId(template.getId() + suffix)
-            .setWhat(template.getWhat() + suffix);
-        if (template.hasCondition()) {
-            metric.setCondition(template.getCondition() + suffix);
-        }
-        if (template.getLinksCount() > 0) {
-            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
-            metric.clearLinks();
-            metric.addAllLinks(links);
-        }
-        metric.setBucket(bucket);
-        config.addDurationMetric(metric);
-    }
-
-    /**
-     * Creates a {@link GaugeMetric} based on the template. Makes sure that all names are appended
-     * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
-     */
-    private void addGaugeMetric(GaugeMetric template, int suffix, TimeUnit bucket,
-        StatsdConfig.Builder config) {
-        GaugeMetric.Builder metric = template.toBuilder()
-            .setId(template.getId() + suffix)
-            .setWhat(template.getWhat() + suffix);
-        if (template.hasCondition()) {
-            metric.setCondition(template.getCondition() + suffix);
-        }
-        if (template.getLinksCount() > 0) {
-            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
-            metric.clearLinks();
-            metric.addAllLinks(links);
-        }
-        metric.setBucket(bucket);
-        config.addGaugeMetric(metric);
-    }
-
-    /**
-     * Creates a {@link ValueMetric} based on the template. Makes sure that all names are appended
-     * with the provided suffix, and overrides the bucket size. Then adds that metric to the config.
-     */
-    private void addValueMetric(ValueMetric template, int suffix, TimeUnit bucket,
-        StatsdConfig.Builder config) {
-        ValueMetric.Builder metric = template.toBuilder()
-            .setId(template.getId() + suffix)
-            .setWhat(template.getWhat() + suffix);
-        if (template.hasCondition()) {
-            metric.setCondition(template.getCondition() + suffix);
-        }
-        if (template.getLinksCount() > 0) {
-            List<MetricConditionLink> links = getLinks(template.getLinksList(), suffix);
-            metric.clearLinks();
-            metric.addAllLinks(links);
-        }
-        metric.setBucket(bucket);
-        config.addValueMetric(metric);
-    }
-
-    /**
-     * Creates a {@link Predicate} based on the template. Makes sure that all names
-     * are appended with the provided suffix. Then adds that predicate to the config.
-     */
-    private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) {
-        Predicate.Builder predicate = template.toBuilder()
-            .setId(template.getId() + suffix);
-        if (template.hasCombination()) {
-            Predicate.Combination.Builder cb = template.getCombination().toBuilder()
-                .clearPredicate();
-            for (long child : template.getCombination().getPredicateList()) {
-                cb.addPredicate(child + suffix);
-            }
-            predicate.setCombination(cb.build());
-        }
-        if (template.hasSimplePredicate()) {
-            SimplePredicate.Builder sc = template.getSimplePredicate().toBuilder()
-                .setStart(template.getSimplePredicate().getStart() + suffix)
-                .setStop(template.getSimplePredicate().getStop() + suffix);
-            if (template.getSimplePredicate().hasStopAll()) {
-                sc.setStopAll(template.getSimplePredicate().getStopAll() + suffix);
-            }
-            predicate.setSimplePredicate(sc.build());
-        }
-        config.addPredicate(predicate);
-    }
-
-    /**
-     * Creates a {@link AtomMatcher} based on the template. Makes sure that all names
-     * are appended with the provided suffix. Then adds that matcher to the config.
-     */
-    private void addMatcher(AtomMatcher template, int suffix, StatsdConfig.Builder config) {
-        AtomMatcher.Builder matcher = template.toBuilder()
-            .setId(template.getId() + suffix);
-        if (template.hasCombination()) {
-            AtomMatcher.Combination.Builder cb = template.getCombination().toBuilder()
-                .clearMatcher();
-            for (long child : template.getCombination().getMatcherList()) {
-                cb.addMatcher(child + suffix);
-            }
-            matcher.setCombination(cb);
-        }
-        config.addAtomMatcher(matcher);
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
deleted file mode 100644
index d55f3f3..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.text.format.DateFormat;
-
-import com.android.os.StatsLog;
-
-import java.util.List;
-
-public class DisplayProtoUtils {
-    private static final int MAX_NUM_METRICS_TO_DISPLAY = 10;
-
-    public static void displayLogReport(StringBuilder sb, StatsLog.ConfigMetricsReportList reports) {
-        sb.append("******************** Report ********************\n");
-        if (reports.hasConfigKey()) {
-            sb.append("ConfigKey: ");
-            com.android.os.StatsLog.ConfigMetricsReportList.ConfigKey key = reports.getConfigKey();
-            sb.append("\tuid: ").append(key.getUid()).append(" id: ").append(key.getId())
-                    .append("\n");
-        }
-
-        int numMetrics = 0;
-        for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
-            sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
-            sb.append("Last report time:").append(getDateStr(report.getLastReportElapsedNanos())).
-                    append("\n");
-            sb.append("Current report time:").append(getDateStr(report.getCurrentReportElapsedNanos())).
-                    append("\n");
-            for (StatsLog.StatsLogReport log : report.getMetricsList()) {
-                numMetrics++;
-                if (numMetrics > MAX_NUM_METRICS_TO_DISPLAY) {
-                    sb.append("... output truncated\n");
-                    sb.append("************************************************");
-                    return;
-                }
-                sb.append("\n");
-                sb.append("metric id: ").append(log.getMetricId()).append("\n");
-
-                switch (log.getDataCase()) {
-                    case DURATION_METRICS:
-                        sb.append("Duration metric data\n");
-                        displayDurationMetricData(sb, log);
-                        break;
-                    case EVENT_METRICS:
-                        sb.append("Event metric data\n");
-                        displayEventMetricData(sb, log);
-                        break;
-                    case COUNT_METRICS:
-                        sb.append("Count metric data\n");
-                        displayCountMetricData(sb, log);
-                        break;
-                    case GAUGE_METRICS:
-                        sb.append("Gauge metric data\n");
-                        displayGaugeMetricData(sb, log);
-                        break;
-                    case VALUE_METRICS:
-                        sb.append("Value metric data\n");
-                        displayValueMetricData(sb, log);
-                        break;
-                    case DATA_NOT_SET:
-                        sb.append("No metric data\n");
-                        break;
-                }
-            }
-        }
-        sb.append("************************************************");
-    }
-
-    public static String getDateStr(long nanoSec) {
-        return DateFormat.format("dd/MM hh:mm:ss", nanoSec/1000000).toString();
-    }
-
-    private static void displayDimension(StringBuilder sb, StatsLog.DimensionsValue dimensionValue) {
-        sb.append(dimensionValue.getField()).append(":");
-        if (dimensionValue.hasValueBool()) {
-            sb.append(dimensionValue.getValueBool());
-        } else if (dimensionValue.hasValueFloat()) {
-            sb.append(dimensionValue.getValueFloat());
-        } else if (dimensionValue.hasValueInt()) {
-            sb.append(dimensionValue.getValueInt());
-        } else if (dimensionValue.hasValueStr()) {
-            sb.append(dimensionValue.getValueStr());
-        } else if (dimensionValue.hasValueTuple()) {
-            sb.append("{");
-            for (StatsLog.DimensionsValue child :
-                    dimensionValue.getValueTuple().getDimensionsValueList()) {
-                displayDimension(sb, child);
-            }
-            sb.append("}");
-        }
-        sb.append(" ");
-    }
-
-    public static void displayDurationMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        StatsLog.StatsLogReport.DurationMetricDataWrapper durationMetricDataWrapper
-                = log.getDurationMetrics();
-        sb.append("Dimension size: ").append(durationMetricDataWrapper.getDataCount()).append("\n");
-        for (StatsLog.DurationMetricData duration : durationMetricDataWrapper.getDataList()) {
-            sb.append("dimension_in_what: ");
-            displayDimension(sb, duration.getDimensionsInWhat());
-            sb.append("\n");
-            if (duration.hasDimensionsInCondition()) {
-                sb.append("dimension_in_condition: ");
-                displayDimension(sb, duration.getDimensionsInCondition());
-                sb.append("\n");
-            }
-
-            for (StatsLog.DurationBucketInfo info : duration.getBucketInfoList())  {
-                sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
-                        .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
-                        .append(info.getDurationNanos()).append(" ns\n");
-            }
-        }
-    }
-
-    public static void displayEventMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        sb.append("Contains ").append(log.getEventMetrics().getDataCount()).append(" events\n");
-        StatsLog.StatsLogReport.EventMetricDataWrapper eventMetricDataWrapper =
-                log.getEventMetrics();
-        for (StatsLog.EventMetricData event : eventMetricDataWrapper.getDataList()) {
-            sb.append(getDateStr(event.getElapsedTimestampNanos())).append(": ");
-            sb.append(event.getAtom().getPushedCase().toString()).append("\n");
-        }
-    }
-
-    public static void displayCountMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        StatsLog.StatsLogReport.CountMetricDataWrapper countMetricDataWrapper
-                = log.getCountMetrics();
-        sb.append("Dimension size: ").append(countMetricDataWrapper.getDataCount()).append("\n");
-        for (StatsLog.CountMetricData count : countMetricDataWrapper.getDataList()) {
-            sb.append("dimension_in_what: ");
-            displayDimension(sb, count.getDimensionsInWhat());
-            sb.append("\n");
-            if (count.hasDimensionsInCondition()) {
-                sb.append("dimension_in_condition: ");
-                displayDimension(sb, count.getDimensionsInCondition());
-                sb.append("\n");
-            }
-
-            for (StatsLog.CountBucketInfo info : count.getBucketInfoList())  {
-                sb.append("\t[").append(getDateStr(info.getStartBucketElapsedNanos())).append("-")
-                        .append(getDateStr(info.getEndBucketElapsedNanos())).append("] -> ")
-                        .append(info.getCount()).append("\n");
-            }
-        }
-    }
-
-    public static void displayGaugeMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        sb.append("Display me!");
-    }
-
-    public static void displayValueMetricData(StringBuilder sb, StatsLog.StatsLogReport log) {
-        sb.append("Display me!");
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
deleted file mode 100644
index 769f78c..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.StatsManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IStatsManager;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.util.StatsLog;
-import android.view.View;
-import android.view.inputmethod.InputMethodManager;
-import android.view.MotionEvent;
-import android.view.View.OnFocusChangeListener;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.ConfigMetricsReportList;
-import com.android.os.StatsLog.StatsdStatsReport;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Runs a load test for statsd.
- * How it works:
- * <ul>
- * <li> Sets up and pushes a custom config with metrics that exercise a large swath of code paths.
- * <li> Periodically logs certain atoms into logd.
- * <li> Impact on battery can be printed to logcat, or a bug report can be filed and analyzed
- * in battery Historian.
- * </ul>
- * The load depends on how demanding the config is, as well as how frequently atoms are pushsed
- * to logd. Those are all controlled by 4 adjustable parameters:
- * <ul>
- * <li> The 'replication' parameter artificially multiplies the number of metrics in the config.
- * <li> The bucket size controls the time-bucketing the aggregate metrics.
- * <li> The period parameter controls how frequently atoms are pushed to logd.
- * <li> The 'burst' parameter controls how many atoms are pushed at the same time (per period).
- * </ul>
- */
-public class LoadtestActivity extends Activity implements AdapterView.OnItemSelectedListener {
-
-    private static final String TAG = "loadtest.LoadtestActivity";
-    public static final String TYPE = "type";
-    private static final String PUSH_ALARM = "push_alarm";
-    public static final String PERF_ALARM = "perf_alarm";
-    private static final String SET_REPLICATION = "set_replication";
-    private static final String REPLICATION = "replication";
-    private static final String START = "start";
-    private static final String STOP = "stop";
-    private static final Map<String, TimeUnit> TIME_UNIT_MAP = initializeTimeUnitMap();
-    private static final List<String> TIME_UNIT_LABELS = initializeTimeUnitLabels();
-
-    public final static class PusherAlarmReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Intent activityIntent = new Intent(context, LoadtestActivity.class);
-            activityIntent.putExtra(TYPE, PUSH_ALARM);
-            context.startActivity(activityIntent);
-        }
-    }
-
-    public final static class StopperAlarmReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Intent activityIntent = new Intent(context, LoadtestActivity.class);
-            activityIntent.putExtra(TYPE, STOP);
-            context.startActivity(activityIntent);
-        }
-    }
-
-    private static Map<String, TimeUnit> initializeTimeUnitMap() {
-        Map<String, TimeUnit> labels = new HashMap();
-        labels.put("1m", TimeUnit.ONE_MINUTE);
-        labels.put("5m", TimeUnit.FIVE_MINUTES);
-        labels.put("10m", TimeUnit.TEN_MINUTES);
-        labels.put("30m", TimeUnit.THIRTY_MINUTES);
-        labels.put("1h", TimeUnit.ONE_HOUR);
-        labels.put("3h", TimeUnit.THREE_HOURS);
-        labels.put("6h", TimeUnit.SIX_HOURS);
-        labels.put("12h", TimeUnit.TWELVE_HOURS);
-        labels.put("1d", TimeUnit.ONE_DAY);
-        labels.put("1s", TimeUnit.CTS);
-        return labels;
-    }
-
-    private static List<String> initializeTimeUnitLabels() {
-        List<String> labels = new ArrayList();
-        labels.add("1s");
-        labels.add("1m");
-        labels.add("5m");
-        labels.add("10m");
-        labels.add("30m");
-        labels.add("1h");
-        labels.add("3h");
-        labels.add("6h");
-        labels.add("12h");
-        labels.add("1d");
-        return labels;
-    }
-
-    private AlarmManager mAlarmMgr;
-
-    /**
-     * Used to periodically log atoms to logd.
-     */
-    private PendingIntent mPushPendingIntent;
-
-    /**
-     * Used to end the loadtest.
-     */
-    private PendingIntent mStopPendingIntent;
-
-    private Button mStartStop;
-    private EditText mReplicationText;
-    private Spinner mBucketSpinner;
-    private EditText mPeriodText;
-    private EditText mBurstText;
-    private EditText mDurationText;
-    private TextView mReportText;
-    private CheckBox mPlaceboCheckBox;
-    private CheckBox mCountMetricCheckBox;
-    private CheckBox mDurationMetricCheckBox;
-    private CheckBox mEventMetricCheckBox;
-    private CheckBox mValueMetricCheckBox;
-    private CheckBox mGaugeMetricCheckBox;
-
-    /**
-     * When the load test started.
-     */
-    private long mStartedTimeMillis;
-
-    /**
-     * For measuring perf data.
-     */
-    private PerfData mPerfData;
-
-    /**
-     * For communicating with statsd.
-     */
-    private StatsManager mStatsManager;
-
-    private PowerManager mPowerManager;
-    private WakeLock mWakeLock;
-
-    /**
-     * If true, we only measure the effect of the loadtest infrastructure. No atom are pushed and
-     * the configuration is empty.
-     */
-    private boolean mPlacebo;
-
-    /**
-     * Whether to include CountMetric in the config.
-     */
-    private boolean mIncludeCountMetric;
-
-    /**
-     * Whether to include DurationMetric in the config.
-     */
-    private boolean mIncludeDurationMetric;
-
-    /**
-     * Whether to include EventMetric in the config.
-     */
-    private boolean mIncludeEventMetric;
-
-    /**
-     * Whether to include ValueMetric in the config.
-     */
-    private boolean mIncludeValueMetric;
-
-    /**
-     * Whether to include GaugeMetric in the config.
-     */
-    private boolean mIncludeGaugeMetric;
-
-    /**
-     * The burst size.
-     */
-    private int mBurst;
-
-    /**
-     * The metrics replication.
-     */
-    private int mReplication;
-
-    /**
-     * The period, in seconds, at which batches of atoms are pushed.
-     */
-    private long mPeriodSecs;
-
-    /**
-     * The bucket size, in minutes, for aggregate metrics.
-     */
-    private TimeUnit mBucket;
-
-    /**
-     * The duration, in minutes, of the loadtest.
-     */
-    private long mDurationMins;
-
-    /**
-     * Whether the loadtest has started.
-     */
-    private boolean mStarted = false;
-
-    /**
-     * Orchestrates the logging of pushed events into logd.
-     */
-    private SequencePusher mPusher;
-
-    /**
-     * Generates statsd configs.
-     */
-    private ConfigFactory mFactory;
-
-    /**
-     * For intra-minute periods.
-     */
-    private final Handler mHandler = new Handler();
-
-    /**
-     * Number of metrics in the current config.
-     */
-    private int mNumMetrics;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        Log.d(TAG, "Starting loadtest Activity");
-
-        setContentView(R.layout.activity_loadtest);
-        mReportText = (TextView) findViewById(R.id.report_text);
-        initBurst();
-        initReplication();
-        initBucket();
-        initPeriod();
-        initDuration();
-        initPlacebo();
-        initMetricWhitelist();
-
-        // Hide the keyboard outside edit texts.
-        findViewById(R.id.outside).setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                InputMethodManager imm =
-                        (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-                if (getCurrentFocus() != null) {
-                    imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
-                }
-                return true;
-            }
-        });
-
-        mStartStop = findViewById(R.id.start_stop);
-        mStartStop.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                if (mStarted) {
-                    stopLoadtest();
-                } else {
-                    startLoadtest();
-                }
-            }
-        });
-
-        mAlarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
-        mStatsManager = (StatsManager) getSystemService("stats");
-        mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
-        mFactory = new ConfigFactory(this);
-        stopLoadtest();
-        mReportText.setText("");
-    }
-
-    @Override
-    public void onNewIntent(Intent intent) {
-        String type = intent.getStringExtra(TYPE);
-        if (type == null) {
-            return;
-        }
-        switch (type) {
-            case PERF_ALARM:
-                onPerfAlarm();
-                break;
-            case PUSH_ALARM:
-                onAlarm();
-                break;
-            case SET_REPLICATION:
-                if (intent.hasExtra(REPLICATION)) {
-                    setReplication(intent.getIntExtra(REPLICATION, 0));
-                }
-                break;
-            case START:
-                startLoadtest();
-                break;
-            case STOP:
-                stopLoadtest();
-                break;
-            default:
-                throw new IllegalArgumentException("Unknown type: " + type);
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        Log.d(TAG, "Destroying");
-        mPerfData.onDestroy();
-        stopLoadtest();
-        clearConfigs();
-        super.onDestroy();
-    }
-
-    @Nullable
-    public StatsdStatsReport getMetadata() {
-        if (!statsdRunning()) {
-            return null;
-        }
-        if (mStatsManager != null) {
-            byte[] data;
-            try {
-                data = mStatsManager.getStatsMetadata();
-            } catch (StatsManager.StatsUnavailableException e) {
-                Log.e(TAG, "Failed to get data from statsd", e);
-                return null;
-            }
-            if (data != null) {
-                StatsdStatsReport report = null;
-                boolean good = false;
-                try {
-                    return StatsdStatsReport.parseFrom(data);
-                } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-                    Log.d(TAG, "Bad StatsdStatsReport");
-                }
-            }
-        }
-        return null;
-    }
-
-    @Nullable
-    public List<ConfigMetricsReport> getData() {
-        if (!statsdRunning()) {
-            return null;
-        }
-        if (mStatsManager != null) {
-            byte[] data;
-            try {
-                data = mStatsManager.getReports(ConfigFactory.CONFIG_ID);
-            } catch (StatsManager.StatsUnavailableException e) {
-                Log.e(TAG, "Failed to get data from statsd", e);
-                return null;
-            }
-            if (data != null) {
-                ConfigMetricsReportList reports = null;
-                try {
-                    reports = ConfigMetricsReportList.parseFrom(data);
-                    Log.d(TAG, "Num reports: " + reports.getReportsCount());
-                    StringBuilder sb = new StringBuilder();
-                    DisplayProtoUtils.displayLogReport(sb, reports);
-                    Log.d(TAG, sb.toString());
-                } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-                    Log.d(TAG, "Invalid data");
-                }
-                if (reports != null) {
-                    return reports.getReportsList();
-                }
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-        String item = parent.getItemAtPosition(position).toString();
-
-        mBucket = TIME_UNIT_MAP.get(item);
-    }
-
-    @Override
-    public void onNothingSelected(AdapterView<?> parent) {
-        // Another interface callback
-    }
-
-    private void onPerfAlarm() {
-        if (mPerfData != null) {
-            mPerfData.onAlarm(this);
-        }
-        // Piggy-back on that alarm to show the elapsed time.
-        long elapsedTimeMins = (long) Math.floor(
-                (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
-        mReportText.setText("Loadtest in progress.\n"
-                + "num metrics =" + mNumMetrics
-                + "\nElapsed time = " + elapsedTimeMins + " min(s)");
-    }
-
-    private void onAlarm() {
-        Log.d(TAG, "ON ALARM");
-
-        // Set the next task.
-        scheduleNext();
-
-        // Do the work.
-        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "StatsdLoadTest");
-        mWakeLock.acquire();
-        if (mPusher != null) {
-            mPusher.next();
-        }
-        mWakeLock.release();
-        mWakeLock = null;
-    }
-
-    /**
-     * Schedules the next cycle of pushing atoms into logd.
-     */
-    private void scheduleNext() {
-        Intent intent = new Intent(this, PusherAlarmReceiver.class);
-        intent.putExtra(TYPE, PUSH_ALARM);
-        mPushPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
-        long nextTime = SystemClock.elapsedRealtime() + mPeriodSecs * 1000;
-        mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mPushPendingIntent);
-    }
-
-    private synchronized void startLoadtest() {
-        if (mStarted) {
-            return;
-        }
-
-        // Clean up the state.
-        stopLoadtest();
-
-        // Prepare to push a sequence of atoms to logd.
-        mPusher = new SequencePusher(mBurst, mPlacebo);
-
-        // Create a config and push it to statsd.
-        if (!setConfig(mFactory.getConfig(mReplication, mBucket, mPlacebo,
-                mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric,
-                mIncludeValueMetric, mIncludeGaugeMetric))) {
-            return;
-        }
-
-        // Remember to stop in the future.
-        Intent intent = new Intent(this, StopperAlarmReceiver.class);
-        intent.putExtra(TYPE, STOP);
-        mStopPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
-        long nextTime = SystemClock.elapsedRealtime() + mDurationMins * 60 * 1000;
-        mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mStopPendingIntent);
-
-        // Log atoms.
-        scheduleNext();
-
-        // Start tracking performance.
-        mPerfData = new PerfData(this, mPlacebo, mReplication, mBucket, mPeriodSecs, mBurst,
-                mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric, mIncludeValueMetric,
-                mIncludeGaugeMetric);
-        mPerfData.startRecording(this);
-
-        mReportText.setText("Loadtest in progress.\nnum metrics =" + mNumMetrics);
-        mStartedTimeMillis = SystemClock.elapsedRealtime();
-
-        updateStarted(true);
-    }
-
-    private synchronized void stopLoadtest() {
-        if (mPushPendingIntent != null) {
-            Log.d(TAG, "Canceling pre-existing push alarm");
-            mAlarmMgr.cancel(mPushPendingIntent);
-            mPushPendingIntent = null;
-        }
-        if (mStopPendingIntent != null) {
-            Log.d(TAG, "Canceling pre-existing stop alarm");
-            mAlarmMgr.cancel(mStopPendingIntent);
-            mStopPendingIntent = null;
-        }
-        if (mWakeLock != null) {
-            mWakeLock.release();
-            mWakeLock = null;
-        }
-        if (mPerfData != null) {
-            mPerfData.stopRecording(this);
-            mPerfData.onDestroy();
-            mPerfData = null;
-        }
-
-        // Obtain the latest data and display it.
-        getData();
-
-        long elapsedTimeMins = (long) Math.floor(
-                (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
-        mReportText.setText("Loadtest ended. Elapsed time = " + elapsedTimeMins + " min(s)");
-        clearConfigs();
-        updateStarted(false);
-    }
-
-    private synchronized void updateStarted(boolean started) {
-        mStarted = started;
-        mStartStop.setBackgroundColor(started ?
-                Color.parseColor("#FFFF0000") : Color.parseColor("#FF00FF00"));
-        mStartStop.setText(started ? getString(R.string.stop) : getString(R.string.start));
-        updateControlsEnabled();
-    }
-
-    private void updateControlsEnabled() {
-        mBurstText.setEnabled(!mPlacebo && !mStarted);
-        mReplicationText.setEnabled(!mPlacebo && !mStarted);
-        mPeriodText.setEnabled(!mStarted);
-        mBucketSpinner.setEnabled(!mPlacebo && !mStarted);
-        mDurationText.setEnabled(!mStarted);
-        mPlaceboCheckBox.setEnabled(!mStarted);
-
-        boolean enabled = !mStarted && !mPlaceboCheckBox.isChecked();
-        mCountMetricCheckBox.setEnabled(enabled);
-        mDurationMetricCheckBox.setEnabled(enabled);
-        mEventMetricCheckBox.setEnabled(enabled);
-        mValueMetricCheckBox.setEnabled(enabled);
-        mGaugeMetricCheckBox.setEnabled(enabled);
-    }
-
-    private boolean statsdRunning() {
-        if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) {
-            Log.d(TAG, "Statsd not running");
-            Toast.makeText(LoadtestActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show();
-            return false;
-        }
-        return true;
-    }
-
-    private int sanitizeInt(int val, int min, int max) {
-        if (val > max) {
-            val = max;
-        } else if (val < min) {
-            val = min;
-        }
-        return val;
-    }
-
-    private void clearConfigs() {
-        // TODO: Clear all configs instead of specific ones.
-        if (mStatsManager != null) {
-            if (mStarted) {
-                try {
-                    mStatsManager.removeConfig(ConfigFactory.CONFIG_ID);
-                    Log.d(TAG, "Removed loadtest statsd configs.");
-                } catch (StatsManager.StatsUnavailableException e) {
-                    Log.e(TAG, "Failed to remove loadtest configs.", e);
-                }
-            }
-        }
-    }
-
-    private boolean setConfig(ConfigFactory.ConfigMetadata configData) {
-        if (mStatsManager != null) {
-            try {
-                mStatsManager.addConfig(ConfigFactory.CONFIG_ID, configData.bytes);
-                mNumMetrics = configData.numMetrics;
-                Log.d(TAG, "Config pushed to statsd");
-                return true;
-            } catch (StatsManager.StatsUnavailableException | IllegalArgumentException e) {
-                Log.e(TAG, "Failed to push config to statsd", e);
-            }
-        }
-        return false;
-    }
-
-    private synchronized void setReplication(int replication) {
-        if (mStarted) {
-            return;
-        }
-        mReplicationText.setText("" + replication);
-    }
-
-    private synchronized void setPeriodSecs(long periodSecs) {
-        mPeriodSecs = periodSecs;
-    }
-
-    private synchronized void setBurst(int burst) {
-        mBurst = burst;
-    }
-
-    private synchronized void setDurationMins(long durationMins) {
-        mDurationMins = durationMins;
-    }
-
-
-    private void handleFocus(EditText editText) {
-      /*
-        editText.setOnFocusChangeListener(new OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (!hasFocus && editText.getText().toString().isEmpty()) {
-                    editText.setText("-1", TextView.BufferType.EDITABLE);
-                }
-            }
-        });
-      */
-    }
-
-    private void initBurst() {
-        mBurst = getResources().getInteger(R.integer.burst_default);
-        mBurstText = (EditText) findViewById(R.id.burst);
-        mBurstText.addTextChangedListener(new NumericalWatcher(mBurstText, 0, 1000) {
-            @Override
-            public void onNewValue(int newValue) {
-                setBurst(newValue);
-            }
-        });
-        handleFocus(mBurstText);
-    }
-
-    private void initReplication() {
-        mReplication = getResources().getInteger(R.integer.replication_default);
-        mReplicationText = (EditText) findViewById(R.id.replication);
-        mReplicationText.addTextChangedListener(new NumericalWatcher(mReplicationText, 1, 4096) {
-            @Override
-            public void onNewValue(int newValue) {
-                mReplication = newValue;
-            }
-        });
-        handleFocus(mReplicationText);
-    }
-
-    private void initBucket() {
-        String defaultValue = getResources().getString(R.string.bucket_default);
-        mBucket = TimeUnit.valueOf(defaultValue);
-        mBucketSpinner = (Spinner) findViewById(R.id.bucket_spinner);
-
-        ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(
-                this, R.layout.spinner_item, TIME_UNIT_LABELS);
-
-        mBucketSpinner.setAdapter(dataAdapter);
-        mBucketSpinner.setOnItemSelectedListener(this);
-
-        for (String label : TIME_UNIT_MAP.keySet()) {
-            if (defaultValue.equals(TIME_UNIT_MAP.get(label).toString())) {
-                mBucketSpinner.setSelection(dataAdapter.getPosition(label));
-            }
-        }
-    }
-
-    private void initPeriod() {
-        mPeriodSecs = getResources().getInteger(R.integer.period_default);
-        mPeriodText = (EditText) findViewById(R.id.period);
-        mPeriodText.addTextChangedListener(new NumericalWatcher(mPeriodText, 1, 60) {
-            @Override
-            public void onNewValue(int newValue) {
-                setPeriodSecs(newValue);
-            }
-        });
-        handleFocus(mPeriodText);
-    }
-
-    private void initDuration() {
-        mDurationMins = getResources().getInteger(R.integer.duration_default);
-        mDurationText = (EditText) findViewById(R.id.duration);
-        mDurationText.addTextChangedListener(new NumericalWatcher(mDurationText, 1, 24 * 60) {
-            @Override
-            public void onNewValue(int newValue) {
-                setDurationMins(newValue);
-            }
-        });
-        handleFocus(mDurationText);
-    }
-
-    private void initPlacebo() {
-        mPlaceboCheckBox = findViewById(R.id.placebo);
-        mPlacebo = false;
-        mPlaceboCheckBox.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPlacebo = mPlaceboCheckBox.isChecked();
-                updateControlsEnabled();
-            }
-        });
-    }
-
-    private void initMetricWhitelist() {
-        mCountMetricCheckBox = findViewById(R.id.include_count);
-        mCountMetricCheckBox.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mIncludeCountMetric = mCountMetricCheckBox.isChecked();
-            }
-        });
-        mDurationMetricCheckBox = findViewById(R.id.include_duration);
-        mDurationMetricCheckBox.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mIncludeDurationMetric = mDurationMetricCheckBox.isChecked();
-            }
-        });
-        mEventMetricCheckBox = findViewById(R.id.include_event);
-        mEventMetricCheckBox.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mIncludeEventMetric = mEventMetricCheckBox.isChecked();
-            }
-        });
-        mValueMetricCheckBox = findViewById(R.id.include_value);
-        mValueMetricCheckBox.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mIncludeValueMetric = mValueMetricCheckBox.isChecked();
-            }
-        });
-        mGaugeMetricCheckBox = findViewById(R.id.include_gauge);
-        mGaugeMetricCheckBox.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mIncludeGaugeMetric = mGaugeMetricCheckBox.isChecked();
-            }
-        });
-
-        mIncludeCountMetric = mCountMetricCheckBox.isChecked();
-        mIncludeDurationMetric = mDurationMetricCheckBox.isChecked();
-        mIncludeEventMetric = mEventMetricCheckBox.isChecked();
-        mIncludeValueMetric = mValueMetricCheckBox.isChecked();
-        mIncludeGaugeMetric = mGaugeMetricCheckBox.isChecked();
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
deleted file mode 100644
index 01eebf2..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.os.SystemClock;
-import android.util.Log;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/** Parses PSS info from dumpsys meminfo */
-public class MemInfoParser implements PerfParser {
-
-    private static final Pattern LINE_PATTERN =
-        Pattern.compile("\\s*(\\d*,*\\d*)K:\\s(\\S*)\\s\\.*");
-    private static final String PSS_BY_PROCESS = "Total PSS by process:";
-    private static final String TAG = "loadtest.MemInfoParser";
-
-    private boolean mPssStarted;
-    private boolean mPssEnded;
-    private final long mStartTimeMillis;
-
-    public MemInfoParser(long startTimeMillis) {
-        mStartTimeMillis = startTimeMillis;
-    }
-
-    @Override
-    @Nullable
-    public String parseLine(String line) {
-        if (mPssEnded) {
-            return null;
-        }
-        if (!mPssStarted) {
-            if (line.contains(PSS_BY_PROCESS)) {
-                mPssStarted = true;
-            }
-            return null;
-        }
-        if (line.isEmpty()) {
-            mPssEnded = true;
-            return null;
-        }
-        Matcher lineMatcher = LINE_PATTERN.matcher(line);
-        if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
-            if (lineMatcher.group(2).equals("statsd")) {
-                long timeDeltaMillis = SystemClock.elapsedRealtime() - mStartTimeMillis;
-                return timeDeltaMillis + "," + convertToPss(lineMatcher.group(1));
-            }
-        }
-        return null;
-    }
-
-    private String convertToPss(String input) {
-        return input.replace(",", "");
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
deleted file mode 100644
index af7bd4d..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.content.Context;
-import android.os.SystemClock;
-import android.util.Log;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-public class MemoryDataRecorder extends PerfDataRecorder {
-    private static final String TAG = "loadtest.MemoryDataDataRecorder";
-    private static final String DUMP_FILENAME = TAG + "_dump.tmp";
-
-    private long mStartTimeMillis;
-    private StringBuilder mSb;
-
-    public MemoryDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
-        int burst,  boolean includeCountMetric, boolean includeDurationMetric,
-        boolean includeEventMetric,  boolean includeValueMetric, boolean includeGaugeMetric) {
-      super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
-          includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
-    }
-
-    @Override
-    public void startRecording(Context context) {
-        mStartTimeMillis = SystemClock.elapsedRealtime();
-        mSb = new StringBuilder();
-    }
-
-    @Override
-    public void onAlarm(Context context) {
-        runDumpsysStats(context, DUMP_FILENAME, "meminfo");
-        readDumpData(context, DUMP_FILENAME, new MemInfoParser(mStartTimeMillis), mSb);
-    }
-
-    @Override
-    public void stopRecording(Context context) {
-        writeData(context, "meminfo_", "time,pss", mSb);
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
deleted file mode 100644
index 555e6dd..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.widget.TextView;
-
-public abstract class NumericalWatcher implements TextWatcher {
-
-    private static final String TAG = "loadtest.NumericalWatcher";
-
-    private final TextView mTextView;
-    private final int mMin;
-    private final int mMax;
-    private int currentValue = -1;
-
-    public NumericalWatcher(TextView textView, int min, int max) {
-        mTextView = textView;
-        mMin = min;
-        mMax = max;
-    }
-
-    public abstract void onNewValue(int newValue);
-
-    @Override
-    final public void afterTextChanged(Editable editable) {
-        String s = mTextView.getText().toString();
-        if (s.isEmpty()) {
-          return;
-        }
-        int unsanitized = Integer.parseInt(s);
-        int newValue = sanitize(unsanitized);
-        if (currentValue != newValue || unsanitized != newValue) {
-            currentValue = newValue;
-            editable.clear();
-            editable.append(newValue + "");
-        }
-        onNewValue(newValue);
-    }
-
-    @Override
-    final public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
-    @Override
-    final public void onTextChanged(CharSequence s, int start, int before, int count) {}
-
-    private int sanitize(int val) {
-        if (val > mMax) {
-            val = mMax;
-        } else if (val < mMin) {
-            val = mMin;
-        }
-        return val;
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
deleted file mode 100644
index 7a01ade..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/** Prints some information about the device via Dumpsys in order to evaluate health metrics. */
-public class PerfData extends PerfDataRecorder {
-
-    private static final String TAG = "loadtest.PerfData";
-
-    /** Polling period for performance snapshots like memory. */
-    private static final long POLLING_PERIOD_MILLIS = 1 * 60 * 1000;
-
-    public final static class PerfAlarmReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Intent activityIntent = new Intent(context, LoadtestActivity.class);
-            activityIntent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
-            context.startActivity(activityIntent);
-         }
-    }
-
-    private AlarmManager mAlarmMgr;
-
-    /** Used to periodically poll some dumpsys data. */
-    private PendingIntent mPendingIntent;
-
-    private final Set<PerfDataRecorder> mRecorders;
-
-    public PerfData(LoadtestActivity loadtestActivity, boolean placebo, int replication,
-        TimeUnit bucket, long periodSecs,  int burst, boolean includeCountMetric,
-        boolean includeDurationMetric, boolean includeEventMetric,  boolean includeValueMetric,
-        boolean includeGaugeMetric) {
-      super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
-          includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
-        mRecorders = new HashSet();
-        mRecorders.add(new BatteryDataRecorder(placebo, replication, bucket, periodSecs, burst,
-                includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
-                includeGaugeMetric));
-        mRecorders.add(new MemoryDataRecorder(placebo, replication, bucket, periodSecs, burst,
-                includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
-                includeGaugeMetric));
-        mRecorders.add(new StatsdStatsRecorder(loadtestActivity, placebo, replication, bucket,
-                periodSecs, burst, includeCountMetric, includeDurationMetric, includeEventMetric,
-                includeValueMetric, includeGaugeMetric));
-        mRecorders.add(new ValidationRecorder(loadtestActivity, placebo, replication, bucket,
-                periodSecs, burst, includeCountMetric, includeDurationMetric, includeEventMetric,
-                includeValueMetric, includeGaugeMetric));
-        mAlarmMgr = (AlarmManager) loadtestActivity.getSystemService(Context.ALARM_SERVICE);
-    }
-
-    public void onDestroy() {
-        if (mPendingIntent != null) {
-            mAlarmMgr.cancel(mPendingIntent);
-            mPendingIntent = null;
-        }
-    }
-
-    @Override
-    public void startRecording(Context context) {
-        Intent intent = new Intent(context, PerfAlarmReceiver.class);
-        intent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
-        mPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
-        mAlarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, -1 /* now */,
-            POLLING_PERIOD_MILLIS, mPendingIntent);
-
-        for (PerfDataRecorder recorder : mRecorders) {
-            recorder.startRecording(context);
-        }
-    }
-
-    @Override
-    public void onAlarm(Context context) {
-        for (PerfDataRecorder recorder : mRecorders) {
-            recorder.onAlarm(context);
-        }
-    }
-
-    @Override
-    public void stopRecording(Context context) {
-        if (mPendingIntent != null) {
-            mAlarmMgr.cancel(mPendingIntent);
-            mPendingIntent = null;
-        }
-
-        for (PerfDataRecorder recorder : mRecorders) {
-            recorder.stopRecording(context);
-        }
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
deleted file mode 100644
index 8613ac1..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Environment;
-import android.util.Log;
-import android.os.Debug;
-
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public abstract class PerfDataRecorder {
-    private static final String TAG = "loadtest.PerfDataRecorder";
-
-    protected final String mTimeAsString;
-    protected final String mColumnSuffix;
-
-    protected PerfDataRecorder(boolean placebo, int replication, TimeUnit bucket, long periodSecs,
-        int burst, boolean includeCountMetric, boolean includeDurationMetric,
-        boolean includeEventMetric,  boolean includeValueMetric, boolean includeGaugeMetric) {
-        mTimeAsString = new SimpleDateFormat("YYYY_MM_dd_HH_mm_ss").format(new Date());
-        mColumnSuffix = getColumnSuffix(placebo, replication, bucket, periodSecs, burst,
-            includeCountMetric, includeDurationMetric, includeEventMetric, includeValueMetric,
-            includeGaugeMetric);
-    }
-
-    /** Starts recording performance data. */
-    public abstract void startRecording(Context context);
-
-    /** Called periodically. For the recorder to sample data, if needed. */
-    public abstract void onAlarm(Context context);
-
-    /** Stops recording performance data, and writes it to disk. */
-    public abstract void stopRecording(Context context);
-
-    /** Runs the dumpsys command. */
-    protected void runDumpsysStats(Context context, String dumpFilename, String cmd,
-        String... args) {
-        boolean success = false;
-        // Call dumpsys Dump statistics to a file.
-        FileOutputStream fo = null;
-        try {
-            fo = context.openFileOutput(dumpFilename, Context.MODE_PRIVATE);
-            if (!Debug.dumpService(cmd, fo.getFD(), args)) {
-                Log.w(TAG, "Dumpsys failed.");
-            }
-            success = true;
-        } catch (IOException | SecurityException | NullPointerException e) {
-            // SecurityException may occur when trying to dump multi-user info.
-            // NPE can occur during dumpService  (root cause unknown).
-            throw new RuntimeException(e);
-        } finally {
-            closeQuietly(fo);
-        }
-    }
-
-    /**
-     * Reads a text file and parses each line, one by one. The result of the parsing is stored
-     * in the passed {@link StringBuffer}.
-     */
-    protected void readDumpData(Context context, String dumpFilename, PerfParser parser,
-        StringBuilder sb) {
-        FileInputStream fi = null;
-        BufferedReader br = null;
-        try {
-            fi = context.openFileInput(dumpFilename);
-            br = new BufferedReader(new InputStreamReader(fi));
-            String line = br.readLine();
-            while (line != null) {
-                String recordLine = parser.parseLine(line);
-                if (recordLine != null) {
-                  sb.append(recordLine).append('\n');
-                }
-                line = br.readLine();
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        } finally {
-            closeQuietly(br);
-        }
-    }
-
-    /** Writes CSV data to a file. */
-    protected void writeData(Context context, String filePrefix, String columnPrefix,
-        StringBuilder sb) {
-        File dataFile = new File(getStorageDir(), filePrefix + mTimeAsString + ".csv");
-
-        FileWriter writer = null;
-        try {
-            writer = new FileWriter(dataFile);
-            writer.append(columnPrefix + mColumnSuffix + "\n");
-            writer.append(sb.toString());
-            writer.flush();
-            Log.d(TAG, "Finished writing data at " + dataFile.getAbsolutePath());
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        } finally {
-            closeQuietly(writer);
-        }
-    }
-
-    /** Gets the suffix to use in the column name for perf data. */
-    private String getColumnSuffix(boolean placebo, int replication, TimeUnit bucket,
-        long periodSecs, int burst, boolean includeCountMetric, boolean includeDurationMetric,
-        boolean includeEventMetric,  boolean includeValueMetric, boolean includeGaugeMetric) {
-        if (placebo) {
-            return "_placebo_p=" + periodSecs;
-        }
-        StringBuilder sb = new StringBuilder()
-            .append("_r=" + replication)
-            .append("_bkt=" + bucket)
-            .append("_p=" + periodSecs)
-            .append("_bst=" + burst)
-            .append("_m=");
-        if (includeCountMetric) {
-            sb.append("c");
-        }
-        if (includeEventMetric) {
-            sb.append("e");
-        }
-        if (includeDurationMetric) {
-            sb.append("d");
-        }
-        if (includeGaugeMetric) {
-            sb.append("g");
-        }
-        if (includeValueMetric) {
-            sb.append("v");
-        }
-        return sb.toString();
-    }
-
-    private File getStorageDir() {
-        File file = new File(Environment.getExternalStoragePublicDirectory(
-            Environment.DIRECTORY_DOCUMENTS), "loadtest/" + mTimeAsString);
-        if (!file.mkdirs()) {
-            Log.e(TAG, "Directory not created");
-        }
-        return file;
-    }
-
-    private void closeQuietly(@Nullable Closeable c) {
-        if (c != null) {
-            try {
-                c.close();
-            } catch (IOException ignore) {
-            }
-        }
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
deleted file mode 100644
index e000918..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.annotation.Nullable;
-
-public interface PerfParser {
-
-  /**
-   * Parses one line of the dumpsys output, and returns a string to write to the data file,
-   * or null if no string should be written.
-   */
-  @Nullable String parseLine(String line);
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
deleted file mode 100644
index 5dcce9a..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.util.Log;
-import android.util.StatsLog;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Manages the pushing of atoms into logd for loadtesting.
- * We rely on small number of pushed atoms, and a config with metrics based on those atoms.
- * The atoms are:
- * <ul>
- *   <li> BatteryLevelChanged   - For EventMetric, CountMetric and GaugeMetric (no dimensions).
- *   <li> BleScanResultReceived - For CountMetric and ValueMetric, sliced by uid.
- *   <li> ChargingStateChanged  - For DurationMetric (no dimension).
- *   <li> GpsScanStateChanged   - For DurationMetric, sliced by uid.
- *   <li> ScreenStateChanged    - For Conditions with no dimensions.
- *   <li> AudioStateChanged     - For Conditions with dimensions (uid).
- * </ul>
- * The sequence is played over and over at a given frequency.
- */
-public class SequencePusher {
-    private static final String TAG = "SequencePusher";
-
-    /** Some atoms are pushed in burst of {@code mBurst} events. */
-    private final int mBurst;
-
-    /** If this is true, we don't log anything in logd. */
-    private final boolean mPlacebo;
-
-    /** Current state in the automaton. */
-    private int mCursor = 0;
-
-  public SequencePusher(int burst, boolean placebo) {
-        mBurst = burst;
-        mPlacebo = placebo;
-    }
-
-    /**
-     * Pushes the next atom to logd.
-     * This follows a small automaton which makes the right events and conditions overlap:
-     *   (0)  Push a burst of BatteryLevelChanged atoms.
-     *   (1)  Push a burst of BleScanResultReceived atoms.
-     *   (2)  Push ChargingStateChanged with BATTERY_STATUS_CHARGING once.
-     *   (3)  Push a burst of GpsScanStateChanged atoms with ON, with a different uid each time.
-     *   (4)  Push ChargingStateChanged with BATTERY_STATUS_NOT_CHARGING once.
-     *   (5)  Push a burst GpsScanStateChanged atoms with OFF, with a different uid each time.
-     *   (6)  Push ScreenStateChanged with STATE_ON once.
-     *   (7)  Push a burst of AudioStateChanged with ON, with a different uid each time.
-     *   (8)  Repeat steps (0)-(5).
-     *   (9)  Push ScreenStateChanged with STATE_OFF once.
-     *   (10) Push a burst of AudioStateChanged with OFF, with a different uid each time.
-     * and repeat.
-     */
-    public void next() {
-        Log.d(TAG, "Next step: " + mCursor);
-        if (mPlacebo) {
-            return;
-        }
-        switch (mCursor) {
-            case 0:
-            case 8:
-                for (int i = 0; i < mBurst; i++) {
-                    StatsLog.write(StatsLog.BATTERY_LEVEL_CHANGED, 50 + i /* battery_level */);
-                }
-                break;
-            case 1:
-            case 9:
-                for (int i = 0; i < mBurst; i++) {
-                    StatsLog.write(StatsLog.BLE_SCAN_RESULT_RECEIVED, i /* uid */,
-                        100 /* num_of_results */);
-                }
-                break;
-            case 2:
-            case 10:
-                StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
-                    StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_CHARGING
-                    /* charging_state */);
-                break;
-            case 3:
-            case 11:
-                for (int i = 0; i < mBurst; i++) {
-                    StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
-                        StatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON /* state */);
-                }
-                break;
-            case 4:
-            case 12:
-                StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
-                    StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
-                    /* charging_state */);
-                break;
-            case 5:
-            case 13:
-                for (int i = 0; i < mBurst; i++) {
-                    StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
-                        StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
-                }
-                break;
-            case 6:
-                StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
-                    StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON /* display_state */);
-                break;
-            case 7:
-                for (int i = 0; i < mBurst; i++) {
-                    StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
-                        StatsLog.AUDIO_STATE_CHANGED__STATE__ON /* state */);
-                }
-                break;
-            case 14:
-                StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
-                    StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
-                break;
-            case 15:
-                for (int i = 0; i < mBurst; i++) {
-                    StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
-                        StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
-                }
-                break;
-            default:
-        }
-        mCursor++;
-        if (mCursor > 15) {
-            mCursor = 0;
-        }
-    }
-
-    /**
-     * Properly finishes in order to be close all conditions and durations.
-     */
-    public void finish() {
-        // Screen goes back to off. This will ensure that conditions get back to false.
-        StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
-            StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
-        for (int i = 0; i < mBurst; i++) {
-          StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
-              StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
-        }
-        // Stop charging, to ensure the corresponding durations are closed.
-        StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
-            StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
-            /* charging_state */);
-        // Stop scanning GPS, to ensure the corresponding conditions get back to false.
-        for (int i = 0; i < mBurst; i++) {
-          StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, i /* uid */,
-              StatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF /* state */);
-        }
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java
deleted file mode 100644
index 3939e7e..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/StatsdStatsRecorder.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.content.Context;
-import com.android.os.StatsLog.StatsdStatsReport;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-
-public class StatsdStatsRecorder extends PerfDataRecorder {
-    private static final String TAG = "loadtest.StatsdStatsRecorder";
-
-    private final LoadtestActivity mLoadtestActivity;
-
-    public StatsdStatsRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
-        TimeUnit bucket, long periodSecs, int burst, boolean includeCountMetric,
-        boolean includeDurationMetric, boolean includeEventMetric,  boolean includeValueMetric,
-        boolean includeGaugeMetric) {
-      super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
-          includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
-        mLoadtestActivity = loadtestActivity;
-    }
-
-    @Override
-    public void startRecording(Context context) {
-        // Nothing to do.
-    }
-
-    @Override
-    public void onAlarm(Context context) {
-        // Nothing to do.
-    }
-
-    @Override
-    public void stopRecording(Context context) {
-        StatsdStatsReport metadata = mLoadtestActivity.getMetadata();
-        if (metadata != null) {
-            int numConfigs = metadata.getConfigStatsCount();
-            StringBuilder sb = new StringBuilder();
-            StatsdStatsReport.ConfigStats configStats = metadata.getConfigStats(numConfigs - 1);
-            sb.append("metric_count,")
-                .append(configStats.getMetricCount() + "\n")
-                .append("condition_count,")
-                .append(configStats.getConditionCount() + "\n")
-                .append("matcher_count,")
-                .append(configStats.getMatcherCount() + "\n");
-            writeData(context, "statsdstats_", "stat,value", sb);
-        }
-    }
-}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
deleted file mode 100644
index d9f0ca9..0000000
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ValidationRecorder.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.loadtest;
-
-import android.content.Context;
-import android.util.Log;
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.EventMetricData;
-import com.android.os.StatsLog.StatsLogReport;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Checks the correctness of the stats.
- */
-public class ValidationRecorder extends PerfDataRecorder {
-    private static final String TAG = "loadtest.ValidationRecorder";
-
-    private final LoadtestActivity mLoadtestActivity;
-
-    public ValidationRecorder(LoadtestActivity loadtestActivity, boolean placebo, int replication,
-        TimeUnit bucket, long periodSecs, int burst,  boolean includeCountMetric,
-        boolean includeDurationMetric, boolean includeEventMetric,  boolean includeValueMetric,
-        boolean includeGaugeMetric) {
-      super(placebo, replication, bucket, periodSecs, burst, includeCountMetric,
-          includeDurationMetric, includeEventMetric, includeValueMetric, includeGaugeMetric);
-        mLoadtestActivity = loadtestActivity;
-    }
-
-    @Override
-    public void startRecording(Context context) {
-        // Nothing to do.
-    }
-
-    @Override
-    public void onAlarm(Context context) {
-        validateData();
-    }
-
-    @Override
-    public void stopRecording(Context context) {
-        validateData();
-    }
-
-    private void validateData() {
-        // The code below is commented out because it calls getData, which has the side-effect
-        // of clearing statsd's data buffer.
-        /*
-        List<ConfigMetricsReport> reports = mLoadtestActivity.getData();
-        if (reports != null) {
-            Log.d(TAG, "GOT DATA");
-            for (ConfigMetricsReport report : reports) {
-                for (StatsLogReport logReport : report.getMetricsList()) {
-                    if (!logReport.hasMetricId()) {
-                        Log.e(TAG, "Metric missing name.");
-                    }
-                }
-            }
-        }
-        */
-    }
-
-    private void validateEventBatteryLevelChanges(StatsLogReport logReport) {
-        Log.d(TAG, "Validating " + logReport.getMetricId());
-        if (logReport.hasEventMetrics()) {
-            Log.d(TAG, "Num events captured: " + logReport.getEventMetrics().getDataCount());
-            for (EventMetricData data : logReport.getEventMetrics().getDataList()) {
-                Log.d(TAG, "  Event : " + data.getAtom());
-            }
-        } else {
-            Log.d(TAG, "Metric is invalid");
-        }
-    }
-
-    private void validateEventBatteryLevelChangesWhileScreenIsOn(StatsLogReport logReport) {
-        Log.d(TAG, "Validating " + logReport.getMetricId());
-    }
-}
diff --git a/config/boot-profile.txt b/config/boot-profile.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/config/boot-profile.txt
diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-greylist-max-p.txt
index 141e8e6..25d45b0 100644
--- a/config/hiddenapi-greylist-max-p.txt
+++ b/config/hiddenapi-greylist-max-p.txt
@@ -70,6 +70,8 @@
 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
diff --git a/config/preloaded-classes b/config/preloaded-classes
index b4fd031..03e3b82 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2696,6 +2696,7 @@
 android.os.-$$Lambda$Trace$2zLZ-Lc2kAXsVjw_nLYeNhqmGq0
 android.os.-$$Lambda$q1UvBdLgHRZVzc68BxdksTmbuCw
 android.os.AsyncResult
+android.os.AsyncTask
 android.os.AsyncTask$1
 android.os.AsyncTask$2
 android.os.AsyncTask$3
diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-blacklist
index b5f9950..f05edee 100644
--- a/config/preloaded-classes-blacklist
+++ b/config/preloaded-classes-blacklist
@@ -1,6 +1,5 @@
 android.content.AsyncTaskLoader$LoadTask
 android.net.ConnectivityThread$Singleton
-android.os.AsyncTask
 android.os.FileObserver
 android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask
 android.widget.Magnifier
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 4a02644..667f2bf 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -671,6 +671,32 @@
         }
     }
 
+    @Override
+    public Context createDisplayContext(Display display) {
+        final Context context = super.createDisplayContext(display);
+        final int displayId = display.getDisplayId();
+        setDefaultTokenInternal(context, displayId);
+        return context;
+    }
+
+    private void setDefaultTokenInternal(Context context, int displayId) {
+        final WindowManagerImpl wm = (WindowManagerImpl) context.getSystemService(WINDOW_SERVICE);
+        final IAccessibilityServiceConnection connection =
+                AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+        IBinder token = null;
+        if (connection != null) {
+            synchronized (mLock) {
+                try {
+                    token = connection.getOverlayWindowToken(displayId);
+                } catch (RemoteException re) {
+                    Log.w(LOG_TAG, "Failed to get window token", re);
+                    re.rethrowFromSystemServer();
+                }
+            }
+            wm.setDefaultToken(token);
+        }
+    }
+
     /**
      * Returns the magnification controller, which may be used to query and
      * modify the state of display magnification.
@@ -778,8 +804,8 @@
                             callback, handler);
                     mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
                 }
-                connection.sendGesture(mGestureStatusCallbackSequence,
-                        new ParceledListSlice<>(steps));
+                connection.dispatchGesture(mGestureStatusCallbackSequence,
+                        new ParceledListSlice<>(steps), gesture.getDisplayId());
             }
         } catch (RemoteException re) {
             throw new RuntimeException(re);
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index a3e7ad5..3b79d21 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -23,6 +23,7 @@
 import android.graphics.RectF;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.Display;
 
 import com.android.internal.util.Preconditions;
 
@@ -33,7 +34,7 @@
  * Accessibility services with the
  * {@link android.R.styleable#AccessibilityService_canPerformGestures} property can dispatch
  * gestures. This class describes those gestures. Gestures are made up of one or more strokes.
- * Gestures are immutable once built.
+ * Gestures are immutable once built and will be dispatched to the specified display.
  * <p>
  * Spatial dimensions throughout are in screen pixels. Time is measured in milliseconds.
  */
@@ -48,6 +49,7 @@
 
     private final List<StrokeDescription> mStrokes = new ArrayList<>();
     private final float[] mTempPos = new float[2];
+    private final int mDisplayId;
 
     /**
      * Get the upper limit for the number of strokes a gesture may contain.
@@ -67,10 +69,17 @@
         return MAX_GESTURE_DURATION_MS;
     }
 
-    private GestureDescription() {}
+    private GestureDescription() {
+       this(new ArrayList<>());
+    }
 
     private GestureDescription(List<StrokeDescription> strokes) {
+        this(strokes, Display.DEFAULT_DISPLAY);
+    }
+
+    private GestureDescription(List<StrokeDescription> strokes, int displayId) {
         mStrokes.addAll(strokes);
+        mDisplayId = displayId;
     }
 
     /**
@@ -94,6 +103,16 @@
     }
 
     /**
+     * Returns the ID of the display this gesture is sent on, for use with
+     * {@link android.hardware.display.DisplayManager#getDisplay(int)}.
+     *
+     * @return The logical display id.
+     */
+    public int getDisplayId() {
+        return mDisplayId;
+    }
+
+    /**
      * Return the smallest key point (where a path starts or ends) that is at least a specified
      * offset
      * @param offset the minimum start time
@@ -160,9 +179,10 @@
     public static class Builder {
 
         private final List<StrokeDescription> mStrokes = new ArrayList<>();
+        private int mDisplayId = Display.DEFAULT_DISPLAY;
 
         /**
-         * Add a stroke to the gesture description. Up to
+         * Adds a stroke to the gesture description. Up to
          * {@link GestureDescription#getMaxStrokeCount()} paths may be
          * added to a gesture, and the total gesture duration (earliest path start time to latest
          * path end time) may not exceed {@link GestureDescription#getMaxGestureDuration()}.
@@ -187,11 +207,23 @@
             return this;
         }
 
+        /**
+         * Sets the id of the display to dispatch gestures.
+         *
+         * @param displayId The logical display id
+         *
+         * @return this
+         */
+        public @NonNull Builder setDisplayId(int displayId) {
+            mDisplayId = displayId;
+            return this;
+        }
+
         public GestureDescription build() {
             if (mStrokes.size() == 0) {
                 throw new IllegalStateException("Gestures must have at least one stroke");
             }
-            return new GestureDescription(mStrokes);
+            return new GestureDescription(mStrokes, mDisplayId);
         }
     }
 
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 8c38fe4..1ca07dd 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -95,5 +95,9 @@
 
     void sendGesture(int sequence, in ParceledListSlice gestureSteps);
 
+    void dispatchGesture(int sequence, in ParceledListSlice gestureSteps, int displayId);
+
     boolean isFingerprintGestureDetectionAvailable();
+
+    IBinder getOverlayWindowToken(int displayid);
 }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 17368b7..cb99a3a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -925,7 +925,7 @@
      * (which tends to consume a lot more RAM).
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
     static public boolean isHighEndGfx() {
         return !isLowRamDeviceStatic()
                 && !RoSystemProperties.CONFIG_AVOID_GFX_ACCEL
@@ -1822,7 +1822,8 @@
      * @hide
      */
     public static class TaskSnapshot implements Parcelable {
-
+        // Identifier of this snapshot
+        private final long mId;
         // Top activity in task when snapshot was taken
         private final ComponentName mTopActivityComponent;
         private final GraphicBuffer mSnapshot;
@@ -1841,10 +1842,12 @@
         // Must be one of the named color spaces, otherwise, always use SRGB color space.
         private final ColorSpace mColorSpace;
 
-        public TaskSnapshot(@NonNull ComponentName topActivityComponent, GraphicBuffer snapshot,
+        public TaskSnapshot(long id,
+                @NonNull ComponentName topActivityComponent, GraphicBuffer snapshot,
                 @NonNull ColorSpace colorSpace, int orientation, Rect contentInsets,
                 boolean reducedResolution, float scale, boolean isRealSnapshot, int windowingMode,
                 int systemUiVisibility, boolean isTranslucent) {
+            mId = id;
             mTopActivityComponent = topActivityComponent;
             mSnapshot = snapshot;
             mColorSpace = colorSpace.getId() < 0
@@ -1860,6 +1863,7 @@
         }
 
         private TaskSnapshot(Parcel source) {
+            mId = source.readLong();
             mTopActivityComponent = ComponentName.readFromParcel(source);
             mSnapshot = source.readParcelable(null /* classLoader */);
             int colorSpaceId = source.readInt();
@@ -1877,6 +1881,13 @@
         }
 
         /**
+         * @return Identifier of this snapshot.
+         */
+        public long getId() {
+            return mId;
+        }
+
+        /**
          * @return The top activity component for the task at the point this snapshot was taken.
          */
         public ComponentName getTopActivityComponent() {
@@ -1970,6 +1981,7 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
+            dest.writeLong(mId);
             ComponentName.writeToParcel(mTopActivityComponent, dest);
             dest.writeParcelable(mSnapshot, 0);
             dest.writeInt(mColorSpace.getId());
@@ -1988,6 +2000,7 @@
             final int width = mSnapshot != null ? mSnapshot.getWidth() : 0;
             final int height = mSnapshot != null ? mSnapshot.getHeight() : 0;
             return "TaskSnapshot{"
+                    + " mId=" + mId
                     + " mTopActivityComponent=" + mTopActivityComponent.flattenToShortString()
                     + " mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")"
                     + " mColorSpace=" + mColorSpace.toString()
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f8e6ae5..69e7118 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -26,6 +26,7 @@
 import android.content.pm.ActivityPresentationInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.UserInfo;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.TransactionTooLargeException;
@@ -52,6 +53,12 @@
      */
     public abstract String checkContentProviderAccess(String authority, int userId);
 
+    /**
+     * Verify that calling UID has access to the given provider.
+     */
+    public abstract int checkContentProviderUriPermission(Uri uri, int userId,
+            int callingUid, int modeFlags);
+
     // Called by the power manager.
     public abstract void onWakefulnessChanged(int wakefulness);
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d741b61..2b4d4f8b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -791,6 +791,8 @@
         @Nullable
         ContentCaptureOptions contentCaptureOptions;
 
+        long[] disabledCompatChanges;
+
         @Override
         public String toString() {
             return "AppBindData{appInfo=" + appInfo + "}";
@@ -1003,7 +1005,7 @@
                 boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                 CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                 String buildSerial, AutofillOptions autofillOptions,
-                ContentCaptureOptions contentCaptureOptions) {
+                ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
             if (services != null) {
                 if (false) {
                     // Test code to make sure the app could see the passed-in services.
@@ -1051,6 +1053,7 @@
             data.buildSerial = buildSerial;
             data.autofillOptions = autofillOptions;
             data.contentCaptureOptions = contentCaptureOptions;
+            data.disabledCompatChanges = disabledCompatChanges;
             sendMessage(H.BIND_APPLICATION, data);
         }
 
@@ -6144,10 +6147,10 @@
         if (data.trackAllocation) {
             DdmVmInternal.enableRecentAllocations(true);
         }
-
         // Note when this process has started.
         Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
 
+        AppCompatCallbacks.install(data.disabledCompatChanges);
         mBoundApplication = data;
         mConfiguration = new Configuration(data.config);
         mCompatConfiguration = new Configuration(data.config);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 755f047..415ec64 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -386,9 +386,15 @@
 
                 // Also report this geometry information to InputMethodManagerService.
                 // TODO(b/115693908): Unify this logic into the above WMS-based one.
+                // TODO(b/138175283): Address the location update when the host of this view is
+                //  moving.
                 final Matrix matrix = new Matrix();
+                final int[] locationOnScreen = new int[2];
+                getLocationOnScreen(locationOnScreen);
+                final int dx = locationOnScreen[0];
+                final int dy = locationOnScreen[1];
                 matrix.set(getMatrix());
-                matrix.postTranslate(x, y);
+                matrix.postTranslate(dx, dy);
                 mContext.getSystemService(InputMethodManager.class)
                         .reportActivityView(displayId, matrix);
             }
diff --git a/core/java/android/app/AppCompatCallbacks.java b/core/java/android/app/AppCompatCallbacks.java
new file mode 100644
index 0000000..17697db
--- /dev/null
+++ b/core/java/android/app/AppCompatCallbacks.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+import android.compat.Compatibility;
+import android.os.Process;
+import android.util.Log;
+
+import java.util.Arrays;
+
+/**
+ * App process implementation of the {@link Compatibility} API.
+ *
+ * @hide
+ */
+public final class AppCompatCallbacks extends Compatibility.Callbacks {
+
+    private static final String TAG = "Compatibility";
+
+    private final long[] mDisabledChanges;
+
+    /**
+     * Install this class into the current process.
+     *
+     * @param disabledChanges Set of compatibility changes that are disabled for this process.
+     */
+    public static void install(long[] disabledChanges) {
+        Compatibility.setCallbacks(new AppCompatCallbacks(disabledChanges));
+    }
+
+    private AppCompatCallbacks(long[] disabledChanges) {
+        mDisabledChanges = Arrays.copyOf(disabledChanges, disabledChanges.length);
+        Arrays.sort(mDisabledChanges);
+    }
+
+    protected void reportChange(long changeId) {
+        Log.d(TAG, "Compat change reported: " + changeId + "; UID " + Process.myUid());
+        // TODO log via StatsLog
+    }
+
+    protected boolean isChangeEnabled(long changeId) {
+        if (Arrays.binarySearch(mDisabledChanges, changeId) < 0) {
+            // Not present in the disabled array
+            reportChange(changeId);
+            return true;
+        }
+        return false;
+    }
+
+}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 1641afb..0478ac8 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -34,7 +34,6 @@
 import android.content.pm.ChangedPackages;
 import android.content.pm.ComponentInfo;
 import android.content.pm.FeatureInfo;
-import android.content.pm.IOnPermissionsChangeListener;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageManager;
@@ -82,6 +81,7 @@
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.permission.IOnPermissionsChangeListener;
 import android.permission.IPermissionManager;
 import android.provider.Settings;
 import android.system.ErrnoException;
@@ -626,7 +626,7 @@
     @Override
     public int checkPermission(String permName, String pkgName) {
         try {
-            return mPM.checkPermission(permName, pkgName, getUserId());
+            return mPermissionManager.checkPermission(permName, pkgName, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -635,7 +635,7 @@
     @Override
     public boolean isPermissionRevokedByPolicy(String permName, String pkgName) {
         try {
-            return mPM.isPermissionRevokedByPolicy(permName, pkgName, getUserId());
+            return mPermissionManager.isPermissionRevokedByPolicy(permName, pkgName, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -707,46 +707,47 @@
     }
 
     @Override
-    public void revokeRuntimePermission(String packageName, String permissionName,
-            UserHandle user) {
+    public void revokeRuntimePermission(String packageName, String permName, UserHandle user) {
         if (DEBUG_TRACE_GRANTS
-                && shouldTraceGrant(packageName, permissionName, user.getIdentifier())) {
+                && shouldTraceGrant(packageName, permName, user.getIdentifier())) {
             Log.i(TAG, "App " + mContext.getPackageName() + " is revoking "
-                    + permissionName + " for user " + user.getIdentifier(), new RuntimeException());
+                    + permName + " for user " + user.getIdentifier(), new RuntimeException());
         }
         try {
-            mPM.revokeRuntimePermission(packageName, permissionName, user.getIdentifier());
+            mPermissionManager
+                    .revokeRuntimePermission(packageName, permName, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
-    public int getPermissionFlags(String permissionName, String packageName, UserHandle user) {
+    public int getPermissionFlags(String permName, String packageName, UserHandle user) {
         try {
-            return mPM.getPermissionFlags(permissionName, packageName, user.getIdentifier());
+            return mPermissionManager
+                    .getPermissionFlags(permName, packageName, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
-    public void updatePermissionFlags(String permissionName, String packageName,
+    public void updatePermissionFlags(String permName, String packageName,
             int flagMask, int flagValues, UserHandle user) {
         if (DEBUG_TRACE_GRANTS
-                && shouldTraceGrant(packageName, permissionName, user.getIdentifier())) {
+                && shouldTraceGrant(packageName, permName, user.getIdentifier())) {
             Log.i(TAG, "App " + mContext.getPackageName() + " is updating flags for "
-                    + permissionName + " for user " + user.getIdentifier() + ": "
+                    + permName + " for user " + user.getIdentifier() + ": "
                     + DebugUtils.flagsToString(PackageManager.class, "FLAG_PERMISSION_", flagMask)
                     + " := " + DebugUtils.flagsToString(
                             PackageManager.class, "FLAG_PERMISSION_", flagValues),
                     new RuntimeException());
         }
         try {
-            mPM.updatePermissionFlags(permissionName, packageName, flagMask,
-                    flagValues,
-                    mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q,
-                    user.getIdentifier());
+            final boolean checkAdjustPolicyFlagPermission =
+                    mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q;
+            mPermissionManager.updatePermissionFlags(permName, packageName, flagMask,
+                    flagValues, checkAdjustPolicyFlagPermission, user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -754,10 +755,11 @@
 
     @Override
     public @NonNull Set<String> getWhitelistedRestrictedPermissions(
-            @NonNull String packageName, @PermissionWhitelistFlags int whitelistFlags) {
+            @NonNull String packageName, @PermissionWhitelistFlags int flags) {
         try {
-            final List<String> whitelist = mPM.getWhitelistedRestrictedPermissions(
-                    packageName, whitelistFlags, getUserId());
+            final int userId = getUserId();
+            final List<String> whitelist = mPermissionManager
+                    .getWhitelistedRestrictedPermissions(packageName, flags, userId);
             if (whitelist != null) {
                 return new ArraySet<>(whitelist);
             }
@@ -769,10 +771,11 @@
 
     @Override
     public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
-            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
+            @NonNull String permName, @PermissionWhitelistFlags int flags) {
         try {
-            return mPM.addWhitelistedRestrictedPermission(packageName, permission,
-                    whitelistFlags, getUserId());
+            final int userId = getUserId();
+            return mPermissionManager
+                    .addWhitelistedRestrictedPermission(packageName, permName, flags, userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -780,10 +783,11 @@
 
     @Override
     public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
-            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
+            @NonNull String permName, @PermissionWhitelistFlags int flags) {
         try {
-            return mPM.removeWhitelistedRestrictedPermission(packageName, permission,
-                    whitelistFlags, getUserId());
+            final int userId = getUserId();
+            return mPermissionManager
+                    .removeWhitelistedRestrictedPermission(packageName, permName, flags, userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -791,10 +795,11 @@
 
     @Override
     @UnsupportedAppUsage
-    public boolean shouldShowRequestPermissionRationale(String permission) {
+    public boolean shouldShowRequestPermissionRationale(String permName) {
         try {
-            return mPM.shouldShowRequestPermissionRationale(permission,
-                    mContext.getPackageName(), getUserId());
+            final String packageName = mContext.getPackageName();
+            return mPermissionManager
+                    .shouldShowRequestPermissionRationale(permName, packageName, getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1623,7 +1628,7 @@
             OnPermissionsChangeListenerDelegate delegate =
                     new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper());
             try {
-                mPM.addOnPermissionsChangeListener(delegate);
+                mPermissionManager.addOnPermissionsChangeListener(delegate);
                 mPermissionListeners.put(listener, delegate);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
@@ -1637,7 +1642,7 @@
             IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener);
             if (delegate != null) {
                 try {
-                    mPM.removeOnPermissionsChangeListener(delegate);
+                    mPermissionManager.removeOnPermissionsChangeListener(delegate);
                     mPermissionListeners.remove(listener);
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
@@ -2045,7 +2050,7 @@
     @Override
     public String getDefaultBrowserPackageNameAsUser(int userId) {
         try {
-            return mPM.getDefaultBrowserPackageName(userId);
+            return mPermissionManager.getDefaultBrowser(userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2054,7 +2059,7 @@
     @Override
     public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
         try {
-            return mPM.setDefaultBrowserPackageName(packageName, userId);
+            return mPermissionManager.setDefaultBrowser(packageName, userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 2957309..47b784b 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -153,6 +153,7 @@
     void moveTaskToFront(in IApplicationThread app, in String callingPackage, int task,
             int flags, in Bundle options);
     int getTaskForActivity(in IBinder token, in boolean onlyRoot);
+    /** Finish all activities that were started for result from the specified activity. */
     void finishSubActivity(in IBinder token, in String resultWho, int requestCode);
     ParceledListSlice getRecentTasks(int maxNum, int flags, int userId);
     boolean willActivityBeVisible(in IBinder token);
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 66c4383..cfa065b 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -73,7 +73,7 @@
             boolean restrictedBackupMode, boolean persistent, in Configuration config,
             in CompatibilityInfo compatInfo, in Map services,
             in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions,
-            in ContentCaptureOptions contentCaptureOptions);
+            in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges);
     void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs);
     void scheduleExit();
     void scheduleServiceArgs(IBinder token, in ParceledListSlice args);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ccea964..372eab2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5437,10 +5437,11 @@
         /**
          * Construct a RemoteViews for the display in public contexts like on the lockscreen.
          *
+         * @param isLowPriority is this notification low priority
          * @hide
          */
         @UnsupportedAppUsage
-        public RemoteViews makePublicContentView() {
+        public RemoteViews makePublicContentView(boolean isLowPriority) {
             if (mN.publicVersion != null) {
                 final Builder builder = recoverBuilder(mContext, mN.publicVersion);
                 return builder.createContentView();
@@ -5467,7 +5468,11 @@
             }
             mN.extras = publicExtras;
             RemoteViews view;
-            view = makeNotificationHeader();
+            StandardTemplateParams params = mParams.reset().fillTextsFrom(this);
+            if (isLowPriority) {
+                params.forceDefaultColor();
+            }
+            view = makeNotificationHeader(params);
             view.setBoolean(R.id.notification_header, "setExpandOnlyOnButton", true);
             mN.extras = savedBundle;
             mN.mLargeIcon = largeIcon;
@@ -8101,8 +8106,7 @@
          */
         @Override
         public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
-            RemoteViews expanded = makeMediaBigContentView();
-            return expanded != null ? expanded : makeMediaContentView();
+            return makeMediaContentView();
         }
 
         /** @hide */
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c1cee77..316cab8 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -171,6 +171,78 @@
             "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
 
     /**
+     * Intent that is broadcast when the status of an {@link AutomaticZenRule} has changed.
+     *
+     * <p>Use this to know whether you need to continue monitor to device state in order to
+     * provide up-to-date states (with {@link #setAutomaticZenRuleState(String, Condition)}) for
+     * this rule.</p>
+     *
+     * Input: nothing
+     * Output: {@link #EXTRA_AUTOMATIC_ZEN_RULE_ID}
+     * Output: {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS}
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED =
+            "android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED";
+
+    /**
+     * Integer extra for {@link #ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED} containing the state of
+     * the {@link AutomaticZenRule}.
+     *
+     * <p>
+     *     The value will be one of {@link #AUTOMATIC_RULE_STATUS_ENABLED},
+     *     {@link #AUTOMATIC_RULE_STATUS_DISABLED}, {@link #AUTOMATIC_RULE_STATUS_REMOVED},
+     *     {@link #AUTOMATIC_RULE_STATUS_UNKNOWN}.
+     * </p>
+     */
+    public static final String EXTRA_AUTOMATIC_ZEN_RULE_STATUS =
+            "android.app.extra.AUTOMATIC_ZEN_RULE_STATUS";
+
+    /**
+     * String extra for {@link #ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED} containing the id of the
+     * {@link AutomaticZenRule} (see {@link #addAutomaticZenRule(AutomaticZenRule)}) that has
+     * changed.
+     */
+    public static final String EXTRA_AUTOMATIC_ZEN_RULE_ID =
+            "android.app.extra.AUTOMATIC_ZEN_RULE_ID";
+
+    /** @hide */
+    @IntDef(prefix = { "AUTOMATIC_RULE_STATUS" }, value = {
+            AUTOMATIC_RULE_STATUS_ENABLED, AUTOMATIC_RULE_STATUS_DISABLED,
+            AUTOMATIC_RULE_STATUS_REMOVED, AUTOMATIC_RULE_STATUS_UNKNOWN
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AutomaticZenRuleStatus {}
+
+    /**
+     * Constant value for {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS} - the current status of the
+     * rule is unknown at your target sdk version, and you should continue to provide state changes
+     * via {@link #setAutomaticZenRuleState(String, Condition)}.
+     */
+    public static final int AUTOMATIC_RULE_STATUS_UNKNOWN = -1;
+
+    /**
+     * Constant value for {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS} - the given rule currently
+     * exists and is enabled. You should continue to provide state changes via
+     * {@link #setAutomaticZenRuleState(String, Condition)}.
+     */
+    public static final int AUTOMATIC_RULE_STATUS_ENABLED = 1;
+
+    /**
+     * Constant value for {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS} - the given rule currently
+     * exists but is disabled. You do not need to continue to provide state changes via
+     * {@link #setAutomaticZenRuleState(String, Condition)} until the rule is reenabled.
+     */
+    public static final int AUTOMATIC_RULE_STATUS_DISABLED = 2;
+
+    /**
+     * Constant value for {@link #EXTRA_AUTOMATIC_ZEN_RULE_STATUS} - the given rule has been
+     * deleted. Further calls to {@link #setAutomaticZenRuleState(String, Condition)} will be
+     * ignored.
+     */
+    public static final int AUTOMATIC_RULE_STATUS_REMOVED = 3;
+
+    /**
      * Intent that is broadcast when the state of {@link #getEffectsSuppressor()} changes.
      * This broadcast is only sent to registered receivers.
      *
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 0f8976f..9162626 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.SharedPreferences;
@@ -25,6 +26,7 @@
 import android.system.Os;
 import android.system.StructStat;
 import android.system.StructTimespec;
+import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -92,6 +94,10 @@
     private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
             new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
 
+    @GuardedBy("mLock")
+    private final WeakHashMap<OnSharedPreferencesClearListener, Object> mClearListeners =
+            new WeakHashMap<>();
+
     /** Current memory state (always increasing) */
     @GuardedBy("this")
     private long mCurrentMemoryStateGeneration;
@@ -252,6 +258,28 @@
         }
     }
 
+    @Override
+    public void registerOnSharedPreferencesClearListener(
+            @NonNull OnSharedPreferencesClearListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener cannot be null.");
+        }
+        synchronized (mLock) {
+            mClearListeners.put(listener, CONTENT);
+        }
+    }
+
+    @Override
+    public void unregisterOnSharedPreferencesClearListener(
+            @NonNull OnSharedPreferencesClearListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener cannot be null.");
+        }
+        synchronized (mLock) {
+            mClearListeners.remove(listener);
+        }
+    }
+
     @GuardedBy("mLock")
     private void awaitLoadedLocked() {
         if (!mLoaded) {
@@ -361,7 +389,9 @@
     private static class MemoryCommitResult {
         final long memoryStateGeneration;
         @Nullable final List<String> keysModified;
+        @Nullable final Set<String> keysCleared;
         @Nullable final Set<OnSharedPreferenceChangeListener> listeners;
+        @Nullable final Set<OnSharedPreferencesClearListener> clearListeners;
         final Map<String, Object> mapToWriteToDisk;
         final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
 
@@ -371,10 +401,14 @@
 
         private MemoryCommitResult(long memoryStateGeneration, @Nullable List<String> keysModified,
                 @Nullable Set<OnSharedPreferenceChangeListener> listeners,
+                @Nullable Set<String> keysCleared,
+                @Nullable Set<OnSharedPreferencesClearListener> clearListeners,
                 Map<String, Object> mapToWriteToDisk) {
             this.memoryStateGeneration = memoryStateGeneration;
             this.keysModified = keysModified;
             this.listeners = listeners;
+            this.keysCleared = keysCleared;
+            this.clearListeners = clearListeners;
             this.mapToWriteToDisk = mapToWriteToDisk;
         }
 
@@ -492,13 +526,16 @@
             // SharedPreferences instance back, which has the
             // changes reflected in memory.
             notifyListeners(mcr);
+            notifyClearListeners(mcr);
         }
 
         // Returns true if any changes were made
         private MemoryCommitResult commitToMemory() {
             long memoryStateGeneration;
             List<String> keysModified = null;
+            Set<String> keysCleared = null;
             Set<OnSharedPreferenceChangeListener> listeners = null;
+            Set<OnSharedPreferencesClearListener> clearListeners = null;
             Map<String, Object> mapToWriteToDisk;
 
             synchronized (SharedPreferencesImpl.this.mLock) {
@@ -520,12 +557,20 @@
                     keysModified = new ArrayList<String>();
                     listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
                 }
+                boolean hasClearListeners = !mClearListeners.isEmpty();
+                if (hasClearListeners) {
+                    keysCleared = new ArraySet<>();
+                    clearListeners = new HashSet<>(mClearListeners.keySet());
+                }
 
                 synchronized (mEditorLock) {
                     boolean changesMade = false;
 
                     if (mClear) {
                         if (!mapToWriteToDisk.isEmpty()) {
+                            if (hasClearListeners) {
+                                keysCleared.addAll(mapToWriteToDisk.keySet());
+                            }
                             changesMade = true;
                             mapToWriteToDisk.clear();
                         }
@@ -569,7 +614,7 @@
                 }
             }
             return new MemoryCommitResult(memoryStateGeneration, keysModified, listeners,
-                    mapToWriteToDisk);
+                    keysCleared, clearListeners, mapToWriteToDisk);
         }
 
         @Override
@@ -596,6 +641,7 @@
                 }
             }
             notifyListeners(mcr);
+            notifyClearListeners(mcr);
             return mcr.writeToDiskResult;
         }
 
@@ -618,6 +664,24 @@
                 ActivityThread.sMainThreadHandler.post(() -> notifyListeners(mcr));
             }
         }
+
+        private void notifyClearListeners(final MemoryCommitResult mcr) {
+            if (mcr.clearListeners == null || mcr.keysCleared == null
+                    || mcr.keysCleared.isEmpty()) {
+                return;
+            }
+            if (Looper.myLooper() == Looper.getMainLooper()) {
+                for (OnSharedPreferencesClearListener listener : mcr.clearListeners) {
+                    if (listener != null) {
+                        listener.onSharedPreferencesClear(SharedPreferencesImpl.this,
+                                mcr.keysCleared);
+                    }
+                }
+            } else {
+                // Run this function on the main thread.
+                ActivityThread.sMainThreadHandler.post(() -> notifyClearListeners(mcr));
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d32b6b5..cfe2cf0 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -172,7 +172,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccCardManager;
 import android.telephony.euicc.EuiccManager;
-import android.telephony.ims.RcsManager;
+import android.telephony.ims.RcsMessageManager;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
@@ -614,11 +614,11 @@
                 return new SubscriptionManager(ctx.getOuterContext());
             }});
 
-        registerService(Context.TELEPHONY_RCS_SERVICE, RcsManager.class,
-                new CachedServiceFetcher<RcsManager>() {
+        registerService(Context.TELEPHONY_RCS_MESSAGE_SERVICE, RcsMessageManager.class,
+                new CachedServiceFetcher<RcsMessageManager>() {
                     @Override
-                    public RcsManager createService(ContextImpl ctx) {
-                        return new RcsManager(ctx.getOuterContext());
+                    public RcsMessageManager createService(ContextImpl ctx) {
+                        return new RcsMessageManager(ctx.getOuterContext());
                     }
                 });
 
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index dc07df8..4f8b60b 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -20,7 +20,6 @@
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.pm.IPackageManager;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.hardware.input.InputManager;
@@ -31,6 +30,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.permission.IPermissionManager;
 import android.util.Log;
 import android.view.IWindowManager;
 import android.view.InputEvent;
@@ -69,8 +69,8 @@
     private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub
             .asInterface(ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
 
-    private final IPackageManager mPackageManager = IPackageManager.Stub
-            .asInterface(ServiceManager.getService("package"));
+    private final IPermissionManager mPermissionManager = IPermissionManager.Stub
+            .asInterface(ServiceManager.getService("permissionmgr"));
 
     private final IActivityManager mActivityManager = IActivityManager.Stub
             .asInterface(ServiceManager.getService("activity"));
@@ -273,7 +273,7 @@
         }
         final long identity = Binder.clearCallingIdentity();
         try {
-            mPackageManager.grantRuntimePermission(packageName, permission, userId);
+            mPermissionManager.grantRuntimePermission(packageName, permission, userId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -289,7 +289,7 @@
         }
         final long identity = Binder.clearCallingIdentity();
         try {
-            mPackageManager.revokeRuntimePermission(packageName, permission, userId);
+            mPermissionManager.revokeRuntimePermission(packageName, permission, userId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 05833b5..5d00f09 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -126,6 +126,17 @@
             "android.bluetooth.headsetclient.profile.action.RESULT";
 
     /**
+     * Intent that notifies about vendor specific event arrival. Events not defined in
+     * HFP spec will be matched with supported vendor event list and this intent will
+     * be broadcasted upon a match. Supported vendor events are of format of
+     * of "+eventCode" or "+eventCode=xxxx" or "+eventCode:=xxxx".
+     * Vendor event can be a response to an vendor specific command or unsolicited.
+     *
+     */
+    public static final String ACTION_VENDOR_SPECIFIC_HEADSETCLIENT_EVENT =
+            "android.bluetooth.headsetclient.profile.action.VENDOR_SPECIFIC_EVENT";
+
+    /**
      * Intent that notifies about the number attached to the last voice tag
      * recorded on AG.
      *
@@ -243,6 +254,28 @@
     public static final String EXTRA_CME_CODE =
             "android.bluetooth.headsetclient.extra.CME_CODE";
 
+    /**
+     * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
+     * indicates vendor ID.
+     */
+    public static final String EXTRA_VENDOR_ID =
+            "android.bluetooth.headsetclient.extra.VENDOR_ID";
+
+     /**
+     * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
+     * indicates vendor event code.
+     */
+    public static final String EXTRA_VENDOR_EVENT_CODE =
+            "android.bluetooth.headsetclient.extra.VENDOR_EVENT_CODE";
+
+     /**
+     * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
+     * contains full vendor event including event code and full arguments.
+     */
+    public static final String EXTRA_VENDOR_EVENT_FULL_ARGS =
+            "android.bluetooth.headsetclient.extra.VENDOR_EVENT_FULL_ARGS";
+
+
     /* Extras for AG_FEATURES, extras type is boolean */
     // TODO verify if all of those are actually useful
     /**
@@ -588,6 +621,31 @@
     }
 
     /**
+     * Send vendor specific AT command.
+     *
+     * @param device remote device
+     * @param vendorId vendor number by Bluetooth SIG
+     * @param atCommand command to be sent. It start with + prefix and only one command at one time.
+     * @return <code>true</code> if command has been issued successfully; <code>false</code>
+     * otherwise.
+     */
+    public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId,
+                                             String atCommand) {
+        if (DBG) log("sendVendorSpecificCommand()");
+        final IBluetoothHeadsetClient service =
+                getService();
+        if (service != null && isEnabled() && isValidDevice(device)) {
+            try {
+                return service.sendVendorAtCommand(device, vendorId, atCommand);
+            } catch (RemoteException e) {
+                Log.e(TAG, Log.getStackTraceString(new Throwable()));
+            }
+        }
+        if (service == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
      * Stops voice recognition.
      *
      * @param device remote device
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 88e2c22..fdef2a1 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -892,12 +892,6 @@
         mItems.add(item);
     }
 
-    /** @removed use #addItem(ContentResolver, Item) instead */
-    @Deprecated
-    public void addItem(Item item, ContentResolver resolver) {
-        addItem(resolver, item);
-    }
-
     /**
      * Add a new Item to the overall ClipData container.
      * <p> Unlike {@link #addItem(Item)}, this method will update the list of available MIME types
diff --git a/core/java/android/content/ContentInterface.java b/core/java/android/content/ContentInterface.java
index d41d8d9..197de97 100644
--- a/core/java/android/content/ContentInterface.java
+++ b/core/java/android/content/ContentInterface.java
@@ -56,6 +56,9 @@
     public boolean refresh(@NonNull Uri uri, @Nullable Bundle args,
             @Nullable CancellationSignal cancellationSignal) throws RemoteException;
 
+    public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags)
+            throws RemoteException;
+
     public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues initialValues)
             throws RemoteException;
 
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 7cdd268..3c79991 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -28,6 +28,7 @@
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.app.AppOpsManager;
+import android.content.pm.PackageManager;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
 import android.content.res.AssetFileDescriptor;
@@ -582,6 +583,22 @@
             }
         }
 
+        @Override
+        public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags) {
+            uri = validateIncomingUri(uri);
+            uri = maybeGetUriWithoutUserId(uri);
+            Trace.traceBegin(TRACE_TAG_DATABASE, "checkUriPermission");
+            final String original = setCallingPackage(callingPkg);
+            try {
+                return mInterface.checkUriPermission(uri, uid, modeFlags);
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            } finally {
+                setCallingPackage(original);
+                Trace.traceEnd(TRACE_TAG_DATABASE);
+            }
+        }
+
         private void enforceFilePermission(String callingPkg, Uri uri, String mode,
                 IBinder callerToken) throws FileNotFoundException, SecurityException {
             if (mode != null && mode.indexOf('w') != -1) {
@@ -1416,6 +1433,12 @@
         return false;
     }
 
+    /** {@hide} */
+    @Override
+    public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) {
+        return PackageManager.PERMISSION_DENIED;
+    }
+
     /**
      * @hide
      * Implementation when a caller has performed an insert on the content
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 93bf518..8a4330e 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -307,6 +307,25 @@
         }
     }
 
+    /** {@hide} */
+    @Override
+    public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags)
+            throws RemoteException {
+        Preconditions.checkNotNull(uri, "uri");
+
+        beforeRemote();
+        try {
+            return mContentProvider.checkUriPermission(mPackageName, uri, uid, modeFlags);
+        } catch (DeadObjectException e) {
+            if (!mStable) {
+                mContentResolver.unstableProviderDied(mContentProvider);
+            }
+            throw e;
+        } finally {
+            afterRemote();
+        }
+    }
+
     /** See {@link ContentProvider#insert ContentProvider.insert} */
     @Override
     public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues)
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 9948338..cd735d4 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -363,6 +363,19 @@
                     reply.writeInt(out ? 0 : -1);
                     return true;
                 }
+
+                case CHECK_URI_PERMISSION_TRANSACTION: {
+                    data.enforceInterface(IContentProvider.descriptor);
+                    String callingPkg = data.readString();
+                    Uri uri = Uri.CREATOR.createFromParcel(data);
+                    int uid = data.readInt();
+                    int modeFlags = data.readInt();
+
+                    int out = checkUriPermission(callingPkg, uri, uid, modeFlags);
+                    reply.writeNoException();
+                    reply.writeInt(out);
+                    return true;
+                }
             }
         } catch (Exception e) {
             DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -800,6 +813,29 @@
         }
     }
 
+    @Override
+    public int checkUriPermission(String callingPkg, Uri url, int uid, int modeFlags)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        try {
+            data.writeInterfaceToken(IContentProvider.descriptor);
+
+            data.writeString(callingPkg);
+            url.writeToParcel(data, 0);
+            data.writeInt(uid);
+            data.writeInt(modeFlags);
+
+            mRemote.transact(IContentProvider.CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0);
+
+            DatabaseUtils.readExceptionFromParcel(reply);
+            return reply.readInt();
+        } finally {
+            data.recycle();
+            reply.recycle();
+        }
+    }
+
     @UnsupportedAppUsage
     private IBinder mRemote;
 }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0a1bc85..9c86359 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -31,6 +31,7 @@
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.UriGrantsManager;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
@@ -1146,6 +1147,24 @@
         }
     }
 
+    /** {@hide} */
+    @Override
+    public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) {
+        Preconditions.checkNotNull(uri, "uri");
+
+        try {
+            if (mWrapped != null) return mWrapped.checkUriPermission(uri, uid, modeFlags);
+        } catch (RemoteException e) {
+            return PackageManager.PERMISSION_DENIED;
+        }
+
+        try (ContentProviderClient client = acquireUnstableContentProviderClient(uri)) {
+            return client.checkUriPermission(uri, uid, modeFlags);
+        } catch (RemoteException e) {
+            return PackageManager.PERMISSION_DENIED;
+        }
+    }
+
     /**
      * Open a stream on to the content associated with a content URI.  If there
      * is no data associated with the URI, FileNotFoundException is thrown.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 341fc26..7a013f1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4665,10 +4665,10 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve an
-     * {@link android.telephony.ims.RcsManager}.
+     * {@link android.telephony.ims.RcsMessageManager}.
      * @hide
      */
-    public static final String TELEPHONY_RCS_SERVICE = "ircs";
+    public static final String TELEPHONY_RCS_MESSAGE_SERVICE = "ircsmessage";
 
      /**
      * Use with {@link #getSystemService(String)} to retrieve an
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 0427c2f..fade0ab 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.AssetFileDescriptor;
@@ -82,6 +83,9 @@
     public Bundle call(String callingPkg, String authority, String method,
             @Nullable String arg, @Nullable Bundle extras) throws RemoteException;
 
+    public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags)
+            throws RemoteException;
+
     public ICancellationSignal createCancellationSignal() throws RemoteException;
 
     public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException;
@@ -116,4 +120,5 @@
     static final int CANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 24;
     static final int UNCANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 25;
     static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26;
+    static final int CHECK_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 27;
 }
diff --git a/core/java/android/content/LoggingContentInterface.java b/core/java/android/content/LoggingContentInterface.java
index 83c0c91..1df1c4f 100644
--- a/core/java/android/content/LoggingContentInterface.java
+++ b/core/java/android/content/LoggingContentInterface.java
@@ -165,6 +165,19 @@
     }
 
     @Override
+    public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags)
+            throws RemoteException {
+        try (Logger l = new Logger("checkUriPermission", uri, uid, modeFlags)) {
+            try {
+                return l.setResult(delegate.checkUriPermission(uri, uid, modeFlags));
+            } catch (Exception res) {
+                l.setResult(res);
+                throw res;
+            }
+        }
+    }
+
+    @Override
     public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues initialValues)
             throws RemoteException {
         try (Logger l = new Logger("insert", uri, initialValues)) {
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 877dfee..9d87e25 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 
 import java.util.Map;
@@ -58,7 +59,9 @@
          * <p>This callback will be run on your main thread.
          *
          * <p><em>Note: This callback will not be triggered when preferences are cleared via
-         * {@link Editor#clear()}.</em>
+         * {@link Editor#clear()}. However, from {@link android.os.Build.VERSION_CODES#R Android R}
+         * onwards, you can use {@link OnSharedPreferencesClearListener} to register for
+         * {@link Editor#clear()} callbacks.</em>
          *
          * @param sharedPreferences The {@link SharedPreferences} that received
          *            the change.
@@ -67,7 +70,23 @@
          */
         void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
     }
-    
+
+    /**
+     * Interface definition for a callback to be invoked when shared preferences are cleared.
+     */
+    public interface OnSharedPreferencesClearListener {
+        /**
+         * Called when shared preferences are cleared via {@link Editor#clear()}.
+         *
+         * <p>This callback will be run on your main thread.
+         *
+         * @param sharedPreferences The {@link SharedPreferences} that received the change.
+         * @param keys The set of keys that were cleared.
+         */
+        void onSharedPreferencesClear(@NonNull SharedPreferences sharedPreferences,
+                @NonNull Set<String> keys);
+    }
+
     /**
      * Interface used for modifying values in a {@link SharedPreferences}
      * object.  All changes you make in an editor are batched, and not copied
@@ -378,12 +397,43 @@
      * @see #unregisterOnSharedPreferenceChangeListener
      */
     void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
-    
+
     /**
      * Unregisters a previous callback.
-     * 
+     *
      * @param listener The callback that should be unregistered.
      * @see #registerOnSharedPreferenceChangeListener
      */
     void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
+
+    /**
+     * Registers a callback to be invoked when preferences are cleared via {@link Editor#clear()}.
+     *
+     * <p class="caution"><strong>Caution:</strong> The preference manager does
+     * not currently store a strong reference to the listener. You must store a
+     * strong reference to the listener, or it will be susceptible to garbage
+     * collection. We recommend you keep a reference to the listener in the
+     * instance data of an object that will exist as long as you need the
+     * listener.</p>
+     *
+     * @param listener The callback that will run.
+     * @see #unregisterOnSharedPreferencesClearListener
+     */
+    default void registerOnSharedPreferencesClearListener(
+            @NonNull OnSharedPreferencesClearListener listener) {
+        throw new UnsupportedOperationException(
+                "registerOnSharedPreferencesClearListener not implemented");
+    }
+
+    /**
+     * Unregisters a previous callback for {@link Editor#clear()}.
+     *
+     * @param listener The callback that should be unregistered.
+     * @see #registerOnSharedPreferencesClearListener
+     */
+    default void unregisterOnSharedPreferencesClearListener(
+            @NonNull OnSharedPreferencesClearListener listener) {
+        throw new UnsupportedOperationException(
+                "unregisterOnSharedPreferencesClearListener not implemented");
+    }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index f75cd23..d0a61eb 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -614,10 +614,10 @@
 
     /**
      * Value for {@link #privateFlags}: whether this app is pre-installed on the
-     * google partition of the system image.
+     * system_ext partition of the system image.
      * @hide
      */
-    public static final int PRIVATE_FLAG_PRODUCT_SERVICES = 1 << 21;
+    public static final int PRIVATE_FLAG_SYSTEM_EXT = 1 << 21;
 
     /**
      * Indicates whether this package requires access to non-SDK APIs.
@@ -713,7 +713,7 @@
             PRIVATE_FLAG_USE_EMBEDDED_DEX,
             PRIVATE_FLAG_PRIVILEGED,
             PRIVATE_FLAG_PRODUCT,
-            PRIVATE_FLAG_PRODUCT_SERVICES,
+            PRIVATE_FLAG_SYSTEM_EXT,
             PRIVATE_FLAG_PROFILEABLE_BY_SHELL,
             PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER,
             PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY,
@@ -2046,8 +2046,8 @@
     }
 
     /** @hide */
-    public boolean isProductServices() {
-        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0;
+    public boolean isSystemExt() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
     }
 
     /** @hide */
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 277e41d..c6beee2 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -32,7 +32,6 @@
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
-import android.content.pm.IOnPermissionsChangeListener;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.KeySet;
@@ -96,37 +95,6 @@
     @UnsupportedAppUsage
     ProviderInfo getProviderInfo(in ComponentName className, int flags, int userId);
 
-    @UnsupportedAppUsage
-    int checkPermission(String permName, String pkgName, int userId);
-
-    int checkUidPermission(String permName, int uid);
-
-    @UnsupportedAppUsage
-    void grantRuntimePermission(String packageName, String permissionName, int userId);
-
-    void revokeRuntimePermission(String packageName, String permissionName, int userId);
-
-    void resetRuntimePermissions();
-
-    int getPermissionFlags(String permissionName, String packageName, int userId);
-
-    void updatePermissionFlags(String permissionName, String packageName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId);
-
-    void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId);
-
-    List<String> getWhitelistedRestrictedPermissions(String packageName, int flags,
-            int userId);
-
-    boolean addWhitelistedRestrictedPermission(String packageName, String permission,
-            int whitelistFlags, int userId);
-
-    boolean removeWhitelistedRestrictedPermission(String packageName, String permission,
-            int whitelistFlags, int userId);
-
-    boolean shouldShowRequestPermissionRationale(String permissionName,
-            String packageName, int userId);
-
     boolean isProtectedBroadcast(String actionName);
 
     @UnsupportedAppUsage
@@ -624,18 +592,12 @@
     ParceledListSlice getIntentFilterVerifications(String packageName);
     ParceledListSlice getAllIntentFilters(String packageName);
 
-    boolean setDefaultBrowserPackageName(String packageName, int userId);
-    String getDefaultBrowserPackageName(int userId);
-
     VerifierDeviceIdentity getVerifierDeviceIdentity();
 
     boolean isFirstBoot();
     boolean isOnlyCoreApps();
     boolean isDeviceUpgrading();
 
-    void setPermissionEnforced(String permission, boolean enforced);
-    boolean isPermissionEnforced(String permission);
-
     /** Reflects current DeviceStorageMonitorService state */
     @UnsupportedAppUsage
     boolean isStorageLow();
@@ -659,19 +621,6 @@
     boolean isPackageSignedByKeySet(String packageName, in KeySet ks);
     boolean isPackageSignedByKeySetExactly(String packageName, in KeySet ks);
 
-    void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
-    void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
-    void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);
-    void grantDefaultPermissionsToEnabledImsServices(in String[] packageNames, int userId);
-    void grantDefaultPermissionsToEnabledTelephonyDataServices(
-            in String[] packageNames, int userId);
-    void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
-            in String[] packageNames, int userId);
-    void grantDefaultPermissionsToActiveLuiApp(in String packageName, int userId);
-    void revokeDefaultPermissionsFromLuiApps(in String[] packageNames, int userId);
-
-    boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
-
     @UnsupportedAppUsage
     String getPermissionControllerPackageName();
 
@@ -757,6 +706,10 @@
     // The following binder interfaces have been moved to IPermissionManager
     //
     //------------------------------------------------------------------------
+
+    //------------------------------------------------------------------------
+    // We need to keep these in IPackageManager for app compatibility
+    //------------------------------------------------------------------------
     @UnsupportedAppUsage
     String[] getAppOpPermissionPackages(String permissionName);
 
@@ -771,4 +724,17 @@
 
     @UnsupportedAppUsage
     void removePermission(String name);
+
+    @UnsupportedAppUsage
+    int checkPermission(String permName, String pkgName, int userId);
+
+    @UnsupportedAppUsage
+    void grantRuntimePermission(String packageName, String permissionName, int userId);
+
+    //------------------------------------------------------------------------
+    // We need to keep these in IPackageManager for convenience in splitting
+    // out the permission manager. This should be cleaned up, but, will require
+    // a large change that modifies many repos.
+    //------------------------------------------------------------------------
+    int checkUidPermission(String permName, int uid);
 }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3cecd7f..1099d8b 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1565,7 +1565,7 @@
         }
 
         /** {@hide} */
-        @SystemApi
+        @SystemApi @TestApi
         public void setRequestDowngrade(boolean requestDowngrade) {
             if (requestDowngrade) {
                 installFlags |= PackageManager.INSTALL_REQUEST_DOWNGRADE;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b845a37..895eba6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2044,6 +2044,30 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports Open Mobile API capable UICC-based secure
+     * elements.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SE_OMAPI_UICC = "android.hardware.se.omapi.uicc";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports Open Mobile API capable eSE-based secure
+     * elements.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SE_OMAPI_ESE = "android.hardware.se.omapi.ese";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports Open Mobile API capable SD-based secure
+     * elements.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SE_OMAPI_SD = "android.hardware.se.omapi.sd";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports the OpenGL ES
      * <a href="http://www.khronos.org/registry/gles/extensions/ANDROID/ANDROID_extension_pack_es31a.txt">
      * Android Extension Pack</a>.
@@ -3571,7 +3595,7 @@
     /**
      * Retrieve all of the information we know about a particular permission.
      *
-     * @param permissionName The fully qualified name (i.e. com.google.permission.LOGIN)
+     * @param permName The fully qualified name (i.e. com.google.permission.LOGIN)
      *            of the permission you are interested in.
      * @param flags Additional option flags to modify the data returned.
      * @return Returns a {@link PermissionInfo} containing information about the
@@ -3579,7 +3603,7 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract PermissionInfo getPermissionInfo(@NonNull String permissionName,
+    public abstract PermissionInfo getPermissionInfo(@NonNull String permName,
             @PermissionInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -3620,7 +3644,7 @@
      * Retrieve all of the information we know about a particular group of
      * permissions.
      *
-     * @param permissionName The fully qualified name (i.e.
+     * @param permName The fully qualified name (i.e.
      *            com.google.permission_group.APPS) of the permission you are
      *            interested in.
      * @param flags Additional option flags to modify the data returned.
@@ -3630,7 +3654,7 @@
      *             found on the system.
      */
     @NonNull
-    public abstract PermissionGroupInfo getPermissionGroupInfo(@NonNull String permissionName,
+    public abstract PermissionGroupInfo getPermissionGroupInfo(@NonNull String permName,
             @PermissionGroupInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -3858,7 +3882,7 @@
      * Check whether a particular package has been granted a particular
      * permission.
      *
-     * @param permissionName The name of the permission you are checking for.
+     * @param permName The name of the permission you are checking for.
      * @param packageName The name of the package you are checking against.
      *
      * @return If the package has the permission, PERMISSION_GRANTED is
@@ -3870,7 +3894,7 @@
      */
     @CheckResult
     @PermissionResult
-    public abstract int checkPermission(@NonNull String permissionName,
+    public abstract int checkPermission(@NonNull String permName,
             @NonNull String packageName);
 
     /**
@@ -3880,13 +3904,13 @@
      * permissions, hence the only way for an app to get such a permission
      * is by a policy change.
      *
-     * @param permissionName The name of the permission you are checking for.
+     * @param permName The name of the permission you are checking for.
      * @param packageName The name of the package you are checking against.
      *
      * @return Whether the permission is restricted by policy.
      */
     @CheckResult
-    public abstract boolean isPermissionRevokedByPolicy(@NonNull String permissionName,
+    public abstract boolean isPermissionRevokedByPolicy(@NonNull String permName,
             @NonNull String packageName);
 
     /**
@@ -3949,14 +3973,14 @@
      * -- you are only allowed to remove permissions that you are allowed
      * to add.
      *
-     * @param permissionName The name of the permission to remove.
+     * @param permName The name of the permission to remove.
      *
      * @throws SecurityException if you are not allowed to remove the
      * given permission name.
      *
      * @see #addPermission(PermissionInfo)
      */
-    public abstract void removePermission(@NonNull String permissionName);
+    public abstract void removePermission(@NonNull String permName);
 
     /**
      * Permission flags set when granting or revoking a permission.
@@ -3998,7 +4022,7 @@
      * </p>
      *
      * @param packageName The package to which to grant the permission.
-     * @param permissionName The permission name to grant.
+     * @param permName The permission name to grant.
      * @param user The user for which to grant the permission.
      *
      * @see #revokeRuntimePermission(String, String, android.os.UserHandle)
@@ -4009,7 +4033,7 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
     public abstract void grantRuntimePermission(@NonNull String packageName,
-            @NonNull String permissionName, @NonNull UserHandle user);
+            @NonNull String permName, @NonNull UserHandle user);
 
     /**
      * Revoke a runtime permission that was previously granted by {@link
@@ -4025,7 +4049,7 @@
      * </p>
      *
      * @param packageName The package from which to revoke the permission.
-     * @param permissionName The permission name to revoke.
+     * @param permName The permission name to revoke.
      * @param user The user for which to revoke the permission.
      *
      * @see #grantRuntimePermission(String, String, android.os.UserHandle)
@@ -4036,12 +4060,12 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
     public abstract void revokeRuntimePermission(@NonNull String packageName,
-            @NonNull String permissionName, @NonNull UserHandle user);
+            @NonNull String permName, @NonNull UserHandle user);
 
     /**
      * Gets the state flags associated with a permission.
      *
-     * @param permissionName The permission for which to get the flags.
+     * @param permName The permission for which to get the flags.
      * @param packageName The package name for which to get the flags.
      * @param user The user for which to get permission flags.
      * @return The permission flags.
@@ -4056,14 +4080,14 @@
             android.Manifest.permission.GET_RUNTIME_PERMISSIONS
     })
     @PermissionFlags
-    public abstract int getPermissionFlags(@NonNull String permissionName,
+    public abstract int getPermissionFlags(@NonNull String permName,
             @NonNull String packageName, @NonNull UserHandle user);
 
     /**
      * Updates the flags associated with a permission by replacing the flags in
      * the specified mask with the provided flag values.
      *
-     * @param permissionName The permission for which to update the flags.
+     * @param permName The permission for which to update the flags.
      * @param packageName The package name for which to update the flags.
      * @param flagMask The flags which to replace.
      * @param flagValues The flags with which to replace.
@@ -4077,7 +4101,7 @@
             android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
             android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
     })
-    public abstract void updatePermissionFlags(@NonNull String permissionName,
+    public abstract void updatePermissionFlags(@NonNull String permName,
             @NonNull String packageName, @PermissionFlags int flagMask,
             @PermissionFlags int flagValues, @NonNull UserHandle user);
 
@@ -4164,7 +4188,7 @@
      * provided ones.
      *
      * @param packageName The app for which to get whitelisted permissions.
-     * @param permission The whitelisted permission to add.
+     * @param permName The whitelisted permission to add.
      * @param whitelistFlags The whitelists to which to add. Passing multiple flags
      * updates all specified whitelists.
      * @return Whether the permission was added to the whitelist.
@@ -4180,7 +4204,7 @@
     @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS,
             conditional = true)
     public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
-            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
+            @NonNull String permName, @PermissionWhitelistFlags int whitelistFlags) {
         return false;
     }
 
@@ -4218,7 +4242,7 @@
      * provided ones.
      *
      * @param packageName The app for which to get whitelisted permissions.
-     * @param permission The whitelisted permission to remove.
+     * @param permName The whitelisted permission to remove.
      * @param whitelistFlags The whitelists from which to remove. Passing multiple flags
      * updates all specified whitelists.
      * @return Whether the permission was removed from the whitelist.
@@ -4234,7 +4258,7 @@
     @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS,
         conditional = true)
     public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
-        @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
+            @NonNull String permName, @PermissionWhitelistFlags int whitelistFlags) {
         return false;
     }
 
@@ -4244,13 +4268,13 @@
      * which the permission is requested does not clearly communicate to the user
      * what would be the benefit from grating this permission.
      *
-     * @param permissionName A permission your app wants to request.
+     * @param permName A permission your app wants to request.
      * @return Whether you can show permission rationale UI.
      *
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract boolean shouldShowRequestPermissionRationale(@NonNull String permissionName);
+    public abstract boolean shouldShowRequestPermissionRationale(@NonNull String permName);
 
     /**
      * Returns an {@link android.content.Intent} suitable for passing to
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 1c1d709..2f198ac 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -32,13 +32,10 @@
 import android.util.ArraySet;
 import android.util.SparseArray;
 
-import com.android.internal.util.function.TriFunction;
-
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
-import java.util.function.BiFunction;
 import java.util.function.Consumer;
 
 /**
@@ -86,165 +83,6 @@
         void onPackageRemoved(@NonNull String packageName, int uid);
     }
 
-    /** Interface to override permission checks via composition */
-    public interface CheckPermissionDelegate {
-        /**
-         * Allows overriding check permission behavior.
-         *
-         * @param permName The permission to check.
-         * @param pkgName The package for which to check.
-         * @param userId The user for which to check.
-         * @param superImpl The super implementation.
-         * @return The check permission result.
-         */
-        int checkPermission(String permName, String pkgName, int userId,
-                TriFunction<String, String, Integer, Integer> superImpl);
-
-        /**
-         * Allows overriding check UID permission behavior.
-         *
-         * @param permName The permission to check.
-         * @param uid The UID for which to check.
-         * @param superImpl The super implementation.
-         * @return The check permission result.
-         */
-        int checkUidPermission(String permName, int uid,
-                BiFunction<String, Integer, Integer> superImpl);
-    }
-
-    /**
-     * Provider for package names.
-     */
-    public interface PackagesProvider {
-
-        /**
-         * Gets the packages for a given user.
-         * @param userId The user id.
-         * @return The package names.
-         */
-        public String[] getPackages(int userId);
-    }
-
-    /**
-     * Provider for package names.
-     */
-    public interface SyncAdapterPackagesProvider {
-
-        /**
-         * Gets the sync adapter packages for given authority and user.
-         * @param authority The authority.
-         * @param userId The user id.
-         * @return The package names.
-         */
-        public String[] getPackages(String authority, int userId);
-    }
-
-    /**
-     * Provider for default browser
-     */
-    public interface DefaultBrowserProvider {
-
-        /**
-         * Get the package name of the default browser.
-         *
-         * @param userId the user id
-         *
-         * @return the package name of the default browser, or {@code null} if none
-         */
-        @Nullable
-        String getDefaultBrowser(@UserIdInt int userId);
-
-        /**
-         * Set the package name of the default browser.
-         *
-         * @param packageName package name of the default browser, or {@code null} to remove
-         * @param userId the user id
-         *
-         * @return whether the default browser was successfully set.
-         */
-        boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId);
-
-        /**
-         * Set the package name of the default browser asynchronously.
-         *
-         * @param packageName package name of the default browser, or {@code null} to remove
-         * @param userId the user id
-         */
-        void setDefaultBrowserAsync(@Nullable String packageName, @UserIdInt int userId);
-    }
-
-    /**
-     * Provider for default dialer
-     */
-    public interface DefaultDialerProvider {
-
-        /**
-         * Get the package name of the default dialer.
-         *
-         * @param userId the user id
-         *
-         * @return the package name of the default dialer, or {@code null} if none
-         */
-        @Nullable
-        String getDefaultDialer(@UserIdInt int userId);
-    }
-
-    /**
-     * Provider for default home
-     */
-    public interface DefaultHomeProvider {
-
-        /**
-         * Get the package name of the default home.
-         *
-         * @param userId the user id
-         *
-         * @return the package name of the default home, or {@code null} if none
-         */
-        @Nullable
-        String getDefaultHome(@UserIdInt int userId);
-
-        /**
-         * Set the package name of the default home.
-         *
-         * @param packageName package name of the default home, or {@code null} to remove
-         * @param userId the user id
-         * @param callback the callback made after the default home as been updated
-         */
-        void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId,
-                @NonNull Consumer<Boolean> callback);
-    }
-
-    /**
-     * Sets the location provider packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setLocationPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Set the location extra packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract  void setLocationExtraPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the voice interaction packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setVoiceInteractionPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the Use Open Wifi packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setUseOpenWifiAppPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the sync adapter packages provider.
-     * @param provider The provider.
-     */
-    public abstract void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider);
-
     /**
      * Called when the package for the default SMS handler changed
      *
@@ -262,14 +100,6 @@
     public void onDefaultSimCallManagerAppChanged(String packageName, int userId) {}
 
     /**
-     * Requests granting of the default permissions to the current default Use Open Wifi app.
-     * @param packageName The default use open wifi package name.
-     * @param userId The user for which to grant the permissions.
-     */
-    public abstract void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName,
-            int userId);
-
-    /**
      * Sets a list of apps to keep in PM's internal data structures and as APKs even if no user has
      * currently installed it. The apps are not preloaded.
      * @param packageList List of package names to keep cached.
@@ -464,26 +294,6 @@
     public abstract boolean wasPackageEverLaunched(String packageName, int userId);
 
     /**
-     * Grants a runtime permission
-     * @param packageName The package name.
-     * @param name The name of the permission.
-     * @param userId The userId for which to grant the permission.
-     * @param overridePolicy If true, grant this permission even if it is fixed by policy.
-     */
-    public abstract void grantRuntimePermission(String packageName, String name, int userId,
-            boolean overridePolicy);
-
-    /**
-     * Revokes a runtime permission
-     * @param packageName The package name.
-     * @param name The name of the permission.
-     * @param userId The userId for which to revoke the permission.
-     * @param overridePolicy If true, revoke this permission even if it is fixed by policy.
-     */
-    public abstract void revokeRuntimePermission(String packageName, String name, int userId,
-            boolean overridePolicy);
-
-    /**
      * Retrieve the official name associated with a uid. This name is
      * guaranteed to never change, though it is possible for the underlying
      * uid to be changed. That is, if you are storing information about
@@ -668,6 +478,12 @@
     public abstract @Nullable PackageParser.Package getPackage(@NonNull String packageName);
 
     /**
+     * Returns a package for the given UID. If the UID is part of a shared user ID, one
+     * of the packages will be chosen to be returned.
+     */
+    public abstract @Nullable PackageParser.Package getPackage(int uid);
+
+    /**
      * Returns a list without a change observer.
      *
      * @see #getPackageList(PackageListObserver)
@@ -740,18 +556,15 @@
      * @see #canAccessInstantApps
      */
     public abstract boolean filterAppAccess(
-            @Nullable PackageParser.Package pkg, int callingUid, int userId);
+            @NonNull PackageParser.Package pkg, int callingUid, int userId);
 
-    /*
-     * NOTE: The following methods are temporary until permissions are extracted from
-     * the package manager into a component specifically for handling permissions.
+    /**
+     * Returns whether or not access to the application should be filtered.
+     *
+     * @see #filterAppAccess(android.content.pm.PackageParser.Package, int, int)
      */
-    /** Returns the flags for the given permission. */
-    public abstract @Nullable int getPermissionFlagsTEMP(@NonNull String permName,
-            @NonNull String packageName, int userId);
-    /** Updates the flags for the given permission. */
-    public abstract void updatePermissionFlagsTEMP(@NonNull String permName,
-            @NonNull String packageName, int flagMask, int flagValues, int userId);
+    public abstract boolean filterAppAccess(
+            @NonNull String packageName, int callingUid, int userId);
 
     /** Returns whether the given package was signed by the platform */
     public abstract boolean isPlatformSigned(String pkg);
@@ -782,20 +595,6 @@
             @PackageParser.SigningDetails.CertCapabilities int capability);
 
     /**
-     * Get the delegate to influence permission checking.
-     *
-     * @return The delegate instance or null to clear.
-     */
-    public abstract @Nullable CheckPermissionDelegate getCheckPermissionDelegate();
-
-    /**
-     * Set a delegate to influence permission checking.
-     *
-     * @param delegate A delegate instance or null to clear.
-     */
-    public abstract void setCheckPermissionDelegate(@Nullable CheckPermissionDelegate delegate);
-
-    /**
      * Get appIds of all available apps which specified android:sharedUserId in the manifest.
      *
      * @return a SparseArray mapping from appId to it's sharedUserId.
@@ -940,27 +739,6 @@
     public abstract String removeLegacyDefaultBrowserPackageName(int userId);
 
     /**
-     * Sets the default browser provider.
-     *
-     * @param provider the provider
-     */
-    public abstract void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider);
-
-    /**
-     * Sets the default dialer provider.
-     *
-     * @param provider the provider
-     */
-    public abstract void setDefaultDialerProvider(@NonNull DefaultDialerProvider provider);
-
-    /**
-     * Sets the default home provider.
-     *
-     * @param provider the provider
-     */
-    public abstract void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider);
-
-    /**
      * Returns {@code true} if given {@code packageName} is an apex package.
      */
     public abstract boolean isApexPackage(String packageName);
@@ -978,15 +756,6 @@
             IntentSender intentSender);
 
     /**
-     * Whether default permission grants have been performed for a user
-     * since the device booted.
-     *
-     * @param userId The user id.
-     * @return true if default permissions
-     */
-    public abstract boolean wereDefaultPermissionsGrantedSinceBoot(int userId);
-
-    /**
      * Get fingerprint of build that updated the runtime permissions for a user.
      *
      * @param userId The user to update
@@ -1006,4 +775,32 @@
      * the settings have been written.
      */
     public abstract void writeSettings(boolean async);
+
+    /**
+     * Writes all permission settings for the given set of users to disk. If {@code async}
+     * is {@code true}, the settings are written at some point in the future. Otherwise,
+     * the call blocks until the settings have been written.
+     */
+    public abstract void writePermissionSettings(@NonNull @UserIdInt int[] userIds, boolean async);
+
+    /**
+     * Returns the target SDK for the given UID. Will return {@code 0} if there is no
+     * package associated with the UID or if the package has not been installed for
+     * the user. Will return the highest target SDK if the UID references packages with
+     * a shared user id.
+     */
+    public abstract int getTargetSdk(int uid);
+
+    /**
+     * Returns {@code true} if the caller is the installer of record for the given package.
+     * Otherwise, {@code false}.
+     */
+    public abstract boolean isCallerInstallerOfRecord(
+            @NonNull PackageParser.Package pkg, int callingUid);
+
+    /** Returns whether or not default runtime permissions are granted for the given user */
+    public abstract boolean areDefaultRuntimePermissionsGranted(@UserIdInt int userId);
+
+    /** Sets the enforcement of reading external storage */
+    public abstract void setReadExternalStorageEnforced(boolean enforced);
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index a74c34f..a4933ef 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -66,6 +66,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.FileUtils;
@@ -254,6 +255,8 @@
 
     /** @hide */
     public static final String APK_FILE_EXTENSION = ".apk";
+    /** @hide */
+    public static final String APEX_FILE_EXTENSION = ".apex";
 
     /** @hide */
     public static class NewPermissionInfo {
@@ -2443,6 +2446,8 @@
                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                 return null;
 
+            } else if (tagName.equals("queries")) {
+                parseQueries(pkg, res, parser, flags, outError);
             } else {
                 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
                         + " at " + mArchiveSourcePath + " "
@@ -3536,6 +3541,9 @@
             owner.mRequiredAccountType = requiredAccountType;
         }
 
+        owner.mForceQueryable =
+                sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false);
+
         if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
                 false)) {
@@ -3951,7 +3959,6 @@
                     ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL;
                 }
                 XmlUtils.skipCurrentTag(parser);
-
             } else {
                 if (!RIGID_PARSER) {
                     Slog.w(TAG, "Unknown element under <application>: " + tagName
@@ -3998,6 +4005,67 @@
         return true;
     }
 
+    private boolean parseQueries(Package owner, Resources res, XmlResourceParser parser, int flags,
+            String[] outError)
+            throws IOException, XmlPullParserException {
+
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (parser.getName().equals("intent")) {
+                QueriesIntentInfo intentInfo = new QueriesIntentInfo();
+                if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
+                        intentInfo, outError)) {
+                    return false;
+                }
+                Intent intent = new Intent();
+                if (intentInfo.countActions() != 1) {
+                    outError[0] = "intent tags must contain exactly one action.";
+                    return false;
+                }
+                intent.setAction(intentInfo.getAction(0));
+                for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
+                    intent.addCategory(intentInfo.getCategory(i));
+                }
+                Uri data = null;
+                String dataType = null;
+                if (intentInfo.countDataTypes() > 1) {
+                    outError[0] = "intent tag may have at most one data type.";
+                    return false;
+                }
+                if (intentInfo.countDataSchemes() > 1) {
+                    outError[0] = "intent tag may have at most one data scheme.";
+                    return false;
+                }
+                if (intentInfo.countDataTypes() == 1) {
+                    data = Uri.fromParts(intentInfo.getDataType(0), "", null);
+                }
+                if (intentInfo.countDataSchemes() == 1) {
+                    dataType = intentInfo.getDataScheme(0);
+                }
+                intent.setDataAndType(data, dataType);
+                owner.mQueriesIntents = ArrayUtils.add(owner.mQueriesIntents, intent);
+            } else if (parser.getName().equals("package")) {
+                final TypedArray sa = res.obtainAttributes(parser,
+                        com.android.internal.R.styleable.AndroidManifestQueriesPackage);
+                final String packageName =
+                        sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
+                if (TextUtils.isEmpty(packageName)) {
+                    outError[0] = "Package name is missing from package tag.";
+                    return false;
+                }
+                owner.mQueriesPackages =
+                        ArrayUtils.add(owner.mQueriesPackages, packageName.intern());
+            }
+        }
+        return true;
+    }
+
     /**
      * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
      */
@@ -6512,6 +6580,9 @@
         // The major version code declared for this package.
         public int mVersionCodeMajor;
 
+        // Whether the package declares that it should be queryable by all normal apps on device.
+        public boolean mForceQueryable;
+
         // Return long containing mVersionCode and mVersionCodeMajor.
         public long getLongVersionCode() {
             return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
@@ -6617,6 +6688,9 @@
         /** Whether or not the package is a stub and must be replaced by the full version. */
         public boolean isStub;
 
+        public ArrayList<String> mQueriesPackages;
+        public ArrayList<Intent> mQueriesIntents;
+
         @UnsupportedAppUsage
         public Package(String packageName) {
             this.packageName = packageName;
@@ -6897,8 +6971,8 @@
         }
 
         /** @hide */
-        public boolean isProductServices() {
-            return applicationInfo.isProductServices();
+        public boolean isSystemExt() {
+            return applicationInfo.isSystemExt();
         }
 
         /** @hide */
@@ -7120,6 +7194,9 @@
             use32bitAbi = (dest.readInt() == 1);
             restrictUpdateHash = dest.createByteArray();
             visibleToInstantApps = dest.readInt() == 1;
+            mForceQueryable = dest.readBoolean();
+            mQueriesIntents = dest.createTypedArrayList(Intent.CREATOR);
+            mQueriesPackages = dest.createStringArrayList();
         }
 
         private static void internStringArrayList(List<String> list) {
@@ -7245,6 +7322,9 @@
             dest.writeInt(use32bitAbi ? 1 : 0);
             dest.writeByteArray(restrictUpdateHash);
             dest.writeInt(visibleToInstantApps ? 1 : 0);
+            dest.writeBoolean(mForceQueryable);
+            dest.writeTypedList(mQueriesIntents);
+            dest.writeList(mQueriesPackages);
         }
 
 
@@ -8255,6 +8335,8 @@
         }
     }
 
+    public static final class QueriesIntentInfo extends IntentInfo {}
+
     public final static class ActivityIntentInfo extends IntentInfo {
         @UnsupportedAppUsage
         public Activity activity;
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 2b1b32e..7865d75 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -19,7 +19,6 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 
@@ -232,7 +231,7 @@
         if (isManagedProfile() || isGuest() || isRestricted()) {
             return false;
         }
-        if (UserManager.isSplitSystemUser()) {
+        if (UserManager.isSplitSystemUser() || UserManager.isHeadlessSystemUserMode()) {
             return id != UserHandle.USER_SYSTEM;
         } else {
             return id == UserHandle.USER_SYSTEM;
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index a99a0b5..f3b7553 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -32,8 +32,8 @@
 import android.view.WindowManager.LayoutParams;
 
 /**
- * CompatibilityInfo class keeps the information about compatibility mode that the application is
- * running under.
+ * CompatibilityInfo class keeps the information about the screen compatibility mode that the
+ * application is running under.
  * 
  *  {@hide} 
  */
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 794be9e..b72544c 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -856,7 +856,8 @@
             stack.push(id);
             try {
                 if (file.endsWith(".xml")) {
-                    if (file.startsWith("res/color/")) {
+                    final String typeName = getResourceTypeName(id);
+                    if (typeName != null && typeName.equals("color")) {
                         dr = loadColorOrXmlDrawable(wrapper, value, id, density, file);
                     } else {
                         dr = loadXmlDrawable(wrapper, value, id, density, file);
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 3523e95..48d8867 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -30,11 +30,14 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
+
 import libcore.util.EmptyArray;
 
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
@@ -49,14 +52,11 @@
 public class SQLiteQueryBuilder {
     private static final String TAG = "SQLiteQueryBuilder";
 
-    private static final Pattern sLimitPattern =
-            Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
     private static final Pattern sAggregationPattern = Pattern.compile(
             "(?i)(AVG|COUNT|MAX|MIN|SUM|TOTAL|GROUP_CONCAT)\\((.+)\\)");
 
     private Map<String, String> mProjectionMap = null;
     private List<Pattern> mProjectionGreylist = null;
-    private boolean mProjectionAggregationAllowed = false;
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private String mTables = "";
@@ -65,7 +65,12 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private boolean mDistinct;
     private SQLiteDatabase.CursorFactory mFactory;
-    private boolean mStrict;
+
+    private static final int STRICT_PARENTHESES = 1 << 0;
+    private static final int STRICT_COLUMNS = 1 << 1;
+    private static final int STRICT_GRAMMAR = 1 << 2;
+
+    private int mStrictFlags;
 
     public SQLiteQueryBuilder() {
         mDistinct = false;
@@ -209,13 +214,14 @@
     }
 
     /** {@hide} */
+    @Deprecated
     public void setProjectionAggregationAllowed(boolean projectionAggregationAllowed) {
-        mProjectionAggregationAllowed = projectionAggregationAllowed;
     }
 
     /** {@hide} */
+    @Deprecated
     public boolean isProjectionAggregationAllowed() {
-        return mProjectionAggregationAllowed;
+        return true;
     }
 
     /**
@@ -258,8 +264,12 @@
      * </ul>
      * By default, this value is false.
      */
-    public void setStrict(boolean flag) {
-        mStrict = flag;
+    public void setStrict(boolean strict) {
+        if (strict) {
+            mStrictFlags |= STRICT_PARENTHESES;
+        } else {
+            mStrictFlags &= ~STRICT_PARENTHESES;
+        }
     }
 
     /**
@@ -267,7 +277,67 @@
      * {@link #setStrict(boolean)}.
      */
     public boolean isStrict() {
-        return mStrict;
+        return (mStrictFlags & STRICT_PARENTHESES) != 0;
+    }
+
+    /**
+     * When enabled, verify that all projections and {@link ContentValues} only
+     * contain valid columns as defined by {@link #setProjectionMap(Map)}.
+     * <p>
+     * This enforcement applies to {@link #insert}, {@link #query}, and
+     * {@link #update} operations. Any enforcement failures will throw an
+     * {@link IllegalArgumentException}.
+     */
+    public void setStrictColumns(boolean strictColumns) {
+        if (strictColumns) {
+            mStrictFlags |= STRICT_COLUMNS;
+        } else {
+            mStrictFlags &= ~STRICT_COLUMNS;
+        }
+    }
+
+    /**
+     * Get if the query is marked as strict, as last configured by
+     * {@link #setStrictColumns(boolean)}.
+     */
+    public boolean isStrictColumns() {
+        return (mStrictFlags & STRICT_COLUMNS) != 0;
+    }
+
+    /**
+     * When enabled, verify that all untrusted SQL conforms to a restricted SQL
+     * grammar. Here are the restrictions applied:
+     * <ul>
+     * <li>In {@code WHERE} and {@code HAVING} clauses: subqueries, raising, and
+     * windowing terms are rejected.
+     * <li>In {@code GROUP BY} clauses: only valid columns are allowed.
+     * <li>In {@code ORDER BY} clauses: only valid columns, collation, and
+     * ordering terms are allowed.
+     * <li>In {@code LIMIT} clauses: only numerical values and offset terms are
+     * allowed.
+     * </ul>
+     * All column references must be valid as defined by
+     * {@link #setProjectionMap(Map)}.
+     * <p>
+     * This enforcement applies to {@link #query}, {@link #update} and
+     * {@link #delete} operations. This enforcement does not apply to trusted
+     * inputs, such as those provided by {@link #appendWhere}. Any enforcement
+     * failures will throw an {@link IllegalArgumentException}.
+     */
+    public void setStrictGrammar(boolean strictGrammar) {
+        if (strictGrammar) {
+            mStrictFlags |= STRICT_GRAMMAR;
+        } else {
+            mStrictFlags &= ~STRICT_GRAMMAR;
+        }
+    }
+
+    /**
+     * Get if the query is marked as strict, as last configured by
+     * {@link #setStrictGrammar(boolean)}.
+     */
+    public boolean isStrictGrammar() {
+        return (mStrictFlags & STRICT_GRAMMAR) != 0;
     }
 
     /**
@@ -303,9 +373,6 @@
             throw new IllegalArgumentException(
                     "HAVING clauses are only permitted when using a groupBy clause");
         }
-        if (!TextUtils.isEmpty(limit) && !sLimitPattern.matcher(limit).matches()) {
-            throw new IllegalArgumentException("invalid LIMIT clauses:" + limit);
-        }
 
         StringBuilder query = new StringBuilder(120);
 
@@ -479,7 +546,13 @@
                 projectionIn, selection, groupBy, having,
                 sortOrder, limit);
 
-        if (mStrict && selection != null && selection.length() > 0) {
+        if (isStrictColumns()) {
+            enforceStrictColumns(projectionIn);
+        }
+        if (isStrictGrammar()) {
+            enforceStrictGrammar(selection, groupBy, having, sortOrder, limit);
+        }
+        if (isStrict()) {
             // Validate the user-supplied selection to detect syntactic anomalies
             // in the selection string that could indicate a SQL injection attempt.
             // The idea is to ensure that the selection clause is a valid SQL expression
@@ -497,7 +570,7 @@
 
             // Execute wrapped query for extra protection
             final String wrappedSql = buildQuery(projectionIn, wrap(selection), groupBy,
-                    having, sortOrder, limit);
+                    wrap(having), sortOrder, limit);
             sql = wrappedSql;
         } else {
             // Execute unwrapped query
@@ -519,6 +592,40 @@
     }
 
     /**
+     * Perform an insert by combining all current settings and the
+     * information passed into this method.
+     *
+     * @param db the database to insert on
+     * @return the row ID of the newly inserted row, or -1 if an error occurred
+     */
+    public long insert(@NonNull SQLiteDatabase db, @NonNull ContentValues values) {
+        Objects.requireNonNull(mTables, "No tables defined");
+        Objects.requireNonNull(db, "No database defined");
+        Objects.requireNonNull(values, "No values defined");
+
+        if (isStrictColumns()) {
+            enforceStrictColumns(values);
+        }
+
+        final String sql = buildInsert(values);
+
+        final ArrayMap<String, Object> rawValues = values.getValues();
+        final int valuesLength = rawValues.size();
+        final Object[] sqlArgs = new Object[valuesLength];
+        for (int i = 0; i < sqlArgs.length; i++) {
+            sqlArgs[i] = rawValues.valueAt(i);
+        }
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (Build.IS_DEBUGGABLE) {
+                Log.d(TAG, sql + " with args " + Arrays.toString(sqlArgs));
+            } else {
+                Log.d(TAG, sql);
+            }
+        }
+        return db.executeSql(sql, sqlArgs);
+    }
+
+    /**
      * Perform an update by combining all current settings and the
      * information passed into this method.
      *
@@ -541,7 +648,13 @@
         final String sql;
         final String unwrappedSql = buildUpdate(values, selection);
 
-        if (mStrict) {
+        if (isStrictColumns()) {
+            enforceStrictColumns(values);
+        }
+        if (isStrictGrammar()) {
+            enforceStrictGrammar(selection, null, null, null, null);
+        }
+        if (isStrict()) {
             // Validate the user-supplied selection to detect syntactic anomalies
             // in the selection string that could indicate a SQL injection attempt.
             // The idea is to ensure that the selection clause is a valid SQL expression
@@ -610,7 +723,10 @@
         final String sql;
         final String unwrappedSql = buildDelete(selection);
 
-        if (mStrict) {
+        if (isStrictGrammar()) {
+            enforceStrictGrammar(selection, null, null, null, null);
+        }
+        if (isStrict()) {
             // Validate the user-supplied selection to detect syntactic anomalies
             // in the selection string that could indicate a SQL injection attempt.
             // The idea is to ensure that the selection clause is a valid SQL expression
@@ -645,6 +761,81 @@
         return db.executeSql(sql, sqlArgs);
     }
 
+    private void enforceStrictColumns(@Nullable String[] projection) {
+        Objects.requireNonNull(mProjectionMap, "No projection map defined");
+
+        computeProjection(projection);
+    }
+
+    private void enforceStrictColumns(@NonNull ContentValues values) {
+        Objects.requireNonNull(mProjectionMap, "No projection map defined");
+
+        final ArrayMap<String, Object> rawValues = values.getValues();
+        for (int i = 0; i < rawValues.size(); i++) {
+            final String column = rawValues.keyAt(i);
+            if (!mProjectionMap.containsKey(column)) {
+                throw new IllegalArgumentException("Invalid column " + column);
+            }
+        }
+    }
+
+    private void enforceStrictGrammar(@Nullable String selection, @Nullable String groupBy,
+            @Nullable String having, @Nullable String sortOrder, @Nullable String limit) {
+        SQLiteTokenizer.tokenize(selection, SQLiteTokenizer.OPTION_NONE,
+                this::enforceStrictGrammarWhereHaving);
+        SQLiteTokenizer.tokenize(groupBy, SQLiteTokenizer.OPTION_NONE,
+                this::enforceStrictGrammarGroupBy);
+        SQLiteTokenizer.tokenize(having, SQLiteTokenizer.OPTION_NONE,
+                this::enforceStrictGrammarWhereHaving);
+        SQLiteTokenizer.tokenize(sortOrder, SQLiteTokenizer.OPTION_NONE,
+                this::enforceStrictGrammarOrderBy);
+        SQLiteTokenizer.tokenize(limit, SQLiteTokenizer.OPTION_NONE,
+                this::enforceStrictGrammarLimit);
+    }
+
+    private void enforceStrictGrammarWhereHaving(@NonNull String token) {
+        if (isTableOrColumn(token)) return;
+        if (SQLiteTokenizer.isFunction(token)) return;
+        if (SQLiteTokenizer.isType(token)) return;
+
+        // NOTE: we explicitly don't allow SELECT subqueries, since they could
+        // leak data that should have been filtered by the trusted where clause
+        switch (token.toUpperCase(Locale.US)) {
+            case "AND": case "AS": case "BETWEEN": case "BINARY":
+            case "CASE": case "CAST": case "COLLATE": case "DISTINCT":
+            case "ELSE": case "END": case "ESCAPE": case "EXISTS":
+            case "GLOB": case "IN": case "IS": case "ISNULL":
+            case "LIKE": case "MATCH": case "NOCASE": case "NOT":
+            case "NOTNULL": case "NULL": case "OR": case "REGEXP":
+            case "RTRIM": case "THEN": case "WHEN":
+                return;
+        }
+        throw new IllegalArgumentException("Invalid token " + token);
+    }
+
+    private void enforceStrictGrammarGroupBy(@NonNull String token) {
+        if (isTableOrColumn(token)) return;
+        throw new IllegalArgumentException("Invalid token " + token);
+    }
+
+    private void enforceStrictGrammarOrderBy(@NonNull String token) {
+        if (isTableOrColumn(token)) return;
+        switch (token.toUpperCase(Locale.US)) {
+            case "COLLATE": case "ASC": case "DESC":
+            case "BINARY": case "RTRIM": case "NOCASE":
+                return;
+        }
+        throw new IllegalArgumentException("Invalid token " + token);
+    }
+
+    private void enforceStrictGrammarLimit(@NonNull String token) {
+        switch (token.toUpperCase(Locale.US)) {
+            case "OFFSET":
+                return;
+        }
+        throw new IllegalArgumentException("Invalid token " + token);
+    }
+
     /**
      * Construct a {@code SELECT} statement suitable for use in a group of
      * {@code SELECT} statements that will be joined through {@code UNION} operators
@@ -698,6 +889,35 @@
     }
 
     /** {@hide} */
+    public String buildInsert(ContentValues values) {
+        if (values == null || values.isEmpty()) {
+            throw new IllegalArgumentException("Empty values");
+        }
+
+        StringBuilder sql = new StringBuilder(120);
+        sql.append("INSERT INTO ");
+        sql.append(SQLiteDatabase.findEditTable(mTables));
+        sql.append(" (");
+
+        final ArrayMap<String, Object> rawValues = values.getValues();
+        for (int i = 0; i < rawValues.size(); i++) {
+            if (i > 0) {
+                sql.append(',');
+            }
+            sql.append(rawValues.keyAt(i));
+        }
+        sql.append(") VALUES (");
+        for (int i = 0; i < rawValues.size(); i++) {
+            if (i > 0) {
+                sql.append(',');
+            }
+            sql.append('?');
+        }
+        sql.append(")");
+        return sql.toString();
+    }
+
+    /** {@hide} */
     public String buildUpdate(ContentValues values, String selection) {
         if (values == null || values.isEmpty()) {
             throw new IllegalArgumentException("Empty values");
@@ -705,7 +925,7 @@
 
         StringBuilder sql = new StringBuilder(120);
         sql.append("UPDATE ");
-        sql.append(mTables);
+        sql.append(SQLiteDatabase.findEditTable(mTables));
         sql.append(" SET ");
 
         final ArrayMap<String, Object> rawValues = values.getValues();
@@ -726,7 +946,7 @@
     public String buildDelete(String selection) {
         StringBuilder sql = new StringBuilder(120);
         sql.append("DELETE FROM ");
-        sql.append(mTables);
+        sql.append(SQLiteDatabase.findEditTable(mTables));
 
         final String where = computeWhere(selection);
         appendClause(sql, " WHERE ", where);
@@ -868,65 +1088,13 @@
 
     /** {@hide} */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public String[] computeProjection(String[] projectionIn) {
-        if (projectionIn != null && projectionIn.length > 0) {
-            if (mProjectionMap != null) {
-                String[] projection = new String[projectionIn.length];
-                int length = projectionIn.length;
-
-                for (int i = 0; i < length; i++) {
-                    String operator = null;
-                    String userColumn = projectionIn[i];
-                    String column = mProjectionMap.get(userColumn);
-
-                    // If aggregation is allowed, extract the underlying column
-                    // that may be aggregated
-                    if (mProjectionAggregationAllowed) {
-                        final Matcher matcher = sAggregationPattern.matcher(userColumn);
-                        if (matcher.matches()) {
-                            operator = matcher.group(1);
-                            userColumn = matcher.group(2);
-                            column = mProjectionMap.get(userColumn);
-                        }
-                    }
-
-                    if (column != null) {
-                        projection[i] = maybeWithOperator(operator, column);
-                        continue;
-                    }
-
-                    if (!mStrict &&
-                            ( userColumn.contains(" AS ") || userColumn.contains(" as "))) {
-                        /* A column alias already exist */
-                        projection[i] = maybeWithOperator(operator, userColumn);
-                        continue;
-                    }
-
-                    // If greylist is configured, we might be willing to let
-                    // this custom column bypass our strict checks.
-                    if (mProjectionGreylist != null) {
-                        boolean match = false;
-                        for (Pattern p : mProjectionGreylist) {
-                            if (p.matcher(userColumn).matches()) {
-                                match = true;
-                                break;
-                            }
-                        }
-
-                        if (match) {
-                            Log.w(TAG, "Allowing abusive custom column: " + userColumn);
-                            projection[i] = maybeWithOperator(operator, userColumn);
-                            continue;
-                        }
-                    }
-
-                    throw new IllegalArgumentException("Invalid column "
-                            + projectionIn[i]);
-                }
-                return projection;
-            } else {
-                return projectionIn;
+    public @Nullable String[] computeProjection(@Nullable String[] projectionIn) {
+        if (!ArrayUtils.isEmpty(projectionIn)) {
+            String[] projectionOut = new String[projectionIn.length];
+            for (int i = 0; i < projectionIn.length; i++) {
+                projectionOut[i] = computeSingleProjectionOrThrow(projectionIn[i]);
             }
+            return projectionOut;
         } else if (mProjectionMap != null) {
             // Return all columns in projection map.
             Set<Entry<String, String>> entrySet = mProjectionMap.entrySet();
@@ -948,6 +1116,69 @@
         return null;
     }
 
+    private @NonNull String computeSingleProjectionOrThrow(@NonNull String userColumn) {
+        final String column = computeSingleProjection(userColumn);
+        if (column != null) {
+            return column;
+        } else {
+            throw new IllegalArgumentException("Invalid column " + userColumn);
+        }
+    }
+
+    private @Nullable String computeSingleProjection(@NonNull String userColumn) {
+        // When no mapping provided, anything goes
+        if (mProjectionMap == null) {
+            return userColumn;
+        }
+
+        String operator = null;
+        String column = mProjectionMap.get(userColumn);
+
+        // When no direct match found, look for aggregation
+        if (column == null) {
+            final Matcher matcher = sAggregationPattern.matcher(userColumn);
+            if (matcher.matches()) {
+                operator = matcher.group(1);
+                userColumn = matcher.group(2);
+                column = mProjectionMap.get(userColumn);
+            }
+        }
+
+        if (column != null) {
+            return maybeWithOperator(operator, column);
+        }
+
+        if (mStrictFlags == 0 &&
+                (userColumn.contains(" AS ") || userColumn.contains(" as "))) {
+            /* A column alias already exist */
+            return maybeWithOperator(operator, userColumn);
+        }
+
+        // If greylist is configured, we might be willing to let
+        // this custom column bypass our strict checks.
+        if (mProjectionGreylist != null) {
+            boolean match = false;
+            for (Pattern p : mProjectionGreylist) {
+                if (p.matcher(userColumn).matches()) {
+                    match = true;
+                    break;
+                }
+            }
+
+            if (match) {
+                Log.w(TAG, "Allowing abusive custom column: " + userColumn);
+                return maybeWithOperator(operator, userColumn);
+            }
+        }
+
+        return null;
+    }
+
+    private boolean isTableOrColumn(String token) {
+        if (mTables.equals(token)) return true;
+        return computeSingleProjection(token) != null;
+    }
+
     /** {@hide} */
     public @Nullable String computeWhere(@Nullable String selection) {
         final boolean hasInternal = !TextUtils.isEmpty(mWhereClause);
diff --git a/core/java/android/database/sqlite/SQLiteTokenizer.java b/core/java/android/database/sqlite/SQLiteTokenizer.java
new file mode 100644
index 0000000..7e7c3fb
--- /dev/null
+++ b/core/java/android/database/sqlite/SQLiteTokenizer.java
@@ -0,0 +1,297 @@
+/*
+ * 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.database.sqlite;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.function.Consumer;
+
+/**
+ * SQL Tokenizer specialized to extract tokens from SQL (snippets).
+ * <p>
+ * Based on sqlite3GetToken() in tokenzie.c in SQLite.
+ * <p>
+ * Source for v3.8.6 (which android uses): http://www.sqlite.org/src/artifact/ae45399d6252b4d7
+ * (Latest source as of now: http://www.sqlite.org/src/artifact/78c8085bc7af1922)
+ * <p>
+ * Also draft spec: http://www.sqlite.org/draft/tokenreq.html
+ *
+ * @hide
+ */
+public class SQLiteTokenizer {
+    private static boolean isAlpha(char ch) {
+        return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || (ch == '_');
+    }
+
+    private static boolean isNum(char ch) {
+        return ('0' <= ch && ch <= '9');
+    }
+
+    private static boolean isAlNum(char ch) {
+        return isAlpha(ch) || isNum(ch);
+    }
+
+    private static boolean isAnyOf(char ch, String set) {
+        return set.indexOf(ch) >= 0;
+    }
+
+    private static IllegalArgumentException genException(String message, String sql) {
+        throw new IllegalArgumentException(message + " in '" + sql + "'");
+    }
+
+    private static char peek(String s, int index) {
+        return index < s.length() ? s.charAt(index) : '\0';
+    }
+
+    public static final int OPTION_NONE = 0;
+
+    /**
+     * Require that SQL contains only tokens; any comments or values will result
+     * in an exception.
+     */
+    public static final int OPTION_TOKEN_ONLY = 1 << 0;
+
+    /**
+     * Tokenize the given SQL, returning the list of each encountered token.
+     *
+     * @throws IllegalArgumentException if invalid SQL is encountered.
+     */
+    public static List<String> tokenize(@Nullable String sql, int options) {
+        final ArrayList<String> res = new ArrayList<>();
+        tokenize(sql, options, res::add);
+        return res;
+    }
+
+    /**
+     * Tokenize the given SQL, sending each encountered token to the given
+     * {@link Consumer}.
+     *
+     * @throws IllegalArgumentException if invalid SQL is encountered.
+     */
+    public static void tokenize(@Nullable String sql, int options, Consumer<String> checker) {
+        if (sql == null) {
+            return;
+        }
+        int pos = 0;
+        final int len = sql.length();
+        while (pos < len) {
+            final char ch = peek(sql, pos);
+
+            // Regular token.
+            if (isAlpha(ch)) {
+                final int start = pos;
+                pos++;
+                while (isAlNum(peek(sql, pos))) {
+                    pos++;
+                }
+                final int end = pos;
+
+                final String token = sql.substring(start, end);
+                checker.accept(token);
+
+                continue;
+            }
+
+            // Handle quoted tokens
+            if (isAnyOf(ch, "'\"`")) {
+                final int quoteStart = pos;
+                pos++;
+
+                for (;;) {
+                    pos = sql.indexOf(ch, pos);
+                    if (pos < 0) {
+                        throw genException("Unterminated quote", sql);
+                    }
+                    if (peek(sql, pos + 1) != ch) {
+                        break;
+                    }
+                    // Quoted quote char -- e.g. "abc""def" is a single string.
+                    pos += 2;
+                }
+                final int quoteEnd = pos;
+                pos++;
+
+                if (ch != '\'') {
+                    // Extract the token
+                    final String tokenUnquoted = sql.substring(quoteStart + 1, quoteEnd);
+
+                    final String token;
+
+                    // Unquote if needed. i.e. "aa""bb" -> aa"bb
+                    if (tokenUnquoted.indexOf(ch) >= 0) {
+                        token = tokenUnquoted.replaceAll(
+                                String.valueOf(ch) + ch, String.valueOf(ch));
+                    } else {
+                        token = tokenUnquoted;
+                    }
+                    checker.accept(token);
+                } else {
+                    if ((options &= OPTION_TOKEN_ONLY) != 0) {
+                        throw genException("Non-token detected", sql);
+                    }
+                }
+                continue;
+            }
+            // Handle tokens enclosed in [...]
+            if (ch == '[') {
+                final int quoteStart = pos;
+                pos++;
+
+                pos = sql.indexOf(']', pos);
+                if (pos < 0) {
+                    throw genException("Unterminated quote", sql);
+                }
+                final int quoteEnd = pos;
+                pos++;
+
+                final String token = sql.substring(quoteStart + 1, quoteEnd);
+
+                checker.accept(token);
+                continue;
+            }
+            if ((options &= OPTION_TOKEN_ONLY) != 0) {
+                throw genException("Non-token detected", sql);
+            }
+
+            // Detect comments.
+            if (ch == '-' && peek(sql, pos + 1) == '-') {
+                pos += 2;
+                pos = sql.indexOf('\n', pos);
+                if (pos < 0) {
+                    // We disallow strings ending in an inline comment.
+                    throw genException("Unterminated comment", sql);
+                }
+                pos++;
+
+                continue;
+            }
+            if (ch == '/' && peek(sql, pos + 1) == '*') {
+                pos += 2;
+                pos = sql.indexOf("*/", pos);
+                if (pos < 0) {
+                    throw genException("Unterminated comment", sql);
+                }
+                pos += 2;
+
+                continue;
+            }
+
+            // Semicolon is never allowed.
+            if (ch == ';') {
+                throw genException("Semicolon is not allowed", sql);
+            }
+
+            // For this purpose, we can simply ignore other characters.
+            // (Note it doesn't handle the X'' literal properly and reports this X as a token,
+            // but that should be fine...)
+            pos++;
+        }
+    }
+
+    /**
+     * Test if given token is a
+     * <a href="https://www.sqlite.org/lang_keywords.html">SQLite reserved
+     * keyword</a>.
+     */
+    public static boolean isKeyword(@NonNull String token) {
+        switch (token.toUpperCase(Locale.US)) {
+            case "ABORT": case "ACTION": case "ADD": case "AFTER":
+            case "ALL": case "ALTER": case "ANALYZE": case "AND":
+            case "AS": case "ASC": case "ATTACH": case "AUTOINCREMENT":
+            case "BEFORE": case "BEGIN": case "BETWEEN": case "BINARY":
+            case "BY": case "CASCADE": case "CASE": case "CAST":
+            case "CHECK": case "COLLATE": case "COLUMN": case "COMMIT":
+            case "CONFLICT": case "CONSTRAINT": case "CREATE": case "CROSS":
+            case "CURRENT": case "CURRENT_DATE": case "CURRENT_TIME": case "CURRENT_TIMESTAMP":
+            case "DATABASE": case "DEFAULT": case "DEFERRABLE": case "DEFERRED":
+            case "DELETE": case "DESC": case "DETACH": case "DISTINCT":
+            case "DO": case "DROP": case "EACH": case "ELSE":
+            case "END": case "ESCAPE": case "EXCEPT": case "EXCLUDE":
+            case "EXCLUSIVE": case "EXISTS": case "EXPLAIN": case "FAIL":
+            case "FILTER": case "FOLLOWING": case "FOR": case "FOREIGN":
+            case "FROM": case "FULL": case "GLOB": case "GROUP":
+            case "GROUPS": case "HAVING": case "IF": case "IGNORE":
+            case "IMMEDIATE": case "IN": case "INDEX": case "INDEXED":
+            case "INITIALLY": case "INNER": case "INSERT": case "INSTEAD":
+            case "INTERSECT": case "INTO": case "IS": case "ISNULL":
+            case "JOIN": case "KEY": case "LEFT": case "LIKE":
+            case "LIMIT": case "MATCH": case "NATURAL": case "NO":
+            case "NOCASE": case "NOT": case "NOTHING": case "NOTNULL":
+            case "NULL": case "OF": case "OFFSET": case "ON":
+            case "OR": case "ORDER": case "OTHERS": case "OUTER":
+            case "OVER": case "PARTITION": case "PLAN": case "PRAGMA":
+            case "PRECEDING": case "PRIMARY": case "QUERY": case "RAISE":
+            case "RANGE": case "RECURSIVE": case "REFERENCES": case "REGEXP":
+            case "REINDEX": case "RELEASE": case "RENAME": case "REPLACE":
+            case "RESTRICT": case "RIGHT": case "ROLLBACK": case "ROW":
+            case "ROWS": case "RTRIM": case "SAVEPOINT": case "SELECT":
+            case "SET": case "TABLE": case "TEMP": case "TEMPORARY":
+            case "THEN": case "TIES": case "TO": case "TRANSACTION":
+            case "TRIGGER": case "UNBOUNDED": case "UNION": case "UNIQUE":
+            case "UPDATE": case "USING": case "VACUUM": case "VALUES":
+            case "VIEW": case "VIRTUAL": case "WHEN": case "WHERE":
+            case "WINDOW": case "WITH": case "WITHOUT":
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Test if given token is a
+     * <a href="https://www.sqlite.org/lang_corefunc.html">SQLite reserved
+     * function</a>.
+     */
+    public static boolean isFunction(@NonNull String token) {
+        switch (token.toLowerCase(Locale.US)) {
+            case "abs": case "avg": case "char": case "coalesce":
+            case "count": case "glob": case "group_concat": case "hex":
+            case "ifnull": case "instr": case "length": case "like":
+            case "likelihood": case "likely": case "lower": case "ltrim":
+            case "max": case "min": case "nullif": case "random":
+            case "randomblob": case "replace": case "round": case "rtrim":
+            case "substr": case "sum": case "total": case "trim":
+            case "typeof": case "unicode": case "unlikely": case "upper":
+            case "zeroblob":
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Test if given token is a
+     * <a href="https://www.sqlite.org/datatype3.html">SQLite reserved type</a>.
+     */
+    public static boolean isType(@NonNull String token) {
+        switch (token.toUpperCase(Locale.US)) {
+            case "INT": case "INTEGER": case "TINYINT": case "SMALLINT":
+            case "MEDIUMINT": case "BIGINT": case "INT2": case "INT8":
+            case "CHARACTER": case "VARCHAR": case "NCHAR": case "NVARCHAR":
+            case "TEXT": case "CLOB": case "BLOB": case "REAL":
+            case "DOUBLE": case "FLOAT": case "NUMERIC": case "DECIMAL":
+            case "BOOLEAN": case "DATE": case "DATETIME":
+                return true;
+            default:
+                return false;
+        }
+    }
+}
diff --git a/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl b/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
index d22e7e2..62d727c 100644
--- a/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl
@@ -22,5 +22,5 @@
  * @hide
  */
 oneway interface IBiometricEnabledOnKeyguardCallback {
-    void onChanged(in BiometricSourceType type, boolean enabled);
+    void onChanged(in BiometricSourceType type, boolean enabled, int userId);
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index 623d5ec..f4fd1b6 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -369,6 +369,33 @@
         public boolean areModificationsExcluded() {
             return mExcludeModifications;
         }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mIdentifierTypes, mIdentifiers, mIncludeCategories,
+                    mExcludeModifications);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (!(obj instanceof Filter)) return false;
+            Filter other = (Filter) obj;
+
+            if (mIncludeCategories != other.mIncludeCategories) return false;
+            if (mExcludeModifications != other.mExcludeModifications) return false;
+            if (!Objects.equals(mIdentifierTypes, other.mIdentifierTypes)) return false;
+            if (!Objects.equals(mIdentifiers, other.mIdentifiers)) return false;
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "Filter [mIdentifierTypes=" + mIdentifierTypes
+                    + ", mIdentifiers=" + mIdentifiers
+                    + ", mIncludeCategories=" + mIncludeCategories
+                    + ", mExcludeModifications=" + mExcludeModifications + "]";
+        }
     }
 
     /**
@@ -436,5 +463,24 @@
         public @NonNull Set<ProgramSelector.Identifier> getRemoved() {
             return mRemoved;
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (!(obj instanceof Chunk)) return false;
+            Chunk other = (Chunk) obj;
+
+            if (mPurge != other.mPurge) return false;
+            if (mComplete != other.mComplete) return false;
+            if (!Objects.equals(mModified, other.mModified)) return false;
+            if (!Objects.equals(mRemoved, other.mRemoved)) return false;
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "Chunk [mPurge=" + mPurge + ", mComplete=" + mComplete
+                    + ", mModified=" + mModified + ", mRemoved=" + mRemoved + "]";
+        }
     }
 }
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index b60c136..c135c8a 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -258,6 +258,11 @@
     private final Bundle mBundle;
 
     @Override
+    public int hashCode() {
+        return mBundle.hashCode();
+    }
+
+    @Override
     public boolean equals(Object obj) {
         if (this == obj) return true;
         if (!(obj instanceof RadioMetadata)) return false;
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index ae421a4..87c7118 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -48,6 +48,7 @@
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -481,17 +482,39 @@
      * For example, given an incoming template matching B, and the currently
      * active merge set [A,B], we'd return a new template that primarily matches
      * A, but also matches B.
+     * TODO: remove and use {@link #normalize(NetworkTemplate, List)}.
      */
     @UnsupportedAppUsage
     public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) {
-        if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) {
-            // Requested template subscriber is part of the merge group; return
-            // a template that matches all merged subscribers.
-            return new NetworkTemplate(template.mMatchRule, merged[0], merged,
-                    template.mNetworkId);
-        } else {
-            return template;
+        return normalize(template, Arrays.<String[]>asList(merged));
+    }
+
+    /**
+     * Examine the given template and normalize if it refers to a "merged"
+     * mobile subscriber. We pick the "lowest" merged subscriber as the primary
+     * for key purposes, and expand the template to match all other merged
+     * subscribers.
+     *
+     * There can be multiple merged subscriberIds for multi-SIM devices.
+     *
+     * <p>
+     * For example, given an incoming template matching B, and the currently
+     * active merge set [A,B], we'd return a new template that primarily matches
+     * A, but also matches B.
+     */
+    public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) {
+        if (!template.isMatchRuleMobile()) return template;
+
+        for (String[] merged : mergedList) {
+            if (ArrayUtils.contains(merged, template.mSubscriberId)) {
+                // Requested template subscriber is part of the merge group; return
+                // a template that matches all merged subscribers.
+                return new NetworkTemplate(template.mMatchRule, merged[0], merged,
+                        template.mNetworkId);
+            }
         }
+
+        return template;
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 9f4118e..b3125d8 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1191,7 +1191,7 @@
         ArrayList<Partition> partitions = new ArrayList();
 
         String[] names = new String[] {
-            "bootimage", "odm", "product", "product_services", Partition.PARTITION_NAME_SYSTEM,
+            "bootimage", "odm", "product", "system_ext", Partition.PARTITION_NAME_SYSTEM,
             "vendor"
         };
         for (String name : names) {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 0ee9a11..3462d1f 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -54,7 +54,7 @@
     private static final String ENV_ODM_ROOT = "ODM_ROOT";
     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
     private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
-    private static final String ENV_PRODUCT_SERVICES_ROOT = "PRODUCT_SERVICES_ROOT";
+    private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT";
 
     /** {@hide} */
     public static final String DIR_ANDROID = "Android";
@@ -77,8 +77,8 @@
     private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
     private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
-    private static final File DIR_PRODUCT_SERVICES_ROOT = getDirectory(ENV_PRODUCT_SERVICES_ROOT,
-                                                           "/product_services");
+    private static final File DIR_SYSTEM_EXT_ROOT = getDirectory(ENV_SYSTEM_EXT_ROOT,
+                                                           "/system_ext");
 
     @UnsupportedAppUsage
     private static UserEnvironment sCurrentUser;
@@ -222,11 +222,26 @@
      * Return root directory of the "product_services" partition holding middleware
      * services if any. If present, the partition is mounted read-only.
      *
+     * @deprecated This directory is not guaranteed to exist.
+     *             Its name is changed to "system_ext" because the partition's purpose is changed.
+     *             {@link #getSystemExtDirectory()}
      * @hide
      */
     @SystemApi
+    @Deprecated
     public static @NonNull File getProductServicesDirectory() {
-        return DIR_PRODUCT_SERVICES_ROOT;
+        return getDirectory("PRODUCT_SERVICES_ROOT", "/product_services");
+    }
+
+    /**
+     * Return root directory of the "system_ext" partition holding system partition's extension
+     * If present, the partition is mounted read-only.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static @NonNull File getSystemExtDirectory() {
+        return DIR_SYSTEM_EXT_ROOT;
     }
 
     /**
diff --git a/core/java/android/os/RedactingFileDescriptor.java b/core/java/android/os/RedactingFileDescriptor.java
index 4e5eaac..a1ed214 100644
--- a/core/java/android/os/RedactingFileDescriptor.java
+++ b/core/java/android/os/RedactingFileDescriptor.java
@@ -35,7 +35,7 @@
 
 /**
  * Variant of {@link FileDescriptor} that allows its creator to specify regions
- * that should be redacted (appearing as zeros to the reader).
+ * that should be redacted.
  *
  * @hide
  */
@@ -44,13 +44,16 @@
     private static final boolean DEBUG = true;
 
     private volatile long[] mRedactRanges;
+    private volatile long[] mFreeOffsets;
 
     private FileDescriptor mInner = null;
     private ParcelFileDescriptor mOuter = null;
 
-    private RedactingFileDescriptor(Context context, File file, int mode, long[] redactRanges)
+    private RedactingFileDescriptor(
+            Context context, File file, int mode, long[] redactRanges, long[] freeOffsets)
             throws IOException {
         mRedactRanges = checkRangesArgument(redactRanges);
+        mFreeOffsets = freeOffsets;
 
         try {
             try {
@@ -88,13 +91,17 @@
      *
      * @param file The underlying file to open.
      * @param mode The {@link ParcelFileDescriptor} mode to open with.
-     * @param redactRanges List of file offsets that should be redacted, stored
+     * @param redactRanges List of file ranges that should be redacted, stored
      *            as {@code [start1, end1, start2, end2, ...]}. Start values are
      *            inclusive and end values are exclusive.
+     * @param freePositions List of file offsets at which the four byte value 'free' should be
+     *            written instead of zeros within parts of the file covered by {@code redactRanges}.
+     *            Non-redacted bytes will not be modified even if covered by a 'free'. This is
+     *            useful for overwriting boxes in ISOBMFF files with padding data.
      */
     public static ParcelFileDescriptor open(Context context, File file, int mode,
-            long[] redactRanges) throws IOException {
-        return new RedactingFileDescriptor(context, file, mode, redactRanges).mOuter;
+            long[] redactRanges, long[] freePositions) throws IOException {
+        return new RedactingFileDescriptor(context, file, mode, redactRanges, freePositions).mOuter;
     }
 
     /**
@@ -169,6 +176,15 @@
                 for (long j = start; j < end; j++) {
                     data[(int) (j - offset)] = 0;
                 }
+                // Overwrite data at 'free' offsets within the redaction ranges.
+                for (long freeOffset : mFreeOffsets) {
+                    final long freeEnd = freeOffset + 4;
+                    final long redactFreeStart = Math.max(freeOffset, start);
+                    final long redactFreeEnd = Math.min(freeEnd, end);
+                    for (long j = redactFreeStart; j < redactFreeEnd; j++) {
+                        data[(int) (j - offset)] = (byte) "free".charAt((int) (j - freeOffset));
+                    }
+                }
             }
             return n;
         }
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 57a8801..0540e36 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -62,7 +62,7 @@
 
         mMemoryRegistration = new MemoryRegistration(mSize);
         mCleaner = Cleaner.create(mFileDescriptor,
-                new Closer(mFileDescriptor, mMemoryRegistration));
+                new Closer(mFileDescriptor.getInt$(), mMemoryRegistration));
     }
 
     /**
@@ -259,6 +259,9 @@
             mCleaner.clean();
             mCleaner = null;
         }
+
+        // Cleaner.clean doesn't clear the value of the file descriptor.
+        mFileDescriptor.setInt$(-1);
     }
 
     @Override
@@ -290,10 +293,10 @@
      * Cleaner that closes the FD
      */
     private static final class Closer implements Runnable {
-        private FileDescriptor mFd;
+        private int mFd;
         private MemoryRegistration mMemoryReference;
 
-        private Closer(FileDescriptor fd, MemoryRegistration memoryReference) {
+        private Closer(int fd, MemoryRegistration memoryReference) {
             mFd = fd;
             mMemoryReference = memoryReference;
         }
@@ -301,7 +304,9 @@
         @Override
         public void run() {
             try {
-                Os.close(mFd);
+                FileDescriptor fd = new FileDescriptor();
+                fd.setInt$(mFd);
+                Os.close(fd);
             } catch (ErrnoException e) { /* swallow error */ }
             mMemoryReference.release();
             mMemoryReference = null;
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 5cf3b97..29af17a 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -21,6 +21,8 @@
 import android.os.IUpdateEngineCallback;
 import android.os.RemoteException;
 
+import java.io.FileDescriptor;
+
 /**
  * UpdateEngine handles calls to the update engine which takes care of A/B OTA
  * updates. It wraps up the update engine Binder APIs and exposes them as
@@ -312,6 +314,22 @@
     }
 
     /**
+     * Applies the payload passed as file descriptor {@code fd} instead of
+     * using the {@code file://} scheme.
+     *
+     * <p>See {@link #applyPayload(String)} for {@code offset}, {@code size} and
+     * {@code headerKeyValuePairs} parameters.
+     */
+    public void applyPayload(FileDescriptor fd, long offset, long size,
+            String[] headerKeyValuePairs) {
+        try {
+            mUpdateEngine.applyPayloadFd(fd, offset, size, headerKeyValuePairs);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Permanently cancels an in-progress update.
      *
      * <p>See {@link #resetStatus} to undo a finshed update (only available
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 9c9829f..a7fa96b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1283,6 +1283,16 @@
     }
 
     /**
+     * @hide
+     * @return Whether the device is running in a headless system user mode. It means the headless
+     * user (system user) runs system services and system UI, but is not associated with any real
+     * person. Secondary users can be created to be associated with real person.
+     */
+    public static boolean isHeadlessSystemUserMode() {
+        return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER;
+    }
+
+    /**
      * @deprecated use {@link #getUserSwitchability()} instead.
      *
      * @removed
diff --git a/core/java/android/content/pm/IOnPermissionsChangeListener.aidl b/core/java/android/permission/IOnPermissionsChangeListener.aidl
similarity index 96%
rename from core/java/android/content/pm/IOnPermissionsChangeListener.aidl
rename to core/java/android/permission/IOnPermissionsChangeListener.aidl
index 7791b50..cc52a72 100644
--- a/core/java/android/content/pm/IOnPermissionsChangeListener.aidl
+++ b/core/java/android/permission/IOnPermissionsChangeListener.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.content.pm;
+package android.permission;
 
 /**
  * Listener for changes in the permissions for installed packages.
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 3b69b12..9fa5f16 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -19,6 +19,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
+import android.permission.IOnPermissionsChangeListener;
 
 /**
  * Interface to communicate directly with the permission manager service.
@@ -39,4 +40,61 @@
     boolean addPermission(in PermissionInfo info, boolean async);
 
     void removePermission(String name);
+
+    int getPermissionFlags(String permName, String packageName, int userId);
+
+    void updatePermissionFlags(String permName, String packageName, int flagMask,
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId);
+
+    void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId);
+
+    int checkPermission(String permName, String pkgName, int userId);
+
+    int checkUidPermission(String permName, int uid);
+
+    void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
+
+    void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
+
+    List<String> getWhitelistedRestrictedPermissions(String packageName,
+            int flags, int userId);
+
+    boolean addWhitelistedRestrictedPermission(String packageName, String permName,
+            int flags, int userId);
+
+    boolean removeWhitelistedRestrictedPermission(String packageName, String permName,
+            int flags, int userId);
+
+    void grantRuntimePermission(String packageName, String permName, int userId);
+
+    void revokeRuntimePermission(String packageName, String permName, int userId);
+
+    void resetRuntimePermissions();
+
+    boolean setDefaultBrowser(String packageName, int userId);
+
+    String getDefaultBrowser(int userId);
+
+    void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);
+
+    void grantDefaultPermissionsToEnabledImsServices(in String[] packageNames, int userId);
+
+    void grantDefaultPermissionsToEnabledTelephonyDataServices(
+            in String[] packageNames, int userId);
+
+    void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+            in String[] packageNames, int userId);
+
+    void grantDefaultPermissionsToActiveLuiApp(in String packageName, int userId);
+
+    void revokeDefaultPermissionsFromLuiApps(in String[] packageNames, int userId);
+
+    void setPermissionEnforced(String permName, boolean enforced);
+
+    boolean isPermissionEnforced(String permName);
+
+    boolean shouldShowRequestPermissionRationale(String permName,
+            String packageName, int userId);
+
+    boolean isPermissionRevokedByPolicy(String permName, String packageName, int userId);
 }
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 182a2ff..42816c0 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -43,6 +43,14 @@
 @SystemApi
 @SystemService(Context.PERMISSION_SERVICE)
 public final class PermissionManager {
+    /** @hide */
+    public static final String KILL_APP_REASON_PERMISSIONS_REVOKED =
+            "permissions revoked";
+    /** @hide */
+    public static final String KILL_APP_REASON_GIDS_CHANGED =
+            "permission grant or revoke changed gids";
+
+
     /**
      * {@link android.content.pm.PackageParser} needs access without having a {@link Context}.
      *
diff --git a/core/java/android/permission/PermissionManagerInternal.java b/core/java/android/permission/PermissionManagerInternal.java
index 7167431..3134ec0 100644
--- a/core/java/android/permission/PermissionManagerInternal.java
+++ b/core/java/android/permission/PermissionManagerInternal.java
@@ -21,6 +21,10 @@
 import android.annotation.UserIdInt;
 import android.os.UserHandle;
 
+import com.android.internal.util.function.TriFunction;
+
+import java.util.function.BiFunction;
+
 /**
  * Internal interfaces to be used by other components within the system server.
  *
@@ -46,6 +50,33 @@
                 @UserIdInt int userId);
     }
 
+    /** Interface to override permission checks via composition */
+    public interface CheckPermissionDelegate {
+        /**
+         * Checks whether the given package has been granted the specified permission.
+         *
+         * @return If the package has the permission, PERMISSION_GRANTED is
+         * returned.  If it does not have the permission, PERMISSION_DENIED
+         * is returned.
+         *
+         * @see android.content.pm.PackageManager#checkPermission(String, String)
+         */
+        int checkPermission(String permName, String pkgName, int userId,
+                TriFunction<String, String, Integer, Integer> superImpl);
+
+        /**
+        /**
+         * Checks whether the given uid has been granted the specified permission.
+         *
+         * @return If the package has the permission, PERMISSION_GRANTED is
+         * returned.  If it does not have the permission, PERMISSION_DENIED
+         * is returned.
+         *
+         */
+        int checkUidPermission(String permName, int uid,
+                BiFunction<String, Integer, Integer> superImpl);
+    }
+
     /**
      * Get the state of the runtime permissions as xml file.
      *
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 2f68eb4..d862d602 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -40,7 +40,7 @@
 import android.net.Uri;
 import android.os.RemoteException;
 import android.text.format.DateUtils;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
 import android.util.Log;
 
 import com.android.internal.util.Preconditions;
@@ -1680,7 +1680,7 @@
      * <h3>Writing to Events</h3> There are further restrictions on all Updates
      * and Inserts in the Events table:
      * <ul>
-     * <li>If allDay is set to 1 eventTimezone must be {@link Time#TIMEZONE_UTC}
+     * <li>If allDay is set to 1 eventTimezone must be "UTC"
      * and the time must correspond to a midnight boundary.</li>
      * <li>Exceptions are not allowed to recur. If rrule or rdate is not empty,
      * original_id and original_sync_id must be empty.</li>
@@ -2608,9 +2608,7 @@
         @UnsupportedAppUsage
         public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) {
             if (DEBUG) {
-                Time time = new Time();
-                time.set(alarmTime);
-                String schedTime = time.format(" %a, %b %d, %Y %I:%M%P");
+                String schedTime = TimeMigrationUtils.formatMillisWithFixedFormat(alarmTime);
                 Log.d(TAG, "Schedule alarm at " + alarmTime + " " + schedTime);
             }
 
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index c65e773..1cd2d62 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -224,13 +224,21 @@
          */
         public static final int TYPE_CONTEXT_COMMITTED = 4;
 
+        /**
+         * A dataset selector was shown.
+         *
+         * <p>This event is fired whenever the autofill UI was presented to the user.</p>
+         */
+        public static final int TYPE_DATASETS_SHOWN = 5;
+
         /** @hide */
         @IntDef(prefix = { "TYPE_" }, value = {
                 TYPE_DATASET_SELECTED,
                 TYPE_DATASET_AUTHENTICATION_SELECTED,
                 TYPE_AUTHENTICATION_SELECTED,
                 TYPE_SAVE_SHOWN,
-                TYPE_CONTEXT_COMMITTED
+                TYPE_CONTEXT_COMMITTED,
+                TYPE_DATASETS_SHOWN
         })
         @Retention(RetentionPolicy.SOURCE)
         @interface EventIds{}
@@ -473,7 +481,7 @@
                 @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
                 @Nullable AutofillId[] detectedFieldIds,
                 @Nullable FieldClassification[] detectedFieldClassifications) {
-            mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED,
+            mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_DATASETS_SHOWN,
                     "eventType");
             mDatasetId = datasetId;
             mClientState = clientState;
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
index 5a14092..f7fd89d 100644
--- a/core/java/android/text/format/TimeFormatter.java
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -26,6 +26,9 @@
 import libcore.util.ZoneInfo;
 
 import java.nio.CharBuffer;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.Formatter;
 import java.util.Locale;
 import java.util.TimeZone;
@@ -86,6 +89,59 @@
     }
 
     /**
+     * The implementation of {@link TimeMigrationUtils#formatMillisWithFixedFormat(long)} for
+     * 2038-safe formatting with the pattern "%Y-%m-%d %H:%M:%S" and including the historic
+     * incorrect digit localization behavior.
+     */
+    String formatMillisWithFixedFormat(long timeMillis) {
+        // This method is deliberately not a general purpose replacement for
+        // format(String, ZoneInfo.WallTime, ZoneInfo): It hard-codes the pattern used; many of the
+        // pattern characters supported by Time.format() have unusual behavior which would make
+        // using java.time.format or similar packages difficult. It would be a lot of work to share
+        // behavior and many internal Android usecases can be covered by this common pattern
+        // behavior.
+
+        // No need to worry about overflow / underflow: long millis is representable by Instant and
+        // LocalDateTime with room to spare.
+        Instant instant = Instant.ofEpochMilli(timeMillis);
+
+        // Date/times are calculated in the current system default time zone.
+        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
+
+        // You'd think it would be as simple as:
+        // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", locale);
+        // return formatter.format(localDateTime);
+        // but we retain Time's behavior around digits.
+
+        StringBuilder stringBuilder = new StringBuilder(19);
+
+        // This effectively uses the US locale because number localization is handled separately
+        // (see below).
+        stringBuilder.append(localDateTime.getYear());
+        stringBuilder.append('-');
+        append2DigitNumber(stringBuilder, localDateTime.getMonthValue());
+        stringBuilder.append('-');
+        append2DigitNumber(stringBuilder, localDateTime.getDayOfMonth());
+        stringBuilder.append(' ');
+        append2DigitNumber(stringBuilder, localDateTime.getHour());
+        stringBuilder.append(':');
+        append2DigitNumber(stringBuilder, localDateTime.getMinute());
+        stringBuilder.append(':');
+        append2DigitNumber(stringBuilder, localDateTime.getSecond());
+
+        String result = stringBuilder.toString();
+        return localizeDigits(result);
+    }
+
+    /** Zero-pads value as needed to achieve a 2-digit number. */
+    private static void append2DigitNumber(StringBuilder builder, int value) {
+        if (value < 10) {
+            builder.append('0');
+        }
+        builder.append(value);
+    }
+
+    /**
      * Format the specified {@code wallTime} using {@code pattern}. The output is returned.
      */
     public String format(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
@@ -99,12 +155,9 @@
 
             formatInternal(pattern, wallTime, zoneInfo);
             String result = stringBuilder.toString();
-            // This behavior is the source of a bug since some formats are defined as being
-            // in ASCII and not localized.
-            if (localeData.zeroDigit != '0') {
-                result = localizeDigits(result);
-            }
-            return result;
+            // The localizeDigits() behavior is the source of a bug since some formats are defined
+            // as being in ASCII and not localized.
+            return localizeDigits(result);
         } finally {
             outputBuilder = null;
             numberFormatter = null;
@@ -112,6 +165,10 @@
     }
 
     private String localizeDigits(String s) {
+        if (localeData.zeroDigit == '0') {
+            return s;
+        }
+
         int length = s.length();
         int offsetToLocalizedDigits = localeData.zeroDigit - '0';
         StringBuilder result = new StringBuilder(length);
diff --git a/core/java/android/text/format/TimeMigrationUtils.java b/core/java/android/text/format/TimeMigrationUtils.java
new file mode 100644
index 0000000..17bac8d
--- /dev/null
+++ b/core/java/android/text/format/TimeMigrationUtils.java
@@ -0,0 +1,40 @@
+/*
+ * 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.text.format;
+
+/**
+ * Logic to ease migration away from {@link Time} in Android internal code. {@link Time} is
+ * afflicted by the Y2038 issue and deprecated. The methods here are intended to allow minimal
+ * changes to classes that use {@link Time} for common behavior.
+ *
+ * @hide
+ */
+public class TimeMigrationUtils {
+
+    private TimeMigrationUtils() {}
+
+    /**
+     * A Y2038-safe replacement for various users of the {@link Time#format(String)} with the
+     * pattern "%Y-%m-%d %H:%M:%S". Note, this method retains the unusual localization behavior
+     * originally implemented by Time, which can lead to non-latin numbers being produced if the
+     * default locale does not use latin numbers.
+     */
+    public static String formatMillisWithFixedFormat(long timeMillis) {
+        // Delegate to TimeFormatter so that the unusual localization / threading behavior can be
+        // reused.
+        return new TimeFormatter().formatMillisWithFixedFormat(timeMillis);
+    }
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 5a9ab38..6aef5a5 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -40,6 +40,7 @@
     public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
     public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
+    public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
 
     private static final Map<String, String> DEFAULT_FLAGS;
 
@@ -56,6 +57,7 @@
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
         DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
         DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true");
+        DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
     }
 
     /**
diff --git a/core/java/android/util/proto/ProtoInputStream.java b/core/java/android/util/proto/ProtoInputStream.java
index c290dff..24e7d2b 100644
--- a/core/java/android/util/proto/ProtoInputStream.java
+++ b/core/java/android/util/proto/ProtoInputStream.java
@@ -253,12 +253,14 @@
     }
 
     /**
-     * Attempt to guess the next field. If there is a match, the field data will be ready to read.
-     * If there is no match, nextField will need to be called to get the field number
+     * Reads the tag of the next field from the stream. If previous field value was not read, its
+     * data will be skipped over. If {@code fieldId} matches the next field ID, the field data will
+     * be ready to read. If it does not match, {@link #nextField()} or {@link #nextField(long)} will
+     * need to be called again before the field data can be read.
      *
      * @return true if fieldId matches the next field, false if not
      */
-    public boolean isNextField(long fieldId) throws IOException {
+    public boolean nextField(long fieldId) throws IOException {
         if (nextField() == (int) fieldId) {
             return true;
         }
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 4b92968..203b087 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -38,7 +38,6 @@
 import android.text.style.ClickableSpan;
 import android.util.LongSparseArray;
 import android.util.Slog;
-import android.view.View.AttachInfo;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeIdManager;
@@ -903,38 +902,6 @@
                 }
             }
         }
-
-        if (spec != null) {
-            AttachInfo attachInfo = mViewRootImpl.mAttachInfo;
-            if (attachInfo.mDisplay == null) {
-                return;
-            }
-
-            final float scale = attachInfo.mApplicationScale * spec.scale;
-
-            Rect visibleWinFrame = mTempRect1;
-            visibleWinFrame.left = (int) (attachInfo.mWindowLeft * scale + spec.offsetX);
-            visibleWinFrame.top = (int) (attachInfo.mWindowTop * scale + spec.offsetY);
-            visibleWinFrame.right = (int) (visibleWinFrame.left + mViewRootImpl.mWidth * scale);
-            visibleWinFrame.bottom = (int) (visibleWinFrame.top + mViewRootImpl.mHeight * scale);
-
-            attachInfo.mDisplay.getRealSize(mTempPoint);
-            final int displayWidth = mTempPoint.x;
-            final int displayHeight = mTempPoint.y;
-
-            Rect visibleDisplayFrame = mTempRect2;
-            visibleDisplayFrame.set(0, 0, displayWidth, displayHeight);
-
-            if (!visibleWinFrame.intersect(visibleDisplayFrame)) {
-                // If there's no intersection with display, set visibleWinFrame empty.
-                visibleDisplayFrame.setEmpty();
-            }
-
-            if (!visibleWinFrame.intersects(boundsInScreen.left, boundsInScreen.top,
-                    boundsInScreen.right, boundsInScreen.bottom)) {
-                info.setVisibleToUser(false);
-            }
-        }
     }
 
     private boolean shouldApplyAppScaleAndMagnificationSpec(float appScale,
@@ -948,8 +915,10 @@
         try {
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             adjustBoundsInScreenIfNeeded(infos);
-            applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
+            // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
+            // then impact the visibility result, we need to adjust visibility before apply scale.
             adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
+            applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
             callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
             if (infos != null) {
                 infos.clear();
@@ -967,8 +936,10 @@
         try {
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             adjustBoundsInScreenIfNeeded(info);
-            applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+            // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
+            // then impact the visibility result, we need to adjust visibility before apply scale.
             adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+            applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
             callback.setFindAccessibilityNodeInfoResult(info, interactionId);
         } catch (RemoteException re) {
                 /* ignore - the other side will time out */
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 715181f..797c128 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -319,18 +319,23 @@
             sortedBounds[i] = ZERO_RECT;
         }
         if (safeInsets != null && boundingRects != null) {
+            // There is at most one non-functional area per short edge of the device, but none
+            // on the long edges, so either a) safeInsets.top and safeInsets.bottom is 0, or
+            // b) safeInsets.left and safeInset.right is 0.
+            final boolean topBottomInset = safeInsets.top > 0 || safeInsets.bottom > 0;
             for (Rect bound : boundingRects) {
-                // There is at most one non-functional area per short edge of the device, but none
-                // on the long edges, so either safeInsets.right or safeInsets.bottom must be 0.
-                // TODO(b/117199965): Refine the logic to handle edge cases.
-                if (bound.left == 0) {
-                    sortedBounds[BOUNDS_POSITION_LEFT] = bound;
-                } else if (bound.top == 0) {
-                    sortedBounds[BOUNDS_POSITION_TOP] = bound;
-                } else if (safeInsets.right > 0) {
-                    sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
-                } else if (safeInsets.bottom > 0) {
-                    sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+                if (topBottomInset) {
+                    if (bound.top == 0) {
+                        sortedBounds[BOUNDS_POSITION_TOP] = bound;
+                    } else {
+                        sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+                    }
+                } else {
+                    if (bound.left == 0) {
+                        sortedBounds[BOUNDS_POSITION_LEFT] = bound;
+                    } else {
+                        sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
+                    }
                 }
             }
         }
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 956161a..955be8d 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -77,23 +77,9 @@
     void hideCurrentInputMethod();
 
     /**
-     * Set a state for controller whether would like to cancel recents animations with deferred
-     * task screenshot presentation.
-     *
-     * When we cancel the recents animation due to a stack order change, we can't just cancel it
-     * immediately as it would lead to a flicker in Launcher if we just remove the task from the
-     * leash. Instead we screenshot the previous task and replace the child of the leash with the
-     * screenshot, so that Launcher can still control the leash lifecycle & make the next app
-     * transition animate smoothly without flickering.
-     *
-     * @param screenshot When set {@code true}, means recents animation will be canceled when the
-     *                   next app launch. System will take previous task's screenshot when the next
-     *                   app transition starting, and skip previous task's animation.
-     *                   Set {@code false} means will not take screenshot & skip animation
-     *                   for previous task.
-     *
-     * @see #cleanupScreenshot()
-     * @see IRecentsAnimationRunner#onCancelled
+     * This call is deprecated, use #setDeferCancelUntilNextTransition() instead
+     * TODO(138144750): Remove this method once there are no callers
+     * @deprecated
      */
     void setCancelWithDeferredScreenshot(boolean screenshot);
 
@@ -104,4 +90,34 @@
      * @see {@link IRecentsAnimationRunner#onAnimationCanceled}
      */
     void cleanupScreenshot();
+
+    /**
+     * Set a state for controller whether would like to cancel recents animations with deferred
+     * task screenshot presentation.
+     *
+     * When we cancel the recents animation due to a stack order change, we can't just cancel it
+     * immediately as it would lead to a flicker in Launcher if we just remove the task from the
+     * leash. Instead we screenshot the previous task and replace the child of the leash with the
+     * screenshot, so that Launcher can still control the leash lifecycle & make the next app
+     * transition animate smoothly without flickering.
+     *
+     * @param defer When set {@code true}, means that the recents animation will defer canceling the
+     *              animation when a stack order change is triggered until the subsequent app
+     *              transition start and skip previous task's animation.
+     *              When set to {@code false}, means that the recents animation will be canceled
+     *              immediately when the stack order changes.
+     * @param screenshot When set {@code true}, means that the system will take previous task's
+     *                   screenshot and replace the contents of the leash with it when the next app
+     *                   transition starting. The runner must call #cleanupScreenshot() to end the
+     *                   recents animation.
+     *                   When set to {@code false}, means that the system will simply wait for the
+     *                   next app transition start to immediately cancel the recents animation. This
+     *                   can be useful when you want an immediate transition into a state where the
+     *                   task is shown in the home/recents activity (without waiting for a
+     *                   screenshot).
+     *
+     * @see #cleanupScreenshot()
+     * @see IRecentsAnimationRunner#onCancelled
+     */
+    void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot);
 }
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 9c652a8..6cda60c 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -36,7 +36,7 @@
      * @param deferredWithScreenshot If set to {@code true}, the contents of the task will be
      *                               replaced with a screenshot, such that the runner's leash is
      *                               still active. As soon as the runner doesn't need the leash
-     *                               anymore, it can call
+     *                               anymore, it must call
      *                               {@link IRecentsAnimationController#cleanupScreenshot).
      *
      * @see {@link RecentsAnimationController#cleanupScreenshot}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 4bfd138..f73f28a 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -308,7 +308,7 @@
     /**
      * Called when the system gesture exclusion has changed.
      */
-    void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects);
+    oneway void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects);
 
     /**
     * Request the server to call setInputWindowInfo on a given Surface, and return
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 9cc6b28..1a66898 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -96,7 +96,7 @@
  * artifacts may occur on previous versions of the platform when its window is
  * positioned asynchronously.</p>
  */
-public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback {
+public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback {
     private static final String TAG = "SurfaceView";
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_POSITION = false;
@@ -227,9 +227,7 @@
         mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
     }
 
-    /** @hide */
-    @Override
-    public void windowStopped(boolean stopped) {
+    private void setWindowStopped(boolean stopped) {
         mWindowStopped = stopped;
         updateRequestedVisibility();
         updateSurface();
@@ -239,7 +237,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
-        getViewRootImpl().addWindowStoppedCallback(this);
+        getViewRootImpl().addSurfaceChangedCallback(this);
         mWindowStopped = false;
 
         mViewVisibility = getVisibility() == VISIBLE;
@@ -459,7 +457,7 @@
         // the lifecycle. Instead of attaching it to a view, he/she can just pass
         // the SurfaceHolder forward, most live wallpapers do it.
         if (viewRoot != null) {
-            viewRoot.removeWindowStoppedCallback(this);
+            viewRoot.removeSurfaceChangedCallback(this);
         }
 
         mAttachedToWindow = false;
@@ -1349,4 +1347,33 @@
     public SurfaceControl getSurfaceControl() {
         return mSurfaceControl;
     }
+
+    /**
+     * Set window stopped to false and update surface visibility when ViewRootImpl surface is
+     * created.
+     * @hide
+     */
+    @Override
+    public void surfaceCreated(SurfaceControl.Transaction t) {
+        setWindowStopped(false);
+    }
+
+    /**
+     * Set window stopped to true and update surface visibility when ViewRootImpl surface is
+     * destroyed.
+     * @hide
+     */
+    @Override
+    public void surfaceDestroyed() {
+        setWindowStopped(true);
+    }
+
+    /**
+     * Called when a valid ViewRootImpl surface is replaced by another valid surface.
+     * @hide
+     */
+    @Override
+    public void surfaceReplaced(SurfaceControl.Transaction t) {
+
+    }
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 613ddcf..354cc96 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -478,6 +478,12 @@
     private final SurfaceControl mSurfaceControl = new SurfaceControl();
 
     /**
+     * Transaction object that can be used to synchronize child SurfaceControl changes with
+     * ViewRootImpl SurfaceControl changes by the server. The object is passed along with
+     * the SurfaceChangedCallback.
+     */
+    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.
@@ -1541,19 +1547,6 @@
         mIsAmbientMode = ambient;
     }
 
-    interface WindowStoppedCallback {
-        public void windowStopped(boolean stopped);
-    }
-    private final ArrayList<WindowStoppedCallback> mWindowStoppedCallbacks =  new ArrayList<>();
-
-    void addWindowStoppedCallback(WindowStoppedCallback c) {
-        mWindowStoppedCallbacks.add(c);
-    }
-
-    void removeWindowStoppedCallback(WindowStoppedCallback c) {
-        mWindowStoppedCallbacks.remove(c);
-    }
-
     void setWindowStopped(boolean stopped) {
         checkThread();
         if (mStopped != stopped) {
@@ -1570,14 +1563,11 @@
                 if (renderer != null) {
                     renderer.destroyHardwareResources(mView);
                 }
-            }
 
-            for (int i = 0; i < mWindowStoppedCallbacks.size(); i++) {
-                mWindowStoppedCallbacks.get(i).windowStopped(stopped);
-            }
-
-            if (mStopped) {
-                if (mSurfaceHolder != null && mSurface.isValid()) {
+                if (mSurface.isValid()) {
+                    if (mSurfaceHolder != null) {
+                        notifyHolderSurfaceDestroyed();
+                    }
                     notifySurfaceDestroyed();
                 }
                 destroySurface();
@@ -1585,6 +1575,46 @@
         }
     }
 
+    /** Register callbacks to be notified when the ViewRootImpl surface changes. */
+    interface SurfaceChangedCallback {
+        void surfaceCreated(Transaction t);
+        void surfaceReplaced(Transaction t);
+        void surfaceDestroyed();
+    }
+
+    private final ArrayList<SurfaceChangedCallback> mSurfaceChangedCallbacks = new ArrayList<>();
+    void addSurfaceChangedCallback(SurfaceChangedCallback c) {
+        mSurfaceChangedCallbacks.add(c);
+    }
+
+    void removeSurfaceChangedCallback(SurfaceChangedCallback c) {
+        mSurfaceChangedCallbacks.remove(c);
+    }
+
+    private void notifySurfaceCreated() {
+        for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
+            mSurfaceChangedCallbacks.get(i).surfaceCreated(mSurfaceChangedTransaction);
+        }
+    }
+
+    /**
+     * Notify listeners when the ViewRootImpl surface has been replaced. This callback will not be
+     * called if a new surface is created, only if the valid surface has been replaced with another
+     * valid surface.
+     */
+    private void notifySurfaceReplaced() {
+        for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
+            mSurfaceChangedCallbacks.get(i).surfaceReplaced(mSurfaceChangedTransaction);
+        }
+    }
+
+    private void notifySurfaceDestroyed() {
+        for (int i = 0; i < mSurfaceChangedCallbacks.size(); i++) {
+            mSurfaceChangedCallbacks.get(i).surfaceDestroyed();
+        }
+    }
+
+
     /**
      * 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.
@@ -1984,7 +2014,7 @@
         mIsInTraversal = true;
         mWillDrawSoon = true;
         boolean windowSizeMayChange = false;
-        boolean surfaceChanged = false;
+        final boolean windowAttributesChanged = mWindowAttributesChanged;
         WindowManager.LayoutParams lp = mWindowAttributes;
 
         int desiredWindowWidth;
@@ -2003,7 +2033,6 @@
         WindowManager.LayoutParams params = null;
         if (mWindowAttributesChanged) {
             mWindowAttributesChanged = false;
-            surfaceChanged = true;
             params = lp;
         }
         CompatibilityInfo compatibilityInfo =
@@ -2244,6 +2273,10 @@
         final boolean isViewVisible = viewVisibility == View.VISIBLE;
         final boolean windowRelayoutWasForced = mForceNextWindowRelayout;
         boolean surfaceSizeChanged = false;
+        boolean surfaceCreated = false;
+        boolean surfaceDestroyed = false;
+        /* True if surface generation id changes. */
+        boolean surfaceReplaced = false;
 
         if (mFirst || windowShouldResize || insetsChanged ||
                 viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
@@ -2325,10 +2358,14 @@
                 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
                 surfaceSizeChanged = (relayoutResult
                         & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
-                surfaceChanged |= surfaceSizeChanged;
                 final boolean alwaysConsumeSystemBarsChanged =
                         mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
                 final boolean colorModeChanged = hasColorModeChanged(lp.getColorMode());
+                surfaceCreated = !hadSurface && mSurface.isValid();
+                surfaceDestroyed = hadSurface && !mSurface.isValid();
+                surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId())
+                        && mSurface.isValid();
+
                 if (contentInsetsChanged) {
                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
                     if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
@@ -2383,33 +2420,32 @@
                             lp.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
                 }
 
-                if (!hadSurface) {
-                    if (mSurface.isValid()) {
-                        // If we are creating a new surface, then we need to
-                        // completely redraw it.
-                        mFullRedrawNeeded = true;
-                        mPreviousTransparentRegion.setEmpty();
+                if (surfaceCreated) {
+                    // If we are creating a new surface, then we need to
+                    // completely redraw it.
+                    mFullRedrawNeeded = true;
+                    mPreviousTransparentRegion.setEmpty();
 
-                        // Only initialize up-front if transparent regions are not
-                        // requested, otherwise defer to see if the entire window
-                        // will be transparent
-                        if (mAttachInfo.mThreadedRenderer != null) {
-                            try {
-                                hwInitialized = mAttachInfo.mThreadedRenderer.initialize(
-                                        mSurface);
-                                if (hwInitialized && (host.mPrivateFlags
-                                        & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
-                                    // Don't pre-allocate if transparent regions
-                                    // are requested as they may not be needed
-                                    mAttachInfo.mThreadedRenderer.allocateBuffers();
-                                }
-                            } catch (OutOfResourcesException e) {
-                                handleOutOfResourcesException(e);
-                                return;
+                    // Only initialize up-front if transparent regions are not
+                    // requested, otherwise defer to see if the entire window
+                    // will be transparent
+                    if (mAttachInfo.mThreadedRenderer != null) {
+                        try {
+                            hwInitialized = mAttachInfo.mThreadedRenderer.initialize(
+                                    mSurface);
+                            if (hwInitialized && (host.mPrivateFlags
+                                    & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
+                                // Don't pre-allocate if transparent regions
+                                // are requested as they may not be needed
+                                mAttachInfo.mThreadedRenderer.allocateBuffers();
                             }
+                        } catch (OutOfResourcesException e) {
+                            handleOutOfResourcesException(e);
+                            return;
                         }
                     }
-                } else if (!mSurface.isValid()) {
+                    notifySurfaceCreated();
+                } else if (surfaceDestroyed) {
                     // If the surface has been removed, then reset the scroll
                     // positions.
                     if (mLastScrolledFocus != null) {
@@ -2427,10 +2463,12 @@
                             mAttachInfo.mThreadedRenderer.isEnabled()) {
                         mAttachInfo.mThreadedRenderer.destroy();
                     }
-                } else if ((surfaceGenerationId != mSurface.getGenerationId()
+                    notifySurfaceDestroyed();
+                } else if ((surfaceReplaced
                         || surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
                         && mSurfaceHolder == null
-                        && mAttachInfo.mThreadedRenderer != null) {
+                        && mAttachInfo.mThreadedRenderer != null
+                        && mSurface.isValid()) {
                     mFullRedrawNeeded = true;
                     try {
                         // Need to do updateSurface (which leads to CanvasContext::setSurface and
@@ -2448,6 +2486,10 @@
                     }
                 }
 
+                if (!surfaceCreated && surfaceReplaced) {
+                    notifySurfaceReplaced();
+                }
+
                 final boolean freeformResizing = (relayoutResult
                         & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
                 final boolean dockedResizing = (relayoutResult
@@ -2503,31 +2545,32 @@
                 }
                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
                 mSurfaceHolder.mSurfaceLock.unlock();
-                if (mSurface.isValid()) {
-                    if (!hadSurface) {
-                        mSurfaceHolder.ungetCallbacks();
+                if (surfaceCreated) {
+                    mSurfaceHolder.ungetCallbacks();
 
-                        mIsCreating = true;
-                        SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
-                        if (callbacks != null) {
-                            for (SurfaceHolder.Callback c : callbacks) {
-                                c.surfaceCreated(mSurfaceHolder);
-                            }
+                    mIsCreating = true;
+                    SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
+                    if (callbacks != null) {
+                        for (SurfaceHolder.Callback c : callbacks) {
+                            c.surfaceCreated(mSurfaceHolder);
                         }
-                        surfaceChanged = true;
                     }
-                    if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
-                        SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
-                        if (callbacks != null) {
-                            for (SurfaceHolder.Callback c : callbacks) {
-                                c.surfaceChanged(mSurfaceHolder, lp.format,
-                                        mWidth, mHeight);
-                            }
+                }
+
+                if ((surfaceCreated || surfaceReplaced || surfaceSizeChanged
+                        || windowAttributesChanged) && mSurface.isValid()) {
+                    SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
+                    if (callbacks != null) {
+                        for (SurfaceHolder.Callback c : callbacks) {
+                            c.surfaceChanged(mSurfaceHolder, lp.format,
+                                    mWidth, mHeight);
                         }
                     }
                     mIsCreating = false;
-                } else if (hadSurface) {
-                    notifySurfaceDestroyed();
+                }
+
+                if (surfaceDestroyed) {
+                    notifyHolderSurfaceDestroyed();
                     mSurfaceHolder.mSurfaceLock.lock();
                     try {
                         mSurfaceHolder.mSurface = new Surface();
@@ -2841,7 +2884,7 @@
         }
     }
 
-    private void notifySurfaceDestroyed() {
+    private void notifyHolderSurfaceDestroyed() {
         mSurfaceHolder.ungetCallbacks();
         SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
         if (callbacks != null) {
@@ -3447,7 +3490,7 @@
     private void reportDrawFinished() {
         try {
             mDrawsNeededToReport = 0;
-            mWindowSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+            mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction);
         } catch (RemoteException e) {
             // Have fun!
         }
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index abf5e3f..57dfc62 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -44,7 +44,7 @@
     public IBinder parentToken;
     public IBinder activityToken;
     public boolean focused;
-    public final Rect boundsInScreen = new Rect();
+    public Region regionInScreen = new Region();
     public List<IBinder> childTokens;
     public CharSequence title;
     public long accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
@@ -73,7 +73,7 @@
         window.parentToken = other.parentToken;
         window.activityToken = other.activityToken;
         window.focused = other.focused;
-        window.boundsInScreen.set(other.boundsInScreen);
+        window.regionInScreen.set(other.regionInScreen);
         window.title = other.title;
         window.accessibilityIdOfAnchor = other.accessibilityIdOfAnchor;
         window.inPictureInPicture = other.inPictureInPicture;
@@ -109,7 +109,7 @@
         parcel.writeStrongBinder(parentToken);
         parcel.writeStrongBinder(activityToken);
         parcel.writeInt(focused ? 1 : 0);
-        boundsInScreen.writeToParcel(parcel, flags);
+        regionInScreen.writeToParcel(parcel, flags);
         parcel.writeCharSequence(title);
         parcel.writeLong(accessibilityIdOfAnchor);
         parcel.writeInt(inPictureInPicture ? 1 : 0);
@@ -132,7 +132,8 @@
         builder.append(", type=").append(type);
         builder.append(", layer=").append(layer);
         builder.append(", token=").append(token);
-        builder.append(", bounds=").append(boundsInScreen);
+        builder.append(", region=").append(regionInScreen);
+        builder.append(", bounds=").append(regionInScreen.getBounds());
         builder.append(", parent=").append(parentToken);
         builder.append(", focused=").append(focused);
         builder.append(", children=").append(childTokens);
@@ -151,7 +152,7 @@
         parentToken = parcel.readStrongBinder();
         activityToken = parcel.readStrongBinder();
         focused = (parcel.readInt() == 1);
-        boundsInScreen.readFromParcel(parcel);
+        regionInScreen = Region.CREATOR.createFromParcel(parcel);
         title = parcel.readCharSequence();
         accessibilityIdOfAnchor = parcel.readLong();
         inPictureInPicture = (parcel.readInt() == 1);
@@ -174,7 +175,7 @@
         parentToken = null;
         activityToken = null;
         focused = false;
-        boundsInScreen.setEmpty();
+        regionInScreen.setEmpty();
         if (childTokens != null) {
             childTokens.clear();
         }
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index dfeb4b5..5844365 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -20,8 +20,8 @@
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.util.MergedConfiguration;
 import android.util.Log;
+import android.util.MergedConfiguration;
 import android.view.IWindowSession;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
@@ -35,7 +35,7 @@
 * By parcelling the root surface, the app can offer another app content for embedding.
 * @hide
 */
-class WindowlessWindowManager extends IWindowSession.Default {
+class WindowlessWindowManager implements IWindowSession {
     private final static String TAG = "WindowlessWindowManager";
 
     /**
@@ -83,6 +83,17 @@
     }
 
     @Override
+    public int addToDisplayWithoutInputChannel(android.view.IWindow window, int seq,
+            android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId,
+            android.graphics.Rect outContentInsets, android.graphics.Rect outStableInsets,
+            android.view.InsetsState insetsState) {
+        return 0;
+    }
+
+    @Override
+    public void remove(android.view.IWindow window) {}
+
+    @Override
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
             Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
@@ -106,4 +117,154 @@
 
         return 0;
     }
+
+    @Override
+    public void prepareToReplaceWindows(android.os.IBinder appToken, boolean childrenOnly) {
+    }
+
+    @Override
+    public boolean outOfMemory(android.view.IWindow window) {
+        return false;
+    }
+
+    @Override
+    public void setTransparentRegion(android.view.IWindow window, android.graphics.Region region) {
+    }
+
+    @Override
+    public void setInsets(android.view.IWindow window, int touchableInsets,
+            android.graphics.Rect contentInsets, android.graphics.Rect visibleInsets,
+            android.graphics.Region touchableRegion) {
+    }
+
+    @Override
+    public void getDisplayFrame(android.view.IWindow window,
+            android.graphics.Rect outDisplayFrame) {
+    }
+
+    @Override
+    public void finishDrawing(android.view.IWindow window,
+            android.view.SurfaceControl.Transaction postDrawTransaction) {
+    }
+
+    @Override
+    public void setInTouchMode(boolean showFocus) {
+    }
+
+    @Override
+    public boolean getInTouchMode() {
+        return false;
+    }
+
+    @Override
+    public boolean performHapticFeedback(int effectId, boolean always) {
+        return false;
+    }
+
+    @Override
+    public android.os.IBinder performDrag(android.view.IWindow window, int flags,
+            android.view.SurfaceControl surface, int touchSource, float touchX, float touchY,
+            float thumbCenterX, float thumbCenterY, android.content.ClipData data) {
+        return null;
+    }
+
+    @Override
+    public void reportDropResult(android.view.IWindow window, boolean consumed) {
+    }
+
+    @Override
+    public void cancelDragAndDrop(android.os.IBinder dragToken, boolean skipAnimation) {
+    }
+
+    @Override
+    public void dragRecipientEntered(android.view.IWindow window) {
+    }
+
+    @Override
+    public void dragRecipientExited(android.view.IWindow window) {
+    }
+
+    @Override
+    public void setWallpaperPosition(android.os.IBinder windowToken, float x, float y,
+            float xstep, float ystep) {
+    }
+
+    @Override
+    public void wallpaperOffsetsComplete(android.os.IBinder window) {
+    }
+
+    @Override
+    public void setWallpaperDisplayOffset(android.os.IBinder windowToken, int x, int y) {
+    }
+
+    @Override
+    public android.os.Bundle sendWallpaperCommand(android.os.IBinder window,
+            java.lang.String action, int x, int y, int z, android.os.Bundle extras, boolean sync) {
+        return null;
+    }
+
+    @Override
+    public void wallpaperCommandComplete(android.os.IBinder window, android.os.Bundle result) {
+    }
+
+    @Override
+    public void onRectangleOnScreenRequested(android.os.IBinder token,
+            android.graphics.Rect rectangle) {
+    }
+
+    @Override
+    public android.view.IWindowId getWindowId(android.os.IBinder window) {
+        return null;
+    }
+
+    @Override
+    public void pokeDrawLock(android.os.IBinder window) {
+    }
+
+    @Override
+    public boolean startMovingTask(android.view.IWindow window, float startX, float startY) {
+        return false;
+    }
+
+    @Override
+    public void finishMovingTask(android.view.IWindow window) {
+    }
+
+    @Override
+    public void updatePointerIcon(android.view.IWindow window) {
+    }
+
+    @Override
+    public void reparentDisplayContent(android.view.IWindow window, android.view.SurfaceControl sc,
+            int displayId) {
+    }
+
+    @Override
+    public void updateDisplayContentLocation(android.view.IWindow window, int x, int y,
+            int displayId) {
+    }
+
+    @Override
+    public void updateTapExcludeRegion(android.view.IWindow window, int regionId,
+            android.graphics.Region region) {
+    }
+
+    @Override
+    public void insetsModified(android.view.IWindow window, android.view.InsetsState state) {
+    }
+
+    @Override
+    public void reportSystemGestureExclusionChanged(android.view.IWindow window,
+            java.util.List<android.graphics.Rect> exclusionRects) {
+    }
+
+    @Override
+    public void blessInputSurface(int displayId, SurfaceControl surface,
+            InputChannel outInputChannel) {
+    }
+
+    @Override
+    public android.os.IBinder asBinder() {
+        return null;
+    }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 985effb..fd09a87 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -622,6 +622,10 @@
     /**
      * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
      * The window's bounds changed.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#R R}, this event implies the window's
+     * region changed. It's also possible that region changed but bounds doesn't.
+     * </p>
      */
     public static final int WINDOWS_CHANGE_BOUNDS = 0x00000008;
 
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 5b3dbb1..d474b4d 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1688,6 +1688,11 @@
      * Instead it represents the result of {@link View#getParentForAccessibility()},
      * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true.
      * So this method is not reliable.
+     * <p>
+     * When magnification is enabled, the bounds in parent are also scaled up by magnification
+     * scale. For example, it returns Rect(20, 20, 200, 200) for original bounds
+     * Rect(10, 10, 100, 100), when the magnification scale is 2.
+     * <p/>
      *
      * @param outBounds The output node bounds.
      * @deprecated Use {@link #getBoundsInScreen(Rect)} instead.
@@ -1725,6 +1730,12 @@
 
     /**
      * Gets the node bounds in screen coordinates.
+     * <p>
+     * When magnification is enabled, the bounds in screen are scaled up by magnification scale
+     * and the positions are also adjusted according to the offset of magnification viewport.
+     * For example, it returns Rect(-180, -180, 0, 0) for original bounds Rect(10, 10, 100, 100),
+     * when the magnification scale is 2 and offsets for X and Y are both 200.
+     * <p/>
      *
      * @param outBounds The output node bounds.
      */
@@ -1861,6 +1872,12 @@
 
     /**
      * Gets whether this node is visible to the user.
+     * <p>
+     * Between {@link Build.VERSION_CODES#JELLY_BEAN API 16} and
+     * {@link Build.VERSION_CODES#Q API 29}, this method may incorrectly return false when
+     * magnification is enabled. On other versions, a node is considered visible even if it is not
+     * on the screen because magnification is active.
+     * </p>
      *
      * @return Whether the node is visible to the user.
      */
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index ea61ef8..6a3af34 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -16,9 +16,11 @@
 
 package android.view.accessibility;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -107,7 +109,7 @@
     private int mBooleanProperties;
     private int mId = UNDEFINED_WINDOW_ID;
     private int mParentId = UNDEFINED_WINDOW_ID;
-    private final Rect mBoundsInScreen = new Rect();
+    private Region mRegionInScreen = new Region();
     private LongArray mChildIds;
     private CharSequence mTitle;
     private long mAnchorId = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
@@ -305,23 +307,33 @@
     }
 
     /**
-     * Gets the bounds of this window in the screen.
+     * Gets the touchable region of this window in the screen.
+     *
+     * @param outRegion The out window region.
+     */
+    public void getRegionInScreen(@NonNull Region outRegion) {
+        outRegion.set(mRegionInScreen);
+    }
+
+    /**
+     * Sets the touchable region of this window in the screen.
+     *
+     * @param region The window region.
+     *
+     * @hide
+     */
+    public void setRegionInScreen(Region region) {
+        mRegionInScreen.set(region);
+    }
+
+    /**
+     * Gets the bounds of this window in the screen. This is equivalent to get the bounds of the
+     * Region from {@link #getRegionInScreen(Region)}.
      *
      * @param outBounds The out window bounds.
      */
     public void getBoundsInScreen(Rect outBounds) {
-        outBounds.set(mBoundsInScreen);
-    }
-
-    /**
-     * Sets the bounds of this window in the screen.
-     *
-     * @param bounds The out window bounds.
-     *
-     * @hide
-     */
-    public void setBoundsInScreen(Rect bounds) {
-        mBoundsInScreen.set(bounds);
+        outBounds.set(mRegionInScreen.getBounds());
     }
 
     /**
@@ -522,7 +534,7 @@
         parcel.writeInt(mBooleanProperties);
         parcel.writeInt(mId);
         parcel.writeInt(mParentId);
-        mBoundsInScreen.writeToParcel(parcel, flags);
+        mRegionInScreen.writeToParcel(parcel, flags);
         parcel.writeCharSequence(mTitle);
         parcel.writeLong(mAnchorId);
 
@@ -552,7 +564,7 @@
         mBooleanProperties = other.mBooleanProperties;
         mId = other.mId;
         mParentId = other.mParentId;
-        mBoundsInScreen.set(other.mBoundsInScreen);
+        mRegionInScreen.set(other.mRegionInScreen);
         mTitle = other.mTitle;
         mAnchorId = other.mAnchorId;
 
@@ -574,7 +586,7 @@
         mBooleanProperties = parcel.readInt();
         mId = parcel.readInt();
         mParentId = parcel.readInt();
-        mBoundsInScreen.readFromParcel(parcel);
+        mRegionInScreen = Region.CREATOR.createFromParcel(parcel);
         mTitle = parcel.readCharSequence();
         mAnchorId = parcel.readLong();
 
@@ -621,7 +633,8 @@
         builder.append(", id=").append(mId);
         builder.append(", type=").append(typeToString(mType));
         builder.append(", layer=").append(mLayer);
-        builder.append(", bounds=").append(mBoundsInScreen);
+        builder.append(", region=").append(mRegionInScreen);
+        builder.append(", bounds=").append(mRegionInScreen.getBounds());
         builder.append(", focused=").append(isFocused());
         builder.append(", active=").append(isActive());
         builder.append(", pictureInPicture=").append(isInPictureInPictureMode());
@@ -661,7 +674,7 @@
         mBooleanProperties = 0;
         mId = UNDEFINED_WINDOW_ID;
         mParentId = UNDEFINED_WINDOW_ID;
-        mBoundsInScreen.setEmpty();
+        mRegionInScreen.setEmpty();
         mChildIds = null;
         mConnectionId = UNDEFINED_WINDOW_ID;
         mAnchorId = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
@@ -716,7 +729,6 @@
         }
     }
 
-
     /**
      * Reports how this window differs from a possibly different state of the same window. The
      * argument must have the same id and type as neither of those properties may change.
@@ -739,8 +751,7 @@
         if (!TextUtils.equals(mTitle, other.mTitle)) {
             changes |= AccessibilityEvent.WINDOWS_CHANGE_TITLE;
         }
-
-        if (!mBoundsInScreen.equals(other.mBoundsInScreen)) {
+        if (!mRegionInScreen.equals(other.mRegionInScreen)) {
             changes |= AccessibilityEvent.WINDOWS_CHANGE_BOUNDS;
         }
         if (mLayer != other.mLayer) {
diff --git a/core/java/android/view/inputmethod/InputMethodSystemProperty.java b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
index 0689806..e20c2fd 100644
--- a/core/java/android/view/inputmethod/InputMethodSystemProperty.java
+++ b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
@@ -17,7 +17,6 @@
 package android.view.inputmethod;
 
 import android.annotation.Nullable;
-import android.annotation.TestApi;
 import android.content.ComponentName;
 import android.os.Build;
 import android.os.SystemProperties;
@@ -27,7 +26,6 @@
  *
  * @hide
  */
-@TestApi
 public class InputMethodSystemProperty {
     /**
      * System property key for the production use. The value must be either empty or a valid
@@ -78,6 +76,5 @@
      *
      * @hide
      */
-    @TestApi
     public static final boolean MULTI_CLIENT_IME_ENABLED = (sMultiClientImeComponentName != null);
 }
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index c3c2c0d..2bf1ba5 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -50,7 +50,7 @@
  * override {@link #getView(int, View, ViewGroup)}
  * and inflate a view resource.
  * For a code example, see
- * the <a href="https://developer.android.com/samples/CustomChoiceList/index.html">
+ * the <a href="https://github.com/googlesamples/android-CustomChoiceList/#readme">
  * CustomChoiceList</a> sample.
  * </p>
  * <p>
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index efd5daf..b67e27c 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -921,10 +921,12 @@
                 if (!mFlingScroller.isFinished()) {
                     mFlingScroller.forceFinished(true);
                     mAdjustScroller.forceFinished(true);
+                    onScrollerFinished(mFlingScroller);
                     onScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
                 } else if (!mAdjustScroller.isFinished()) {
                     mFlingScroller.forceFinished(true);
                     mAdjustScroller.forceFinished(true);
+                    onScrollerFinished(mAdjustScroller);
                 } else if (mLastDownEventY < mTopSelectionDividerTop) {
                     postChangeCurrentByOneFromLongPress(
                             false, ViewConfiguration.getLongPressTimeout());
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index d985528..6b324a5 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1202,13 +1202,13 @@
      * determine where to position the view on the screen.  If the view is not contained
      * within a relative layout, these attributes are ignored.
      *
-     * See the <a href="/guide/topics/ui/layout/relative.html">
-     * Relative Layout</a> guide for example code demonstrating how to use relative layout’s
+     * See the <a href="{@docRoot}guide/topics/ui/layout/relative.html">Relative
+     * Layout</a> guide for example code demonstrating how to use relative layout's
      * layout parameters in a layout XML.
      *
      * To learn more about layout parameters and how they differ from typical view attributes,
-     * see the <a href="/guide/topics/ui/declaring-layout.html#attributes">
-     *     Layouts guide</a>.
+     * see the <a href="{@docRoot}guide/topics/ui/declaring-layout.html#attributes">Layouts
+     * guide</a>.
      *
      *
      * @attr ref android.R.styleable#RelativeLayout_Layout_layout_alignWithParentIfMissing
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 49a0f39..4c67b08 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -433,7 +433,7 @@
      * to the next tabbed view, in this example).
      * <p>
      * To move both the focus AND the selected tab at once, please use
-     * {@link #setCurrentTab}. Normally, the view logic takes care of
+     * {@link #focusCurrentTab}. Normally, the view logic takes care of
      * adjusting the focus, so unless you're circumventing the UI,
      * you'll probably just focus your interest here.
      *
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index 80ea363..d36f343 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -57,6 +57,9 @@
         super(context, attrs);
 
         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator);
+        saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ViewAnimator,
+                attrs, a, 0, 0);
+
         int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0);
         if (resource > 0) {
             setInAnimation(context, resource);
@@ -90,6 +93,8 @@
         // attribute to override.
         final TypedArray a = context.obtainStyledAttributes(attrs,
                 com.android.internal.R.styleable.FrameLayout);
+        saveAttributeDataForStyleable(context, com.android.internal.R.styleable.FrameLayout,
+                attrs, a, 0, 0);
         final boolean measureAllChildren = a.getBoolean(
                 com.android.internal.R.styleable.FrameLayout_measureAllChildren, true);
         setMeasureAllChildren(measureAllChildren);
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 430fa61..ee4666f 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -198,6 +198,89 @@
      */
     public static final String BRIGHTLINE_FALSING_MANAGER_ENABLED =
             "brightline_falsing_manager_enabled";
+    /**
+     * (float) Maximum fraction of the screen required to qualify as a real swipe.
+     */
+    public static final String BRIGHTLINE_FALSING_DISTANCE_SCREEN_FRACTION_MAX_DISTANCE =
+            "brightline_falsing_distance_screen_fraction_max_distance";
+
+    /**
+     * (float) Multiplier for swipe velocity to convert it to pixels for a fling.
+     */
+    public static final String BRIGHTLINE_FALSING_DISTANCE_VELOCITY_TO_DISTANCE =
+            "brightline_falsing_distance_velcoity_to_distance";
+
+    /**
+     * (float) How far, in inches, must a fling travel horizontally to qualify as intentional.
+     */
+    public static final String BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN =
+            "brightline_falsing_distance_horizontal_fling_threshold_in";
+
+    /**
+     * (float) Maximum fraction of the screen required to qualify as a real swipe.
+     */
+    public static final String BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN =
+            "brightline_falsing_distance_vertical_fling_threshold_in";
+
+    /**
+     * (float) How far, in inches, must a continuous swipe travel horizontally to be intentional.
+     */
+    public static final String BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN =
+            "brightline_falsing_distance_horizontal_swipe_threshold_in";
+
+    /**
+     * (float) How far, in inches, must a continuous swipe travel vertically to be intentional.
+     */
+    public static final String BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN =
+            "brightline_falsing_distance_horizontal_swipe_threshold_in";
+
+    /**
+     * (float) Percentage of swipe with the proximity sensor covered that triggers a higher
+     * swipe distance requirement.
+     */
+    public static final String BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD =
+            "brightline_falsing_proximity_percent_covered_threshold";
+
+    /**
+     * (float) Angle, in radians, that a swipe can vary from horizontal and sill be intentional.
+     */
+    public static final String BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE =
+            "brightline_falsing_diagonal_horizontal_angle_range";
+
+    /**
+     * (float) Angle, in radians, that a swipe can vary from vertical and sill be intentional.
+     */
+    public static final String BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE =
+            "brightline_falsing_diagonal_horizontal_angle_range";
+
+    /**
+     * (float) Distance, in inches, that a swipe is allowed to vary in the horizontal direction for
+     * horizontal swipes.
+     */
+    public static final String BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE =
+            "brightline_falsing_zigzag_x_primary_deviance";
+
+    /**
+     * (float) Distance, in inches, that a swipe is allowed to vary in the vertical direction for
+     * vertical swipes.
+     */
+    public static final String BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE =
+            "brightline_falsing_zigzag_y_primary_deviance";
+
+    /**
+     * (float) Distance, in inches, that a swipe is allowed to vary in the horizontal direction for
+     * horizontal swipes.
+     */
+    public static final String BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE =
+            "brightline_falsing_zigzag_x_secondary_deviance";
+
+    /**
+     * (float) Distance, in inches, that a swipe is allowed to vary in the vertical direction for
+     * vertical swipes.
+     */
+    public static final String BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE =
+            "brightline_falsing_zigzag_y_secondary_deviance";
+
 
     private SystemUiDeviceConfigFlags() { }
 }
diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java
index c7c2924..c8929e9 100644
--- a/core/java/com/android/internal/infra/AndroidFuture.java
+++ b/core/java/com/android/internal/infra/AndroidFuture.java
@@ -115,6 +115,20 @@
         }
     }
 
+    /**
+     * Create a completed future with the given value.
+     *
+     * @param value the value for the completed future
+     * @param <U> the type of the value
+     * @return the completed future
+     */
+    @NonNull
+    public static <U> AndroidFuture<U> completedFuture(U value) {
+        AndroidFuture<U> future = new AndroidFuture<>();
+        future.complete(value);
+        return future;
+    }
+
     @Override
     public boolean complete(@Nullable T value) {
         boolean changed = super.complete(value);
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index 8136cfc..d6862f0 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -228,7 +228,7 @@
         private final int mUserId;
         private final @Nullable Function<IBinder, I> mBinderAsInterface;
 
-        private I mService = null;
+        private volatile I mService = null;
         private boolean mBinding = false;
         private boolean mUnbinding = false;
 
@@ -506,11 +506,12 @@
 
         void unbindJobThread() {
             cancelTimeout();
-            boolean wasBound = isBound();
+            I service = mService;
+            boolean wasBound = service != null;
             if (wasBound) {
-                onServiceConnectionStatusChanged(mService, false);
+                onServiceConnectionStatusChanged(service, false);
                 mContext.unbindService(mServiceConnection);
-                mService.asBinder().unlinkToDeath(this, 0);
+                service.asBinder().unlinkToDeath(this, 0);
                 mService = null;
             }
             mBinding = false;
@@ -543,7 +544,7 @@
         }
 
         @Override
-        public void onServiceConnected(@NonNull ComponentName name, @NonNull IBinder service) {
+        public void onServiceConnected(@NonNull ComponentName name, @NonNull IBinder binder) {
             if (mUnbinding) {
                 Log.i(LOG_TAG, "Ignoring onServiceConnected due to ongoing unbinding: " + this);
                 return;
@@ -551,14 +552,15 @@
             if (DEBUG) {
                 logTrace();
             }
-            mService = binderAsInterface(service);
+            I service = binderAsInterface(binder);
+            mService = service;
             mBinding = false;
             try {
-                service.linkToDeath(ServiceConnector.Impl.this, 0);
+                binder.linkToDeath(ServiceConnector.Impl.this, 0);
             } catch (RemoteException e) {
                 Log.e(LOG_TAG, "onServiceConnected " + name + ": ", e);
             }
-            onServiceConnectionStatusChanged(mService, true);
+            onServiceConnectionStatusChanged(service, true);
             processQueue();
         }
 
@@ -568,8 +570,11 @@
                 logTrace();
             }
             mBinding = true;
-            onServiceConnectionStatusChanged(mService, false);
-            mService = null;
+            I service = mService;
+            if (service != null) {
+                onServiceConnectionStatusChanged(service, false);
+                mService = null;
+            }
         }
 
         @Override
diff --git a/core/java/com/android/internal/infra/ThrottledRunnable.java b/core/java/com/android/internal/infra/ThrottledRunnable.java
new file mode 100644
index 0000000..9846fa9
--- /dev/null
+++ b/core/java/com/android/internal/infra/ThrottledRunnable.java
@@ -0,0 +1,75 @@
+/*
+ * 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.internal.infra;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.SystemClock;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * A throttled runnable that can wrap around a runnable and throttle calls to its run().
+ *
+ * The throttling logic makes sure that the original runnable will be called only after the
+ * specified interval passes since the last actual call. The first call in a while (after the
+ * specified interval passes since the last actual call) will always result in the original runnable
+ * being called immediately, and then subsequent calls will start to be throttled. It is guaranteed
+ * that any call to this throttled runnable will always result in the original runnable being called
+ * afterwards, within the specified interval.
+ */
+public class ThrottledRunnable implements Runnable {
+
+    @NonNull
+    private final Handler mHandler;
+    private final long mIntervalMillis;
+    @NonNull
+    private final Runnable mRunnable;
+
+    @NonNull
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private long mScheduledUptimeMillis;
+
+    public ThrottledRunnable(@NonNull Handler handler, long intervalMillis,
+            @NonNull Runnable runnable) {
+        mHandler = handler;
+        mIntervalMillis = intervalMillis;
+        mRunnable = runnable;
+    }
+
+    @Override
+    public void run() {
+        synchronized (mLock) {
+            if (mHandler.hasCallbacks(mRunnable)) {
+                // We have a scheduled runnable.
+                return;
+            }
+            long currentUptimeMillis = SystemClock.uptimeMillis();
+            if (mScheduledUptimeMillis == 0
+                    || currentUptimeMillis > mScheduledUptimeMillis + mIntervalMillis) {
+                // First time in a while, schedule immediately.
+                mScheduledUptimeMillis = currentUptimeMillis;
+            } else {
+                // We were scheduled not long ago, so schedule with delay for throttling.
+                mScheduledUptimeMillis = mScheduledUptimeMillis + mIntervalMillis;
+            }
+            mHandler.postAtTime(mRunnable, mScheduledUptimeMillis);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index 3ac58e0..d53fada 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -27,6 +27,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.File;
 import java.io.FileInputStream;
 import java.util.Iterator;
 
@@ -38,6 +39,7 @@
     private static int sKernelWakelockUpdateVersion = 0;
     private static final String sWakelockFile = "/proc/wakelocks";
     private static final String sWakeupSourceFile = "/d/wakeup_sources";
+    private static final String sSysClassWakeupDir = "/sys/class/wakeup";
 
     private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
         Process.PROC_TAB_TERM|Process.PROC_OUT_STRING|                // 0: name
@@ -71,99 +73,108 @@
      * @return the updated data.
      */
     public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
-        byte[] buffer = new byte[32*1024];
-        int len = 0;
-        boolean wakeup_sources;
-        final long startTime = SystemClock.uptimeMillis();
+        boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();
 
-        final int oldMask = StrictMode.allowThreadDiskReadsMask();
-        try {
-            FileInputStream is;
-            try {
-                is = new FileInputStream(sWakelockFile);
-                wakeup_sources = false;
-            } catch (java.io.FileNotFoundException e) {
+        if (useSystemSuspend) {
+            WakeLockInfo[] wlStats = null;
+            if (mSuspendControlService == null) {
                 try {
-                    is = new FileInputStream(sWakeupSourceFile);
-                    wakeup_sources = true;
-                } catch (java.io.FileNotFoundException e2) {
-                    Slog.wtf(TAG, "neither " + sWakelockFile + " nor " +
-                            sWakeupSourceFile + " exists");
+                    mSuspendControlService = ISuspendControlService.Stub.asInterface(
+                        ServiceManager.getServiceOrThrow("suspend_control"));
+                } catch (ServiceNotFoundException e) {
+                    Slog.wtf(TAG, "Required service suspend_control not available", e);
                     return null;
                 }
             }
 
-            int cnt;
-            while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
-                len += cnt;
+            try {
+                wlStats = mSuspendControlService.getWakeLockStats();
+                updateVersion(staleStats);
+                updateWakelockStats(wlStats, staleStats);
+            } catch (RemoteException e) {
+                Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
+                return null;
             }
 
-            is.close();
-        } catch (java.io.IOException e) {
-            Slog.wtf(TAG, "failed to read kernel wakelocks", e);
-            return null;
-        } finally {
-            StrictMode.setThreadPolicyMask(oldMask);
-        }
+            return removeOldStats(staleStats);
 
-        final long readTime = SystemClock.uptimeMillis() - startTime;
-        if (readTime > 100) {
-            Slog.w(TAG, "Reading wakelock stats took " + readTime + "ms");
-        }
+        } else {
+            byte[] buffer = new byte[32*1024];
+            int len = 0;
+            boolean wakeup_sources;
+            final long startTime = SystemClock.uptimeMillis();
 
-        if (len > 0) {
-            if (len >= buffer.length) {
-                Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+            final int oldMask = StrictMode.allowThreadDiskReadsMask();
+            try {
+                FileInputStream is;
+                try {
+                    is = new FileInputStream(sWakelockFile);
+                    wakeup_sources = false;
+                } catch (java.io.FileNotFoundException e) {
+                    try {
+                        is = new FileInputStream(sWakeupSourceFile);
+                        wakeup_sources = true;
+                    } catch (java.io.FileNotFoundException e2) {
+                        Slog.wtf(TAG, "neither " + sWakelockFile + " nor " +
+                                sWakeupSourceFile + " exists");
+                        return null;
+                    }
+                }
+
+                int cnt;
+                while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
+                    len += cnt;
+                }
+
+                is.close();
+            } catch (java.io.IOException e) {
+                Slog.wtf(TAG, "failed to read kernel wakelocks", e);
+                return null;
+            } finally {
+                StrictMode.setThreadPolicyMask(oldMask);
             }
-            int i;
-            for (i=0; i<len; i++) {
-                if (buffer[i] == '\0') {
-                    len = i;
-                    break;
+
+            final long readTime = SystemClock.uptimeMillis() - startTime;
+            if (readTime > 100) {
+                Slog.w(TAG, "Reading wakelock stats took " + readTime + "ms");
+            }
+
+            if (len > 0) {
+                if (len >= buffer.length) {
+                    Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+                }
+                int i;
+                for (i=0; i<len; i++) {
+                    if (buffer[i] == '\0') {
+                        len = i;
+                        break;
+                    }
                 }
             }
+
+            updateVersion(staleStats);
+            parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
+            return removeOldStats(staleStats);
         }
-
-        updateVersion(staleStats);
-
-        parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
-
-        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);
-            }
-        }
-
-        try {
-            WakeLockInfo[] wlStats = mSuspendControlService.getWakeLockStats();
-            getNativeWakelockStats(wlStats, staleStats);
-        } catch (RemoteException e) {
-            Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
-        }
-
-        return removeOldStats(staleStats);
     }
 
     /**
-     * Reads native wakelock stats from SystemSuspend and updates staleStats with the new
-     * information.
+     * Updates statleStats with stats from  SystemSuspend.
      * @param staleStats Existing object to update.
      * @return the updated stats.
      */
     @VisibleForTesting
-    public KernelWakelockStats getNativeWakelockStats(WakeLockInfo[] wlStats,
+    public KernelWakelockStats updateWakelockStats(WakeLockInfo[] wlStats,
                                                       final KernelWakelockStats staleStats) {
         for (WakeLockInfo info : wlStats) {
             if (!staleStats.containsKey(info.name)) {
                 staleStats.put(info.name, new KernelWakelockStats.Entry((int) info.activeCount,
-                        info.totalTime, sKernelWakelockUpdateVersion));
+                        info.totalTime * 1000 /* ms to us */, sKernelWakelockUpdateVersion));
             } else {
                 KernelWakelockStats.Entry kwlStats = staleStats.get(info.name);
                 kwlStats.mCount = (int) info.activeCount;
-                kwlStats.mTotalTime = info.totalTime;
+                // Convert milliseconds to microseconds
+                kwlStats.mTotalTime = info.totalTime * 1000;
                 kwlStats.mVersion = sKernelWakelockUpdateVersion;
             }
         }
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 9b51c12..9d4cdc7 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -106,6 +106,14 @@
      */
     public static final int USE_APP_IMAGE_STARTUP_CACHE = 1 << 16;
 
+    /**
+     * When set, application specified signal handlers are not chained (i.e, ignored)
+     * by the runtime.
+     *
+     * Used for debugging only. Usage: set debug.ignoreappsignalhandler to 1.
+     */
+    public static final int DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17;
+
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
     /** Default external storage should be mounted. */
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index fe66cf9..599c354 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -249,6 +249,14 @@
     private Drawable mOriginalBackgroundDrawable;
     private Drawable mLastOriginalBackgroundDrawable;
     private Drawable mResizingBackgroundDrawable;
+
+    /**
+     * Temporary holder for a window background when it is set before {@link #mWindow} is
+     * initialized. It will be set as the actual background once {@link #setWindow(PhoneWindow)} is
+     * called.
+     */
+    @Nullable
+    private Drawable mPendingWindowBackground;
     private Drawable mCaptionBackgroundDrawable;
     private Drawable mUserCaptionBackgroundDrawable;
 
@@ -961,6 +969,10 @@
     }
 
     public void setWindowBackground(Drawable drawable) {
+        if (mWindow == null) {
+            mPendingWindowBackground = drawable;
+            return;
+        }
         if (mOriginalBackgroundDrawable != drawable) {
             mOriginalBackgroundDrawable = drawable;
             updateBackgroundDrawable();
@@ -983,14 +995,7 @@
 
     @Override
     public void setBackgroundDrawable(Drawable background) {
-
-        // TODO: This should route through setWindowBackground, but late in the release to make this
-        // change.
-        if (mOriginalBackgroundDrawable != background) {
-            mOriginalBackgroundDrawable = background;
-            updateBackgroundDrawable();
-            drawableChanged();
-        }
+        setWindowBackground(background);
     }
 
     public void setWindowFrame(Drawable drawable) {
@@ -2010,6 +2015,11 @@
             DecorContext decorContext = (DecorContext) context;
             decorContext.setPhoneWindow(mWindow);
         }
+        if (mPendingWindowBackground != null) {
+            Drawable background = mPendingWindowBackground;
+            mPendingWindowBackground = null;
+            setWindowBackground(background);
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
index adf7692..52172cf 100644
--- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
+++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
@@ -36,13 +36,16 @@
         }
 
         // Radius that should be used in case top or bottom aren't defined.
-        float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius);
+        float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius)
+                - resources.getDimension(R.dimen.rounded_corner_radius_adjustment);
 
-        float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top);
+        float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top)
+                - resources.getDimension(R.dimen.rounded_corner_radius_top_adjustment);
         if (topRadius == 0f) {
             topRadius = defaultRadius;
         }
-        float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom);
+        float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom)
+                - resources.getDimension(R.dimen.rounded_corner_radius_bottom_adjustment);
         if (bottomRadius == 0f) {
             bottomRadius = defaultRadius;
         }
diff --git a/core/java/com/android/internal/util/AnnotationValidations.java b/core/java/com/android/internal/util/AnnotationValidations.java
new file mode 100644
index 0000000..c8afdd4
--- /dev/null
+++ b/core/java/com/android/internal/util/AnnotationValidations.java
@@ -0,0 +1,193 @@
+/*
+ * 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.internal.util;
+
+import static com.android.internal.util.BitUtils.flagsUpTo;
+
+import android.annotation.AppIdInt;
+import android.annotation.ColorInt;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Size;
+import android.annotation.UserIdInt;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.PackageInfoFlags;
+import android.content.pm.PackageManager.PermissionResult;
+import android.os.UserHandle;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Validations for common annotations, e.g. {@link IntRange}, {@link UserIdInt}, etc.
+ *
+ * For usability from generated {@link DataClass} code, all validations are overloads of
+ * {@link #validate} with the following shape:
+ * {@code
+ *      <A extends Annotation> void validate(
+ *              Class<A> cls, A ignored, Object value[, (String, Object)... annotationParams])
+ * }
+ * The ignored {@link Annotation} parameter is used to differentiate between overloads that would
+ * otherwise have the same jvm signature. It's usually null at runtime.
+ */
+public class AnnotationValidations {
+    private AnnotationValidations() {}
+
+    public static void validate(Class<UserIdInt> annotation, UserIdInt ignored, int value) {
+        if ((value != UserHandle.USER_NULL && value < -3)
+                || value > Integer.MAX_VALUE / UserHandle.PER_USER_RANGE) {
+            invalid(annotation, value);
+        }
+    }
+
+    public static void validate(Class<AppIdInt> annotation, AppIdInt ignored, int value) {
+        if (value / UserHandle.PER_USER_RANGE != 0 || value < 0) {
+            invalid(annotation, value);
+        }
+    }
+
+    public static void validate(Class<IntRange> annotation, IntRange ignored, int value,
+            String paramName1, int param1, String paramName2, int param2) {
+        validate(annotation, ignored, value, paramName1, param1);
+        validate(annotation, ignored, value, paramName2, param2);
+    }
+
+    public static void validate(Class<IntRange> annotation, IntRange ignored, int value,
+            String paramName, int param) {
+        switch (paramName) {
+            case "from": if (value < param) invalid(annotation, value, paramName, param); break;
+            case "to": if (value > param) invalid(annotation, value, paramName, param); break;
+        }
+    }
+
+    public static void validate(Class<FloatRange> annotation, FloatRange ignored, float value,
+            String paramName1, float param1, String paramName2, float param2) {
+        validate(annotation, ignored, value, paramName1, param1);
+        validate(annotation, ignored, value, paramName2, param2);
+    }
+
+    public static void validate(Class<FloatRange> annotation, FloatRange ignored, float value,
+            String paramName, float param) {
+        switch (paramName) {
+            case "from": if (value < param) invalid(annotation, value, paramName, param); break;
+            case "to": if (value > param) invalid(annotation, value, paramName, param); break;
+        }
+    }
+
+    public static void validate(Class<NonNull> annotation, NonNull ignored, Object value) {
+        if (value == null) {
+            throw new NullPointerException();
+        }
+    }
+
+    public static void validate(Class<Size> annotation, Size ignored, int value,
+            String paramName1, int param1, String paramName2, int param2) {
+        validate(annotation, ignored, value, paramName1, param1);
+        validate(annotation, ignored, value, paramName2, param2);
+    }
+
+    public static void validate(Class<Size> annotation, Size ignored, int value,
+            String paramName, int param) {
+        switch (paramName) {
+            case "value": {
+                if (param != -1 && value != param) invalid(annotation, value, paramName, param);
+            } break;
+            case "min": {
+                if (value < param) invalid(annotation, value, paramName, param);
+            } break;
+            case "max": {
+                if (value > param) invalid(annotation, value, paramName, param);
+            } break;
+            case "multiple": {
+                if (value % param != 0) invalid(annotation, value, paramName, param);
+            } break;
+        }
+    }
+
+    public static void validate(
+            Class<PermissionResult> annotation, PermissionResult ignored, int value) {
+        validateIntEnum(annotation, value, PackageManager.PERMISSION_GRANTED);
+    }
+
+    public static void validate(
+            Class<PackageInfoFlags> annotation, PackageInfoFlags ignored, int value) {
+        validateIntFlags(annotation, value,
+                flagsUpTo(PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS));
+    }
+
+    public static void validate(
+            Class<Intent.Flags> annotation, Intent.Flags ignored, int value) {
+        validateIntFlags(annotation, value, flagsUpTo(Intent.FLAG_RECEIVER_OFFLOAD));
+    }
+
+
+    @Deprecated
+    public static void validate(Class<? extends Annotation> annotation,
+            Annotation ignored, Object value, Object... params) {}
+    @Deprecated
+    public static void validate(Class<? extends Annotation> annotation,
+            Annotation ignored, Object value) {}
+    @Deprecated
+    public static void validate(Class<? extends Annotation> annotation,
+            Annotation ignored, int value, Object... params) {}
+    public static void validate(Class<? extends Annotation> annotation,
+            Annotation ignored, int value) {
+        if (("android.annotation".equals(annotation.getPackageName$())
+                && annotation.getSimpleName().endsWith("Res"))
+                || ColorInt.class.equals(annotation)) {
+            if (value < 0) {
+                invalid(annotation, value);
+            }
+        }
+    }
+    public static void validate(Class<? extends Annotation> annotation,
+            Annotation ignored, long value) {
+        if ("android.annotation".equals(annotation.getPackageName$())
+                && annotation.getSimpleName().endsWith("Long")) {
+            if (value < 0L) {
+                invalid(annotation, value);
+            }
+        }
+    }
+
+    private static void validateIntEnum(
+            Class<? extends Annotation> annotation, int value, int lastValid) {
+        if (value > lastValid) {
+            invalid(annotation, value);
+        }
+    }
+    private static void validateIntFlags(
+            Class<? extends Annotation> annotation, int value, int validBits) {
+        if ((validBits & value) != validBits) {
+            invalid(annotation, "0x" + Integer.toHexString(value));
+        }
+    }
+
+    private static void invalid(Class<? extends Annotation> annotation, Object value) {
+        invalid("@" + annotation.getSimpleName(), value);
+    }
+
+    private static void invalid(Class<? extends Annotation> annotation, Object value,
+            String paramName, Object param) {
+        String paramPrefix = "value".equals(paramName) ? "" : paramName + " = ";
+        invalid("@" + annotation.getSimpleName() + "(" + paramPrefix + param + ")", value);
+    }
+
+    private static void invalid(String valueKind, Object value) {
+        throw new IllegalStateException("Invalid " + valueKind + ": " + value);
+    }
+}
diff --git a/core/java/com/android/internal/util/BitUtils.java b/core/java/com/android/internal/util/BitUtils.java
index 6158145..b4bab80 100644
--- a/core/java/com/android/internal/util/BitUtils.java
+++ b/core/java/com/android/internal/util/BitUtils.java
@@ -158,4 +158,18 @@
     public static byte[] toBytes(long l) {
         return ByteBuffer.allocate(8).putLong(l).array();
     }
+
+    /**
+     * 0b01000 -> 0b01111
+     */
+    public static int flagsUpTo(int lastFlag) {
+        return lastFlag <= 0 ? 0 : lastFlag | flagsUpTo(lastFlag >> 1);
+    }
+
+    /**
+     * 0b00010, 0b01000 -> 0b01110
+     */
+    public static int flagsWithin(int firstFlag, int lastFlag) {
+        return (flagsUpTo(lastFlag) & ~flagsUpTo(firstFlag)) | firstFlag;
+    }
 }
diff --git a/core/java/com/android/internal/util/DataClass.java b/core/java/com/android/internal/util/DataClass.java
new file mode 100644
index 0000000..146f546
--- /dev/null
+++ b/core/java/com/android/internal/util/DataClass.java
@@ -0,0 +1,219 @@
+/*
+ * 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.internal.util;
+
+import static java.lang.annotation.ElementType.*;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.os.Parcelable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.TYPE)
+public @interface DataClass {
+
+    /**
+     * Generates {@link Parcelable#writeToParcel}, {@link Parcelable#describeContents} and a
+     * {@link Parcelable.Creator}.
+     *
+     * Can be implicitly requested by adding "implements Parcelable" to class signature
+     *
+     * You can provide custom parceling logic by using a {@link ParcelWith} annotation with a
+     * custom {@link Parcelling} subclass.
+     *
+     * Alternatively, for one-off customizations you can declare methods like:
+     * {@code void parcelFieldName(Parcel dest, int flags)}
+     * {@code static FieldType unparcelFieldName(Parcel in)}
+     */
+    boolean genParcelable() default false;
+
+    /**
+     * Generates a simple "parcelable" .aidl file alongside the original .java file
+     *
+     * If not explicitly requested/suppressed, is on iff {@link #genParcelable} is on
+     */
+    boolean genAidl() default false;
+
+    /**
+     * Generates getters for each field.
+     *
+     * You can request for getter to lazily initialize your field by declaring a method like:
+     * {@code FieldType lazyInitFieldName()}
+     *
+     * You can request for the lazy initialization to be thread safe my marking the field volatile.
+     */
+    boolean genGetters() default true;
+
+    /**
+     * Generates setters for each field.
+     */
+    boolean genSetters() default false;
+
+    /**
+     * Generates a public constructor with each field initialized from a parameter and optionally
+     * some user-defined state validation at the end.
+     *
+     * Uses field {@link Nullable nullability}/default value presence to determine optional
+     * parameters.
+     *
+     * Requesting a {@link #genBuilder} suppresses public constructor generation by default.
+     *
+     * You receive a callback at the end of constructor call by declaring the method:
+     * {@code void onConstructed()}
+     * This is the place to put any custom validation logic.
+     */
+    boolean genConstructor() default true;
+
+    /**
+     * Generates a Builder for your class.
+     *
+     * Uses a package-private constructor under the hood, so same rules hold as for
+     * {@link #genConstructor()}
+     */
+    boolean genBuilder() default false;
+
+    /**
+     * Generates a structural {@link Object#equals} + {@link Object#hashCode}.
+     *
+     * You can customize individual fields' logic by declaring methods like:
+     * {@link boolean fieldNameEquals(ClassName otherInstance)}
+     * {@link boolean fieldNameEquals(FieldType otherValue)}
+     * {@link int fieldNameHashCode()}
+     */
+    boolean genEqualsHashCode() default false;
+
+    /**
+     * Generates a structural {@link Object#toString}.
+     *
+     * You can customize individual fields' logic by declaring methods like:
+     * {@link String fieldNameToString()}
+     */
+    boolean genToString() default false;
+
+    /**
+     * Generates a utility method that takes a {@link PerObjectFieldAction per-field callback}
+     * and calls it once for each field with its name and value.
+     *
+     * If some fields are of primitive types, and additional overload is generated that takes
+     * multiple callbacks, specialized for used primitive types to avoid auto-boxing, e.g.
+     * {@link PerIntFieldAction}.
+     */
+    boolean genForEachField() default false;
+
+    /**
+     * Generates a constructor that copies the given instance of the same class.
+     */
+    boolean genCopyConstructor() default false;
+
+    /**
+     * Generates constant annotations({@link IntDef}/{@link StringDef}) for any constant groups
+     * with common prefix.
+     * The annotation names are based on the common prefix.
+     *
+     * For int constants this additionally generates the corresponding static *ToString method and
+     * uses it in {@link Object#toString}.
+     *
+     * Additionally, any fields you annotate with the generated constants will be automatically
+     * validated in constructor.
+     *
+     * Int constants specified as hex(0x..) are considered to be flags, which is taken into account
+     * for in their *ToString and validation.
+     *
+     * You can optionally override the name of the generated annotation by annotating each constant
+     * with the desired annotation name.
+     *
+     * Unless suppressed, is implied by presence of constants with common prefix.
+     */
+    boolean genConstDefs() default true;
+
+
+    /**
+     * Allows specifying custom parcelling logic based on reusable
+     * {@link Parcelling} implementations
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target(FIELD)
+    @interface ParcelWith {
+        Class<? extends Parcelling> value();
+    }
+
+    /**
+     * Allows specifying a singular name for a builder's plural field name e.g. 'name' for 'mNames'
+     * Used for Builder's {@code addName(String name)} methods
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target(FIELD)
+    @interface PluralOf {
+        String value();
+    }
+
+    /**
+     * Marks that any annotations following it are applicable to each element of the
+     * collection/array, as opposed to itself.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
+    @interface Each {}
+
+    /**
+     * @deprecated to be used by code generator exclusively
+     * @hide
+     */
+    @Deprecated
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, ANNOTATION_TYPE, CONSTRUCTOR, TYPE})
+    @interface Generated {
+        long time();
+        String codegenVersion();
+        String sourceFile();
+        String inputSignatures() default "";
+
+        /**
+         * @deprecated to be used by code generator exclusively
+         * @hide
+         */
+        @Deprecated
+        @Retention(RetentionPolicy.SOURCE)
+        @Target({FIELD, METHOD, ANNOTATION_TYPE, CONSTRUCTOR, TYPE})
+        @interface Member {}
+    }
+
+    /**
+     * Callback used by {@link #genForEachField}.
+     *
+     * @param <THIS> The enclosing data class instance.
+     *              Can be used to try and avoid capturing values from outside of the lambda,
+     *              minimizing allocations.
+     */
+    interface PerObjectFieldAction<THIS> {
+        void acceptObject(THIS self, String fieldName, Object fieldValue);
+    }
+
+    /**
+     * A specialization of {@link PerObjectFieldAction} called exclusively for int fields to avoid
+     * boxing.
+     */
+    interface PerIntFieldAction<THIS> {
+        void acceptInt(THIS self, String fieldName, int fieldValue);
+    }
+}
diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java
new file mode 100644
index 0000000..63530dc
--- /dev/null
+++ b/core/java/com/android/internal/util/Parcelling.java
@@ -0,0 +1,104 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.util.ArrayMap;
+
+import java.util.regex.Pattern;
+
+/**
+ * Describes a 2-way parcelling contract of type {@code T} into/out of a {@link Parcel}
+ *
+ * @param <T> the type being [un]parcelled
+ */
+public interface Parcelling<T> {
+
+    /**
+     * Write an item into parcel.
+     */
+    void parcel(T item, Parcel dest, int parcelFlags);
+
+    /**
+     * Read an item from parcel.
+     */
+    T unparcel(Parcel source);
+
+
+    /**
+     * A registry of {@link Parcelling} singletons.
+     */
+    class Cache {
+        private Cache() {}
+
+        private static ArrayMap<Class, Parcelling> sCache = new ArrayMap<>();
+
+        /**
+         * Retrieves an instance of a given {@link Parcelling} class if present.
+         */
+        public static @Nullable <P extends Parcelling<?>> P get(Class<P> clazz) {
+            return (P) sCache.get(clazz);
+        }
+
+        /**
+         * Stores an instance of a given {@link Parcelling}.
+         *
+         * @return the provided parcelling for convenience.
+         */
+        public static <P extends Parcelling<?>> P put(P parcelling) {
+            sCache.put(parcelling.getClass(), parcelling);
+            return parcelling;
+        }
+
+        /**
+         * Produces an instance of a given {@link Parcelling} class, by either retrieving a cached
+         * instance or reflectively creating one.
+         */
+        public static <P extends Parcelling<?>> P getOrCreate(Class<P> clazz) {
+            P cached = get(clazz);
+            if (cached != null) {
+                return cached;
+            } else {
+                try {
+                    return put(clazz.newInstance());
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Common {@link Parcelling} implementations.
+     */
+    interface BuiltIn {
+
+        class ForPattern implements Parcelling<Pattern> {
+
+            @Override
+            public void parcel(Pattern item, Parcel dest, int parcelFlags) {
+                dest.writeString(item == null ? null : item.pattern());
+            }
+
+            @Override
+            public Pattern unparcel(Parcel source) {
+                String s = source.readString();
+                return s == null ? null : Pattern.compile(s);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 9fc79cb..364278d 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -194,9 +194,8 @@
     final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>();
     final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>();
 
-    final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppPermissions = new ArrayMap<>();
-    final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppDenyPermissions =
-            new ArrayMap<>();
+    final ArrayMap<String, ArraySet<String>> mSystemExtPrivAppPermissions = new ArrayMap<>();
+    final ArrayMap<String, ArraySet<String>> mSystemExtPrivAppDenyPermissions = new ArrayMap<>();
 
     final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
 
@@ -321,12 +320,20 @@
         return mProductPrivAppDenyPermissions.get(packageName);
     }
 
-    public ArraySet<String> getProductServicesPrivAppPermissions(String packageName) {
-        return mProductServicesPrivAppPermissions.get(packageName);
+    /**
+     * Read from "permission" tags in /system_ext/etc/permissions/*.xml
+     * @return Set of privileged permissions that are explicitly granted.
+     */
+    public ArraySet<String> getSystemExtPrivAppPermissions(String packageName) {
+        return mSystemExtPrivAppPermissions.get(packageName);
     }
 
-    public ArraySet<String> getProductServicesPrivAppDenyPermissions(String packageName) {
-        return mProductServicesPrivAppDenyPermissions.get(packageName);
+    /**
+     * Read from "deny-permission" tags in /system_ext/etc/permissions/*.xml
+     * @return Set of privileged permissions that are explicitly denied.
+     */
+    public ArraySet<String> getSystemExtPrivAppDenyPermissions(String packageName) {
+        return mSystemExtPrivAppDenyPermissions.get(packageName);
     }
 
     public Map<String, Boolean> getOemPermissions(String packageName) {
@@ -398,11 +405,11 @@
         readPermissions(Environment.buildPath(
                 Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);
 
-        // Allow /product_services to customize all system configs
+        // Allow /system_ext to customize all system configs
         readPermissions(Environment.buildPath(
-                Environment.getProductServicesDirectory(), "etc", "sysconfig"), ALLOW_ALL);
+                Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL);
         readPermissions(Environment.buildPath(
-                Environment.getProductServicesDirectory(), "etc", "permissions"), ALLOW_ALL);
+                Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);
     }
 
     void readPermissions(File libraryDir, int permissionFlag) {
@@ -848,7 +855,7 @@
                     } break;
                     case "privapp-permissions": {
                         if (allowPrivappPermissions) {
-                            // privapp permissions from system, vendor, product and product_services
+                            // privapp permissions from system, vendor, product and system_ext
                             // partitions are stored separately. This is to prevent xml files in
                             // the vendor partition from granting permissions to priv apps in the
                             // system partition and vice versa.
@@ -858,17 +865,17 @@
                                     Environment.getOdmDirectory().toPath() + "/");
                             boolean product = permFile.toPath().startsWith(
                                     Environment.getProductDirectory().toPath() + "/");
-                            boolean productServices = permFile.toPath().startsWith(
-                                    Environment.getProductServicesDirectory().toPath() + "/");
+                            boolean systemExt = permFile.toPath().startsWith(
+                                    Environment.getSystemExtDirectory().toPath() + "/");
                             if (vendor) {
                                 readPrivAppPermissions(parser, mVendorPrivAppPermissions,
                                         mVendorPrivAppDenyPermissions);
                             } else if (product) {
                                 readPrivAppPermissions(parser, mProductPrivAppPermissions,
                                         mProductPrivAppDenyPermissions);
-                            } else if (productServices) {
-                                readPrivAppPermissions(parser, mProductServicesPrivAppPermissions,
-                                        mProductServicesPrivAppDenyPermissions);
+                            } else if (systemExt) {
+                                readPrivAppPermissions(parser, mSystemExtPrivAppPermissions,
+                                        mSystemExtPrivAppDenyPermissions);
                             } else {
                                 readPrivAppPermissions(parser, mPrivAppPermissions,
                                         mPrivAppDenyPermissions);
diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h
index 6934d26..06e31a1 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/core/jni/android/graphics/Bitmap.h
@@ -18,8 +18,9 @@
 
 #include <jni.h>
 #include <android/bitmap.h>
-#include <SkBitmap.h>
-#include <SkImageInfo.h>
+
+class SkBitmap;
+struct SkImageInfo;
 
 namespace android {
 
@@ -34,8 +35,8 @@
 };
 
 jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
-            int bitmapCreateFlags, jbyteArray ninePatchChunk = NULL,
-            jobject ninePatchInsets = NULL, int density = -1);
+            int bitmapCreateFlags, jbyteArray ninePatchChunk = nullptr,
+            jobject ninePatchInsets = nullptr, int density = -1);
 
 
 void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap);
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index d29857d..d1b9521 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -100,8 +100,9 @@
         this->endRecording();
         SkASSERT(NULL != mPicture.get());
     }
-    if (NULL != mPicture.get()) {
-        mPicture->playback(canvas->asSkCanvas());
+
+    if (mPicture) {
+        canvas->drawPicture(*mPicture);
     }
 }
 
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 55abc93..58c5871 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -16,7 +16,6 @@
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
-#include "GraphicsJNI.h"
 
 #include <math.h>
 #include <stdio.h>
@@ -33,6 +32,7 @@
 #include <SkBitmap.h>
 
 #include "core_jni_helpers.h"
+#include "android/graphics/Bitmap.h"
 
 #undef LOG_TAG
 #define LOG_TAG "OpenGLUtil"
@@ -43,6 +43,10 @@
 
 namespace android {
 
+static void doThrowIAE(JNIEnv* env, const char* msg = nullptr) {
+    jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+}
+
 static inline
 void mx4transform(float x, float y, float z, float w, const float* pM, float* pDest) {
     pDest[0] = pM[0 + 4 * 0] * x + pM[0 + 4 * 1] * y + pM[0 + 4 * 2] * z + pM[0 + 4 * 3] * w;
@@ -706,7 +710,7 @@
         jlong bitmapPtr)
 {
     SkBitmap nativeBitmap;
-    bitmap::toBitmap(bitmapPtr).getSkBitmap(&nativeBitmap);
+    bitmap::toSkBitmap(bitmapPtr, &nativeBitmap);
     return getInternalFormat(nativeBitmap.colorType());
 }
 
@@ -714,7 +718,7 @@
         jlong bitmapPtr)
 {
     SkBitmap nativeBitmap;
-    bitmap::toBitmap(bitmapPtr).getSkBitmap(&nativeBitmap);
+    bitmap::toSkBitmap(bitmapPtr, &nativeBitmap);
     return getType(nativeBitmap.colorType());
 }
 
@@ -723,7 +727,7 @@
         jlong bitmapPtr, jint type, jint border)
 {
     SkBitmap bitmap;
-    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
+    bitmap::toSkBitmap(bitmapPtr, &bitmap);
     SkColorType colorType = bitmap.colorType();
     if (internalformat < 0) {
         internalformat = getInternalFormat(colorType);
@@ -751,7 +755,7 @@
         jlong bitmapPtr, jint format, jint type)
 {
     SkBitmap bitmap;
-    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
+    bitmap::toSkBitmap(bitmapPtr, &bitmap);
     SkColorType colorType = bitmap.colorType();
     int internalFormat = getInternalFormat(colorType);
     if (format < 0) {
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
index 93f2525..3a08148 100644
--- a/core/jni/android_app_ActivityThread.cpp
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -15,7 +15,6 @@
  */
 
 #include "jni.h"
-#include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
 
 #include <minikin/Layout.h>
diff --git a/core/jni/android_nio_utils.h b/core/jni/android_nio_utils.h
index aa75dd0..4aaa0a7 100644
--- a/core/jni/android_nio_utils.h
+++ b/core/jni/android_nio_utils.h
@@ -17,7 +17,7 @@
 #ifndef _ANDROID_NIO_UTILS_H_
 #define _ANDROID_NIO_UTILS_H_
 
-#include <android_runtime/AndroidRuntime.h>
+#include <nativehelper/JNIHelp.h>
 
 namespace android {
 
@@ -68,12 +68,12 @@
     AutoBufferPointer() = delete;
     AutoBufferPointer(AutoBufferPointer&) = delete;
     AutoBufferPointer& operator=(AutoBufferPointer&) = delete;
-    static void* operator new(std::size_t);
-    static void* operator new[](std::size_t);
-    static void* operator new(std::size_t, void*);
-    static void* operator new[](std::size_t, void*);
-    static void operator delete(void*, std::size_t);
-    static void operator delete[](void*, std::size_t);
+    static void* operator new(size_t);
+    static void* operator new[](size_t);
+    static void* operator new(size_t, void*);
+    static void* operator new[](size_t, void*);
+    static void operator delete(void*, size_t);
+    static void operator delete[](void*, size_t);
 };
 
 }   /* namespace android */
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index c3e7a36..13e1dfa 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -259,6 +259,8 @@
             which_heap = HEAP_NATIVE;
         } else if (base::StartsWith(name, "[stack")) {
             which_heap = HEAP_STACK;
+        } else if (base::StartsWith(name, "[anon:stack_and_tls:")) {
+            which_heap = HEAP_STACK;
         } else if (base::EndsWith(name, ".so")) {
             which_heap = HEAP_SO;
             is_swappable = true;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index d6d9391..bf4ffc7 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -161,7 +161,7 @@
       }
 
       // Generic idmap parameters
-      const char* argv[10];
+      const char* argv[11];
       int argc = 0;
       struct stat st;
 
@@ -193,8 +193,8 @@
         argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
       }
 
-      if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) {
-        argv[argc++] = AssetManager::PRODUCT_SERVICES_OVERLAY_DIR;
+      if (stat(AssetManager::SYSTEM_EXT_OVERLAY_DIR, &st) == 0) {
+        argv[argc++] = AssetManager::SYSTEM_EXT_OVERLAY_DIR;
       }
 
       if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) {
@@ -235,8 +235,8 @@
     input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR);
   }
 
-  if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) {
-    input_dirs.push_back(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR);
+  if (stat(AssetManager::SYSTEM_EXT_OVERLAY_DIR, &st) == 0) {
+    input_dirs.push_back(AssetManager::SYSTEM_EXT_OVERLAY_DIR);
   }
 
   if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index df98cdc..0afbaa0e 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -99,7 +99,9 @@
 
 static struct error_offsets_t
 {
-    jclass mClass;
+    jclass mError;
+    jclass mOutOfMemory;
+    jclass mStackOverflow;
 } gErrorOffsets;
 
 // ----------------------------------------------------------------------------
@@ -207,6 +209,16 @@
     return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
 }
 
+static const char* GetErrorTypeName(JNIEnv* env, jthrowable error) {
+  if (env->IsInstanceOf(error, gErrorOffsets.mOutOfMemory)) {
+    return "OutOfMemoryError";
+  }
+  if (env->IsInstanceOf(error, gErrorOffsets.mStackOverflow)) {
+    return "StackOverflowError";
+  }
+  return nullptr;
+}
+
 // Report a java.lang.Error (or subclass). This will terminate the runtime by
 // calling FatalError with a message derived from the given error.
 static void report_java_lang_error_fatal_error(JNIEnv* env, jthrowable error,
@@ -216,7 +228,7 @@
 
     // Try to get the exception string. Sometimes logcat isn't available,
     // so try to add it to the abort message.
-    std::string exc_msg = "(Unknown exception message)";
+    std::string exc_msg;
     {
         ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(error));
         jmethodID method_id = env->GetMethodID(exc_class.get(), "toString",
@@ -225,15 +237,36 @@
                 env,
                 reinterpret_cast<jstring>(
                         env->CallObjectMethod(error, method_id)));
-        env->ExceptionClear();  // Just for good measure.
+        ScopedLocalRef<jthrowable> new_error(env, nullptr);
+        bool got_jstr = false;
+        if (env->ExceptionCheck()) {
+            new_error = ScopedLocalRef<jthrowable>(env, env->ExceptionOccurred());
+            env->ExceptionClear();
+        }
         if (jstr.get() != nullptr) {
             ScopedUtfChars jstr_utf(env, jstr.get());
             if (jstr_utf.c_str() != nullptr) {
                 exc_msg = jstr_utf.c_str();
+                got_jstr = true;
             } else {
+                new_error = ScopedLocalRef<jthrowable>(env, env->ExceptionOccurred());
                 env->ExceptionClear();
             }
         }
+        if (!got_jstr) {
+            exc_msg = "(Unknown exception message)";
+            const char* orig_type = GetErrorTypeName(env, error);
+            if (orig_type != nullptr) {
+                exc_msg = base::StringPrintf("%s (Error was %s)", exc_msg.c_str(), orig_type);
+            }
+            const char* new_type =
+                new_error == nullptr ? nullptr : GetErrorTypeName(env, new_error.get());
+            if (new_type != nullptr) {
+                exc_msg = base::StringPrintf("%s (toString() error was %s)",
+                                             exc_msg.c_str(),
+                                             new_type);
+            }
+        }
     }
 
     env->Throw(error);
@@ -291,7 +324,7 @@
         ALOGE("%s", msg);
     }
 
-    if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
+    if (env->IsInstanceOf(excep, gErrorOffsets.mError)) {
         report_java_lang_error(env, excep, msg);
     }
 }
@@ -1440,10 +1473,13 @@
 
 static int int_register_android_os_BinderProxy(JNIEnv* env)
 {
-    jclass clazz = FindClassOrDie(env, "java/lang/Error");
-    gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
+    gErrorOffsets.mError = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/Error"));
+    gErrorOffsets.mOutOfMemory =
+        MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/OutOfMemoryError"));
+    gErrorOffsets.mStackOverflow =
+        MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/StackOverflowError"));
 
-    clazz = FindClassOrDie(env, kBinderProxyPathName);
+    jclass clazz = FindClassOrDie(env, kBinderProxyPathName);
     gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
     gBinderProxyOffsets.mGetInstance = GetStaticMethodIDOrDie(env, clazz, "getInstance",
             "(JJ)Landroid/os/BinderProxy;");
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index c9eac79..ca32b00 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -17,7 +17,6 @@
 #define LOG_TAG "OpenGLRenderer"
 
 #include "jni.h"
-#include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 78dd1aa..a579229 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -21,10 +21,10 @@
 #include "android_util_Binder.h"
 #include "android_hardware_input_InputWindowHandle.h"
 #include "android/graphics/Bitmap.h"
-#include "android/graphics/GraphicsJNI.h"
 #include "android/graphics/Region.h"
 #include "core_jni_helpers.h"
 
+#include <android_runtime/AndroidRuntime.h>
 #include <android-base/chrono_utils.h>
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedUtfChars.h>
@@ -50,6 +50,14 @@
 
 namespace android {
 
+static void doThrowNPE(JNIEnv* env) {
+    jniThrowNullPointerException(env, NULL);
+}
+
+static void doThrowIAE(JNIEnv* env, const char* msg = nullptr) {
+    jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+}
+
 static const char* const OutOfResourcesException =
     "android/view/Surface$OutOfResourcesException";
 
diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
index d20bae2..d629d63 100644
--- a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
+++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include "jni.h"
 #include <nativehelper/JNIHelp.h>
+#include <utils/LightRefBase.h>
 #include "core_jni_helpers.h"
 
 namespace android {
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 940ac22..5aea848 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -30,10 +30,6 @@
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 
-#include <GraphicsJNI.h>
-#include <SkBitmap.h>
-#include <SkPixelRef.h>
-
 #include <ui/ANativeObjectBase.h>
 
 namespace android {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index e5d6393..ea4b252 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -100,8 +100,8 @@
   static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/";
   static const char* kSystemProductOverlayDir = "/system/product/overlay/";
   static const char* kProductOverlayDir = "/product/overlay";
-  static const char* kSystemProductServicesOverlayDir = "/system/product_services/overlay/";
-  static const char* kProductServicesOverlayDir = "/product_services/overlay";
+  static const char* kSystemSystemExtOverlayDir = "/system/system_ext/overlay/";
+  static const char* kSystemExtOverlayDir = "/system_ext/overlay";
   static const char* kSystemOdmOverlayDir = "/system/odm/overlay";
   static const char* kOdmOverlayDir = "/odm/overlay";
   static const char* kSystemOemOverlayDir = "/system/oem/overlay";
@@ -113,8 +113,8 @@
        || android::base::StartsWith(path, kVendorOverlayDir)
        || android::base::StartsWith(path, kSystemProductOverlayDir)
        || android::base::StartsWith(path, kProductOverlayDir)
-       || android::base::StartsWith(path, kSystemProductServicesOverlayDir)
-       || android::base::StartsWith(path, kProductServicesOverlayDir)
+       || android::base::StartsWith(path, kSystemSystemExtOverlayDir)
+       || android::base::StartsWith(path, kSystemExtOverlayDir)
        || android::base::StartsWith(path, kSystemOdmOverlayDir)
        || android::base::StartsWith(path, kOdmOverlayDir)
        || android::base::StartsWith(path, kSystemOemOverlayDir)
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index a3d4798..71e3860 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -7,7 +7,7 @@
 yro@google.com
 
 # Settings UI
-per-file settings_enums.proto=zhfan@google.com
+per-file settings_enums.proto=tmfang@google.com
 
 # Frameworks
 ogunwale@google.com
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index c023438..3323095 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2401,4 +2401,11 @@
     // OS: Q
     // Note: Gear icon is shown next to gesture navigation preference and opens sensitivity dialog
     SETTINGS_GESTURE_NAV_BACK_SENSITIVITY_DLG = 1748;
+
+    // ---- End Q Constants, all Q constants go above this line ----
+    // OPEN: Settings > Network & Internet > Wi-Fi > Click new network
+    // CATEGORY: SETTINGS
+    // OS: R
+    SETTINGS_WIFI_CONFIGURE_NETWORK = 1800;
+
 }
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 784e854..c534aa4 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -231,15 +231,6 @@
     // will use heartbeats, false will use a rolling window.
     optional bool use_heartbeats = 23;
 
-    message TimeController {
-        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
-        // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
-        // ready now.
-        optional bool skip_not_ready_jobs = 1;
-    }
-    optional TimeController time_controller = 25;
-
     message QuotaController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -304,6 +295,15 @@
     }
     optional QuotaController quota_controller = 24;
 
+    message TimeController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+        // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
+        // ready now.
+        reserved 1; // skip_not_ready_jobs
+    }
+    optional TimeController time_controller = 25;
+
     // Max number of jobs, when screen is ON.
     optional MaxJobCountsPerMemoryTrimLevelProto max_job_counts_screen_on = 26;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 119d5ea..aa440d3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -536,6 +536,7 @@
     <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_CHANGED" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED" />
+    <protected-broadcast android:name="android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED" />
     <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED" />
@@ -726,7 +727,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.SEND_SMS"
@@ -740,7 +741,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_SMS"
@@ -754,7 +755,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.READ_SMS"
@@ -768,7 +769,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_WAP_PUSH"
@@ -782,7 +783,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_MMS"
@@ -805,7 +806,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
 
          @hide Pending API council approval -->
@@ -851,7 +852,7 @@
       targetSdkVersion}</a> is 4 or higher.
 
       <p> This is a soft restricted permission which cannot be held by an app it its
-      full form until the installer on record did not whitelist the permission.
+      full form until the installer on record whitelists the permission.
       Specifically, if the permission is whitelisted the holder app can access
       external storage and the visual and aural media collections while if the
       permission is not whitelisted the holder app can only access to the visual
@@ -859,7 +860,7 @@
       meaning that the whitelist state can be specified only at install time and
       cannot change until the app is installed. For more details see
       {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-     -->
+     <p>Protection level: dangerous -->
     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sdcardRead"
@@ -880,8 +881,9 @@
          read/write files in your application-specific directories returned by
          {@link android.content.Context#getExternalFilesDir} and
          {@link android.content.Context#getExternalCacheDir}.
-         <p>Is this permission is not whitelisted for an app that targets an API level before
+         <p>If this permission is not whitelisted for an app that targets an API level before
          {@link android.os.Build.VERSION_CODES#Q} this permission cannot be granted to apps.</p>
+         <p>Protection level: dangerous</p>
     -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -891,7 +893,8 @@
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to access any geographic locations persisted in the
-         user's shared collection. -->
+         user's shared collection.
+         <p>Protection level: dangerous -->
     <permission android:name="android.permission.ACCESS_MEDIA_LOCATION"
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_mediaLocation"
@@ -948,7 +951,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
@@ -994,7 +997,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.READ_CALL_LOG"
@@ -1018,7 +1021,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.WRITE_CALL_LOG"
@@ -1034,7 +1037,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record did not whitelist the permission. For more details see
+         the installer on record whitelists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
 
          @deprecated Applications should use {@link android.telecom.CallRedirectionService} instead
@@ -1693,7 +1696,7 @@
 
     <!-- Allows applications to pair bluetooth devices without user interaction, and to
          allow or disallow phonebook access or message access.
-         This is not available to third party applications. -->
+         <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
@@ -2543,7 +2546,8 @@
         android:protectionLevel="signature" />
 
     <!-- Allows an application to modify the current configuration, such
-         as locale. -->
+         as locale.
+         <p>Protection level: signature|privileged|development -->
     <permission android:name="android.permission.CHANGE_CONFIGURATION"
         android:protectionLevel="signature|privileged|development" />
 
@@ -2842,7 +2846,8 @@
     <!-- ==================================== -->
     <eat-comment />
 
-    <!-- Allows access to the list of accounts in the Accounts Service. -->
+    <!-- Allows access to the list of accounts in the Accounts Service.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
@@ -3428,7 +3433,8 @@
         android:protectionLevel="signature" />
 
     <!-- Old permission for deleting an app's cache files, no longer used,
-         but signals for us to quietly ignore calls instead of throwing an exception. -->
+         but signals for us to quietly ignore calls instead of throwing an exception.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.DELETE_CACHE_FILES"
         android:protectionLevel="signature|privileged" />
 
@@ -3791,7 +3797,8 @@
     <!-- Allows an application to collect component usage
          statistics
          <p>Declaring the permission implies intention to use the API and the user of the
-         device can grant permission through the Settings application. -->
+         device can grant permission through the Settings application.
+         <p>Protection level: signature|privileged|development|appop -->
     <permission android:name="android.permission.PACKAGE_USAGE_STATS"
         android:protectionLevel="signature|privileged|development|appop" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
@@ -3814,14 +3821,14 @@
 
     <!-- Permission an application must hold in order to use
          {@link android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}.
-         This is a normal permission: an app requesting it will always be granted the
-         permission, without the user needing to approve or see it. -->
+         <p>Protection level: normal -->
     <permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
         android:label="@string/permlab_requestIgnoreBatteryOptimizations"
         android:description="@string/permdesc_requestIgnoreBatteryOptimizations"
         android:protectionLevel="normal" />
 
-    <!-- Allows an application to collect battery statistics -->
+    <!-- Allows an application to collect battery statistics
+         <p>Protection level: signature|privileged|development -->
     <permission android:name="android.permission.BATTERY_STATS"
         android:protectionLevel="signature|privileged|development" />
 
@@ -3851,7 +3858,8 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.widget.RemoteViewsService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.BIND_REMOTEVIEWS"
         android:protectionLevel="signature|privileged" />
 
@@ -3893,7 +3901,8 @@
          to the path in the provider where global search queries are
          performed.  This permission can not be held by regular applications;
          it is used by applications to protect themselves from everyone else
-         besides global search. -->
+         besides global search.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.GLOBAL_SEARCH"
         android:protectionLevel="signature|privileged" />
 
@@ -4432,7 +4441,8 @@
     <permission android:name="android.permission.MODIFY_THEME_OVERLAY"
                 android:protectionLevel="signature" />
 
-    <!-- Allows an instant app to create foreground services. -->
+    <!-- Allows an instant app to create foreground services.
+         <p>Protection level: signature|development|instant|appop -->
     <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
         android:protectionLevel="signature|development|instant|appop" />
 
@@ -4502,7 +4512,8 @@
     <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission. -->
+    <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission.
+           <p>Protection level: signature -->
     <permission android:name="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE"
         android:protectionLevel="signature" />
 
@@ -4534,13 +4545,15 @@
     <permission android:name="android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"
         android:protectionLevel="signature" />
 
-    <!-- Allows financial apps to read filtered sms messages. -->
+    <!-- Allows financial apps to read filtered sms messages.
+         Protection level: signature|appop  -->
     <permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS"
         android:protectionLevel="signature|appop" />
 
     <!-- Required for apps targeting {@link android.os.Build.VERSION_CODES#Q} that want to use
          {@link android.app.Notification.Builder#setFullScreenIntent notification full screen
-         intents}.  -->
+         intents}.
+         <p>Protection level: normal -->
     <permission android:name="android.permission.USE_FULL_SCREEN_INTENT"
                 android:protectionLevel="normal" />
 
@@ -4597,6 +4610,7 @@
                  android:supportsRtl="true"
                  android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
                  android:defaultToDeviceProtectedStorage="true"
+                 android:forceQueryable="true"
                  android:directBootAware="true">
         <activity android:name="com.android.internal.app.ChooserActivity"
                 android:theme="@style/Theme.DeviceDefault.Resolver"
@@ -4980,6 +4994,7 @@
         <service
                 android:name="com.android.server.autofill.AutofillCompatAccessibilityService"
                 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+                android:visibleToInstantApps="true"
                 android:exported="true">
             <meta-data
                     android:name="android.accessibilityservice"
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 13fef67..575295b 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -15,7 +15,7 @@
   ~ limitations under the License
   -->
 
-<FrameLayout
+<com.android.internal.widget.MediaNotificationView
     android:id="@+id/status_bar_latest_event_content"
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
@@ -24,8 +24,8 @@
     android:tag="media"
     >
     <ImageView android:id="@+id/right_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
         android:adjustViewBounds="true"
         android:layout_gravity="top|end"
         android:scaleType="centerCrop"
@@ -91,4 +91,4 @@
             android:layout_alignParentBottom="true"
         />
     </LinearLayout>
-</FrameLayout>
+</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 74f0e68c..7a0d475 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Beweeg foon na links."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Beweeg foon na regs."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Kyk asseblief meer reguit na jou toestel."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Kan nie jou gesig sien nie. Kyk na die foon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posisioneer jou gesig direk voor die foon."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Te veel beweging. Hou foon stil."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Skryf jou gesig asseblief weer in."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Kan nie meer gesig herken nie. Probeer weer."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Maak oop met"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Maak oop met %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Maak oop"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Maak <xliff:g id="HOST">%1$s</xliff:g>-skakels oop met"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Maak skakels oop met"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Maak skakels oop met <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Maak <xliff:g id="HOST">%1$s</xliff:g>-skakels oop met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Verleen toegang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redigeer met"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigeer met %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Begin webblaaier?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aanvaar oproep?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altyd"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Stel om altyd oop te maak"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Net een keer"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s steun nie werkprofiel nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index af0ed28c..11ab44d 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ስልክን ወደ ግራ ያንቀሳቅሱ።"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ስልክን ወደ ቀኝ ያንቀሳቅሱ።"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"እባክዎ መሣሪያዎን ይበልጥ በቀጥታ ይመልከቱ።"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"የእርስዎን ፊት መመልከት አይችልም። ስልኩ ላይ ይመልከቱ።"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"መልክዎን በቀጥታ ከስልኩ ፊት ያድርጉት።"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ከልክ በላይ ብዙ እንቅስቃሴ። ስልኩን ቀጥ አድርገው ይያዙት።"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"እባክዎ ፊትዎን እንደገና ያስመዝግቡ"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"ከእንግዲህ ፊትን ለይቶ ማወቅ አይችልም። እንደገና ይሞክሩ።"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ክፈት በ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"ክፈት በ%1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ክፈት"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን ክፈት ከዚህ ጋር"</string>
+    <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="HOST">%1$s</xliff:g> አገናኞችን ከ <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ክፈት"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"መዳረሻ ስጥ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ያርትዑ በ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"ያርትዑ በ%1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ማሰሺያን አስነሳ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"ጥሪ ተቀበል?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ዘወትር"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"ሁልጊዜ ክፍት ወደ የሚል ተቀናብሯል"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"አንዴ ብቻ"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ቅንብሮች"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s የስራ መገለጫ አይደግፍም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 603239f..6edc933 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -580,7 +580,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"يُرجى نقل الهاتف إلى اليمين."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"يُرجى نقل الهاتف إلى اليسار."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"يُرجى النظر إلى جهازك مباشرة أكثر."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"يتعذّر رؤية وجهك. يُرجى النظر إلى الهاتف."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"ضع وجهك أمام الهاتف مباشرة."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"حركة أكثر من اللازم يُرجى حمل بدون حركة."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"يُرجى إعادة تسجيل وجهك."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"لم يعُد يمكن التعرّف على الوجه. حاول مرة أخرى."</string>
@@ -1211,14 +1211,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"فتح باستخدام"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏فتح باستخدام %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"فتح"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"فتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام"</string>
+    <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="HOST">%1$s</xliff:g> باستخدام <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"منح إذن الوصول"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"تعديل باستخدام"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏تعديل باستخدام %1$s"</string>
@@ -1682,8 +1678,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"تشغيل المتصفح؟"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"هل تريد قبول المكالمة؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"دومًا"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"ضبط على الفتح دائمًا"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"مرة واحدة فقط"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"الإعدادات"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏لا يدعم %1$s الملفات الشخصية للعمل"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index b126468..3660403 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ফ’নটো বাওঁফালে নিয়ক।"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ফ’নটো সোঁফালে নিয়ক।"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"আপোনাৰ ডিভাইচটোলৈ অধিক পোনে পোনে চাওক।"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"আপোনাৰ মুখমণ্ডল দেখা নাই। ফ’নটোলৈ চাওক।"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"আপোনাৰ মুখখন পোনপটীয়াকৈ ফ’নটোৰ সন্মুখত ৰাখক।"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"বেছি লৰচৰ কৰি আছে। ফ’নটো স্থিৰকৈ ধৰক।"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"আপোনাৰ মুখমণ্ডল পুনৰ পঞ্জীয়ন কৰক।"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"মুখমণ্ডল আৰু চিনাক্ত কৰিব নোৱাৰি। আকৌ চেষ্টা কৰক।"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ইয়াৰ জৰিয়তে খোলক"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sৰ জৰিয়তে খোলক"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"খোলক"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> লিংকসমূহ ইয়াৰ জৰিয়তে খোলক"</string>
+    <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="HOST">%1$s</xliff:g> লিংকসমূহ <xliff:g id="APPLICATION">%2$s</xliff:g>ৰ জৰিয়তে খোলক"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"এক্সেছ দিয়ক"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ইয়াৰ দ্বাৰা সম্পাদনা কৰক"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sৰদ্বাৰা সম্পাদনা কৰক"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ব্ৰাউজাৰ লঞ্চ কৰিবনে?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"কল স্বীকাৰ কৰিবনে?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"সদায়"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"সদায় খোলক-লৈ ছেট কৰক"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"মাত্ৰ এবাৰ"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ছেটিংসমূহ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sএ কৰ্মস্থানৰ প্ৰ\'ফাইল সমৰ্থন নকৰে।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index f372fec..e2b3998 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Telefonu sola hərəkət etdirin."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Telefonu sağa hərəkət etdirin."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Birbaşa cihaza baxın."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Üzünüz görünmür. Telefona baxın."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Üzünüzü telefonun qarşısında sabit saxlayın."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Cihaz stabil deyil. Telefonu tərpətməyin."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Üzünüzü yenidən qeydiyyatdan keçirin."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Üzü artıq tanımaq olmur. Yenidən cəhd edin."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Bununla açın"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ilə açın"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Açın"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> linklərini belə açın:"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Linkləri belə açın:"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Linkləri <xliff:g id="APPLICATION">%1$s</xliff:g> ilə açın"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> linklərini <xliff:g id="APPLICATION">%2$s</xliff:g> ilə açın"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"İcazə verin"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Bununla düzəliş edin:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ilə düzəliş edin"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Brauzer işə salınsın?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Zəngi qəbul edək?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Həmişə"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"\"Həmişə açıq\" olaraq ayarlayın"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Sadəcə bir dəfə"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s iş profilini dəstəkləmir"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b4faae7..821b730 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -571,7 +571,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Pomerite telefon ulevo."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Pomerite telefon udesno."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Gledajte pravo u uređaj."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ne vidi se lice. Gledajte u telefon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Postavite lice direktno ispred telefona"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Mnogo se pomerate. Držite telefon mirno."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Ponovo registrujte lice."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Više ne može da se prepozna lice. Probajte ponovo."</string>
@@ -1151,14 +1151,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvorite pomoću"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvorite pomoću aplikacije %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otvarajte <xliff:g id="HOST">%1$s</xliff:g> linkove pomoću"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otvaratej linkove pomoću"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otvarajte linkove pomoću aplikacije <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otvarajte <xliff:g id="HOST">%1$s</xliff:g> linkove pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Izmenite pomoću"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Izmenite pomoću aplikacije %1$s"</string>
@@ -1613,8 +1609,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Želite li da pokrenete pregledač?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Želite li da prihvatite poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvek"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Podesi na „uvek otvaraj“"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Podešavanja"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 996a02b..d573202 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -574,7 +574,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Перамясціце тэлефон улева."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Перамясціце тэлефон управа."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Глядзіце прама на экран прылады."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Не відаць твару. Глядзіце на тэлефон."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Трымайце тэлефон прама перад тварам."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Трымайце прыладу нерухома. Трымайце тэлефон роўна."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Паўтарыце рэгістрацыю твару."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Не ўдаецца распазнаць твар. Паўтарыце спробу."</string>
@@ -1171,14 +1171,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Адкрыць з дапамогай"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Адкрыць з дапамогай %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Адкрыць"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Адкрываць спасылкі <xliff:g id="HOST">%1$s</xliff:g> з дапамогай"</string>
+    <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="HOST">%1$s</xliff:g>з дапамогай праграмы \"<xliff:g id="APPLICATION">%2$s</xliff:g>\""</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даць доступ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Рэдагаваць з дапамогай"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Рэдагаваць з дапамогай %1$s"</string>
@@ -1636,8 +1632,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Запусцiць браўзер?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прыняць выклік?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Заўсёды"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Прызначыць стандартна для адкрыцця"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Толькі адзін раз"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налады"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не падтрымлівае працоўны профіль"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index e4e1e80..e073b7d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Преместете телефона наляво."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Преместете телефона надясно."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Моля, гледайте точно към устройството си."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Лицето ви не се вижда. Погледнете към телефона."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Позиционирайте лицето си директно пред телефона."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Твърде много движение. Дръжте телефона неподвижно."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Моля, регистрирайте лицето си отново."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Лицето не бе разпознато. Опитайте отново."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Отваряне чрез"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отваряне чрез %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отваряне"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> посредством"</string>
+    <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="HOST">%1$s</xliff:g> посредством <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даване на достъп"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редактиране чрез"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактиране чрез %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Да се стартира ли браузърът?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Да се приеме ли обаждането?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Винаги"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Задаване винаги да се отваря"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Само веднъж"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддържа служебен потребителски профил"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index ca4d122..368ff90 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ফোনটি বাঁদিকে সরান।"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ফোনটি ডানদিকে সরান।"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"সরাসরি ডিভাইসের দিকে তাকান।"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"আপনার মুখ দেখা যাচ্ছে না। ফোনের দিকে তাকান।"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"আপনার মুখ সরাসরি ফোনের সামনে রাখুন।"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"খুব বেশি নড়ছে। ফোনটি যাতে না কাঁপে সেইভাবে ধরুন।"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"আপনার মুখের ছবি আবার নথিভুক্ত করুন।"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"আর মুখ চিনতে পারবেন না। আবার চেষ্টা করুন।"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"এর মাধ্যমে খুলুন"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s দিয়ে খুলুন"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"খুলুন"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"এই ব্রাউজারে <xliff:g id="HOST">%1$s</xliff:g> লিঙ্কটি খুলুন"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"এর মাধ্যমে সম্পাদনা করুন"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s দিয়ে সম্পাদনা করুন"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ব্রাউজার লঞ্চ করতে চান?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"কল গ্রহণ করবেন?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"সবসময়"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"\'সবসময় খোলা থাকবে\' হিসেবে সেট করুন"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"শুধু একবার"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"সেটিংস"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s কর্মস্থলের প্রোফাইল সমর্থন করে না।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index fd44128..ce852b6 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -127,7 +127,7 @@
     <item msgid="3910386316304772394">"Da biste pozivali i slali poruke koristeći WiFi mrežu, prvo zatražite od operatera da postavi tu uslugu. Zatim ponovo uključite pozivanje putem WiFi-ja u Postavkama. (Kôd greške: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
   </string-array>
   <string-array name="wfcOperatorErrorNotificationMessages">
-    <item msgid="7372514042696663278">"Došlo je do problema prilikom registracije pozivanja putem WiFi mreže kod vašeg operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
+    <item msgid="7372514042696663278">"Došlo je do problema prilikom registracije pozivanja putem WiFi mreže kod vašeg mobilnog operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
     <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
     <skip />
@@ -571,7 +571,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Pomjerite telefon ulijevo."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Pomjerite telefon udesno."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Gledajte direktno u uređaj."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ne vidi se lice. Gledajte u telefon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Postavite lice direktno ispred telefona"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Previše pokreta. Držite telefon mirno."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Ponovo registrirajte lice."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Nije više moguće prepoznati lice. Pokušajte opet."</string>
@@ -802,7 +802,7 @@
     <string name="quick_contacts_not_available" msgid="746098007828579688">"Nije pronađena aplikacija za pregled ovog kontakta."</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Unesite PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Unesite PUK i novi PIN"</string>
-    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK kôd"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Novi PIN"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"Dodirnite za unos lozinke"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Unesite lozinku za otključavanje tipkovnice"</string>
@@ -894,7 +894,7 @@
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Otključavanje licem."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Otključavanje pinom."</string>
     <string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"Otključavanje Pin-om za Sim."</string>
-    <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Otključavanje Puk-om za Sim."</string>
+    <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Otključavanje SIM-a PUK-om"</string>
     <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Otključavanje lozinkom."</string>
     <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Uzorak oblasti."</string>
     <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblast za pomjeranje klizača."</string>
@@ -1151,14 +1151,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvori koristeći"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvori koristeći %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otvaranje linkova pomoću"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otvaranje linkova pomoću aplikacije <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Uredi koristeći"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uredi koristeći %1$s"</string>
@@ -1547,7 +1543,7 @@
     <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Povećaj sate"</string>
     <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Smanji sate"</string>
     <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Postavi za poslijepodne (PM)"</string>
-    <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Postavi za prijepodne (AM)"</string>
+    <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Postavi za prijepodne"</string>
     <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Povećaj mjesece"</string>
     <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Smanji mjesece"</string>
     <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Povećaj dane"</string>
@@ -1615,8 +1611,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Pokretanje preglednika?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Postavi da se uvijek otvara"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo ovaj put"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 1638fd8..bbf1736 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Mou el telèfon cap a l\'esquerra."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Mou el telèfon cap a la dreta."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Mira més directament cap al dispositiu."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"No se\'t veu la cara. Mira el telèfon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posa la cara directament davant del telèfon."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Massa moviment. Subjecta bé el telèfon."</string>
     <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>
@@ -595,7 +595,7 @@
   </string-array>
     <string name="face_icon_content_description" msgid="4024817159806482191">"Icona facial"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"llegir la configuració de sincronització"</string>
-    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet que l\'aplicació llegeixi la configuració de sincronització d\'un compte. Per exemple, això pot determinar que l\'aplicació Persones estigui sincronitzada amb un compte."</string>
+    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet que l\'aplicació llegeixi la configuració de sincronització d\'un compte. Per exemple, això pot determinar que l\'aplicació Contactes estigui sincronitzada amb un compte."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar o desactivar la sincronització"</string>
     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Permet que una aplicació modifiqui la configuració de sincronització d\'un compte. Per exemple, aquesta acció es pot fer servir per activar la sincronització de l\'aplicació Persones amb un compte."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"llegir les estadístiques de sincronització"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Obre amb"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Obre amb %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Obre"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Obre els enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Obre els enllaços amb"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Obre els enllaços amb <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Obre els enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dona accés"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edita amb"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edita amb %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vols iniciar el navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vols acceptar la trucada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Obre sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Només una vegada"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuració"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admet perfils professionals."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 5208e5b..4171a8b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -574,7 +574,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Přesuňte telefon vlevo."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Přesuňte telefon vpravo."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Dívejte se přímo na zařízení."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Obličej není vidět. Podívejte se na telefon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Umístěte obličej přímo před telefon."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Příliš mnoho pohybu. Držte telefon nehybně."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Zaznamenejte obličej znovu."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Obličej už nelze rozpoznat. Zkuste to znovu."</string>
@@ -1171,14 +1171,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otevřít v aplikaci"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otevřít v aplikaci %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otevřít"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Odkazy <xliff:g id="HOST">%1$s</xliff:g> otevírat pomocí aplikace"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Odkazy otevírat pomocí aplikace"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Odkazy otevírat pomocí aplikace <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Odkazy <xliff:g id="HOST">%1$s</xliff:g> otevírat pomocí aplikace <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udělit přístup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Upravit v aplikaci"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upravit v aplikaci %1$s"</string>
@@ -1636,8 +1632,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Spustit prohlížeč?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Přijmout hovor?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Nastavit na Otevírat vždy"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Pouze jednou"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavení"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s pracovní profily nepodporuje."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 401fa4f7..b6cb874 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Flyt telefonen til venstre."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Flyt telefonen til højre."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Kig mere direkte på din enhed."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Dit ansigt kan ikke registreres. Kig på telefonen."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Sørg for, at dit ansigt er direkte foran telefonen."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Der er for meget bevægelse. Hold telefonen stille."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registrer dit ansigt igen."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ansigtet kan ikke længere genkendes. Prøv igen."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Åbn med"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åbn med %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åbn"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Åbn <xliff:g id="HOST">%1$s</xliff:g>-links med"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Åbn links med"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Åbn links med <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Åbn <xliff:g id="HOST">%1$s</xliff:g>-links med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Giv adgang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vil du starte browseren?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare opkaldet?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altid"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Angiv som altid åben"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Kun én gang"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Indstillinger"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s understøtter ikke arbejdsprofil"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 67c179d..114d801 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -316,15 +316,15 @@
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Fensterinhalte abrufen"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Die Inhalte eines Fensters, mit dem du interagierst, werden abgerufen."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"\"Tippen &amp; Entdecken\" aktivieren"</string>
-    <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Berührte Elemente werden laut vorgelesen und der Bildschirm kann über Gesten erkundet werden."</string>
+    <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Berührte Elemente werden laut vorgelesen und der Bildschirm kann über Touch-Gesten erkundet werden."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Text bei der Eingabe beobachten"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Einschließlich personenbezogener Daten wie Kreditkartennummern und Passwörter."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Displayvergrößerung festlegen"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Legt die Zoom-Stufe und -Position auf dem Display fest."</string>
-    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gesten möglich"</string>
-    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Tippen, Wischen, Zusammenziehen und andere Gesten möglich."</string>
-    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Bewegungen auf dem Fingerabdrucksensor"</string>
-    <string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"Erfasst Bewegungen auf dem Fingerabdrucksensor des Geräts."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Touch-Gesten möglich"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Tippen, Wischen, Zusammenziehen und andere Touch-Gesten möglich."</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerabdrucksensor-Gesten"</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"Erfasst Touch-Gesten auf dem Fingerabdrucksensor des Geräts."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Ermöglicht der App, die Statusleiste zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"Statusleiste darstellen"</string>
@@ -429,7 +429,7 @@
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"Diese App kann jederzeit Audio über das Mikrofon aufnehmen."</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"Befehle an die SIM senden"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Ermöglicht der App das Senden von Befehlen an die SIM-Karte. Dies ist äußerst risikoreich."</string>
-    <string name="permlab_activityRecognition" msgid="3634590230567608356">"körperlichen Aktivitäten erkennen"</string>
+    <string name="permlab_activityRecognition" msgid="3634590230567608356">"Körperliche Aktivitäten erkennen"</string>
     <string name="permdesc_activityRecognition" msgid="3143453925156552894">"Diese App kann deine körperliche Aktivität erkennen."</string>
     <string name="permlab_camera" msgid="3616391919559751192">"Bilder und Videos aufnehmen"</string>
     <string name="permdesc_camera" msgid="5392231870049240670">"Diese App kann mit der Kamera jederzeit Bilder und Videos aufnehmen."</string>
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Beweg das Smartphone nach links."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Beweg das Smartphone nach rechts."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Bitte sieh direkt auf dein Gerät."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Gesicht wurde nicht gefunden. Blicke aufs Telefon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Halte dein Gesicht direkt vor dein Smartphone."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Zu viel Unruhe. Halte das Smartphone ruhig."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Bitte registriere dein Gesicht noch einmal."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Gesicht wird nicht mehr erkannt. Erneut versuchen."</string>
@@ -971,8 +971,8 @@
     <string name="searchview_description_submit" msgid="2688450133297983542">"Anfrage senden"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Sprachsuche"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"\"Tippen &amp; Entdecken\" aktivieren?"</string>
-    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder Gesten ausführen, um mit dem Tablet zu kommunizieren."</string>
-    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder Gesten ausführen, um mit dem Telefon zu kommunizieren."</string>
+    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder über Touch-Gesten mit dem Tablet kommunizieren."</string>
+    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder über Touch-Gesten mit dem Telefon kommunizieren."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
     <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Öffnen mit"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mit %1$s öffnen"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öffnen"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Links von <xliff:g id="HOST">%1$s</xliff:g> öffnen mit"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Links öffnen mit"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Links mit <xliff:g id="APPLICATION">%1$s</xliff:g> öffnen"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Links von <xliff:g id="HOST">%1$s</xliff:g> mit <xliff:g id="APPLICATION">%2$s</xliff:g> öffnen"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Zugriff erlauben"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Bearbeiten mit"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Mit %1$s bearbeiten"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Browser starten?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Anruf annehmen?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Immer"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Auf \"Immer geöffnet\" festlegen"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Nur diesmal"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Einstellungen"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Das Arbeitsprofil wird von %1$s nicht unterstützt."</string>
@@ -1675,8 +1670,8 @@
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung deaktiviert"</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</string>
     <string name="accessibility_button_prompt_text" msgid="1176658502969738564">"Wähle den Dienst aus, der verwendet werden soll, wenn du auf die Schaltfläche für die Bedienungshilfen tippst:"</string>
-    <string name="accessibility_gesture_prompt_text" msgid="8259145549733019401">"Wähle den Dienst aus, der mit der Bewegung für die Bedienungshilfen verwendet werden soll (mit zwei Fingern vom unteren Bildschirmrand nach oben wischen):"</string>
-    <string name="accessibility_gesture_3finger_prompt_text" msgid="1041435574275047665">"Wähle den Dienst aus, der mit der Geste für die Bedienungshilfen verwendet werden soll (mit drei Fingern vom unteren Bildschirmrand nach oben wischen):"</string>
+    <string name="accessibility_gesture_prompt_text" msgid="8259145549733019401">"Wähle den Dienst aus, der mit der Touch-Geste für die Bedienungshilfen verwendet werden soll (mit zwei Fingern vom unteren Bildschirmrand nach oben wischen):"</string>
+    <string name="accessibility_gesture_3finger_prompt_text" msgid="1041435574275047665">"Wähle den Dienst aus, der mit der Touch-Geste für die Bedienungshilfen verwendet werden soll (mit drei Fingern vom unteren Bildschirmrand nach oben wischen):"</string>
     <string name="accessibility_button_instructional_text" msgid="7003212763213614833">"Wenn du zwischen den Diensten wechseln möchtest, halte die Schaltfläche für die Bedienungshilfen gedrückt."</string>
     <string name="accessibility_gesture_instructional_text" msgid="5261788874937410950">"Wenn du zwischen den Diensten wechseln möchtest, wische mit zwei Fingern nach oben und halte sie gedrückt."</string>
     <string name="accessibility_gesture_3finger_instructional_text" msgid="4969448938984394550">"Wenn du zwischen den Diensten wechseln möchtest, wische mit drei Fingern nach oben und halte sie gedrückt."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 87d0844..44357ff 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Μετακινήστε το τηλέφωνο στα αριστερά."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Μετακινήστε το τηλέφωνο στα δεξιά."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Κοιτάξτε απευθείας τη συσκευή σας."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Δεν εντοπίστηκε το πρόσωπό σας. Δείτε το τηλέφωνο."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Στρέψτε το πρόσωπό σάς απευθείας στο τηλέφωνο."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Πάρα πολλή κίνηση. Κρατήστε σταθερό το τηλέφωνο."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Καταχωρίστε ξανά το πρόσωπό σας."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Αδύνατη η αναγνώριση του προσώπου. Επανάληψη."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Άνοιγμα με"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Άνοιγμα με %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Άνοιγμα"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με"</string>
+    <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="HOST">%1$s</xliff:g> με την εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Παροχή πρόσβασης"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Επεξεργασία με"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Επεξεργασία με %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Εκκίνηση προγράμματος περιήγησης;"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Αποδοχή κλήσης;"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Πάντα"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Ορισμός ως πάντα ανοικτής"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Μόνο μία φορά"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ρυθμίσεις"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Το προφίλ εργασίας δεν υποστηρίζεται από %1$s"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 51b031b..cc389f3 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Move phone to the left."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Move phone to the right."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Please look more directly at your device."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Can’t see your face. Look at the phone."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Position your face directly in front of the phone."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Too much motion. Hold phone steady."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Please re-enroll your face."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"No longer able to recognise face. Try again."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Open links with"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Set to always open"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index fd14d4d..0e6d49c 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Move phone to the left."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Move phone to the right."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Please look more directly at your device."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Can’t see your face. Look at the phone."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Position your face directly in front of the phone."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Too much motion. Hold phone steady."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Please re-enroll your face."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"No longer able to recognise face. Try again."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Open links with"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Set to always open"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 51b031b..cc389f3 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Move phone to the left."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Move phone to the right."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Please look more directly at your device."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Can’t see your face. Look at the phone."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Position your face directly in front of the phone."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Too much motion. Hold phone steady."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Please re-enroll your face."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"No longer able to recognise face. Try again."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Open links with"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Set to always open"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 51b031b..cc389f3 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Move phone to the left."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Move phone to the right."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Please look more directly at your device."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Can’t see your face. Look at the phone."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Position your face directly in front of the phone."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Too much motion. Hold phone steady."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Please re-enroll your face."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"No longer able to recognise face. Try again."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Open links with"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Set to always open"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 638d29d..dade85e 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎Move phone to the left.‎‏‎‎‏‎"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎Move phone to the right.‎‏‎‎‏‎"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎Please look more directly at your device.‎‏‎‎‏‎"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎‏‎Can’t see your face. Look at the phone.‎‏‎‎‏‎"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎Position your face directly in front of the phone.‎‏‎‎‏‎"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎Too much motion. Hold phone steady.‎‏‎‎‏‎"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎Please re-enroll your face.‎‏‎‎‏‎"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎No longer able to recognize face. Try again.‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 43e0823a..3a2ea3e 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -292,7 +292,7 @@
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar y ver mensajes SMS"</string>
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envíe y vea SMS?"</string>
-    <string name="permgrouplab_storage" msgid="1971118770546336966">"Espacio de almacenamiento"</string>
+    <string name="permgrouplab_storage" msgid="1971118770546336966">"Almacenamiento"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"acceder a las fotos, el contenido multimedia y los archivos"</string>
     <string name="permgrouprequest_storage" msgid="7885942926944299560">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a las fotos, el contenido multimedia y los archivos de tu dispositivo?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Micrófono"</string>
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Mueve el teléfono hacia la izquierda."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Mueve el teléfono hacia la derecha."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Mira directamente al dispositivo."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"No se ve tu cara. Mira el teléfono."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Ubica el rostro directamente frente al teléfono."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Te estás moviendo demasiado. No muevas el teléfono"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Vuelve a registrar tu cara."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ya no se reconoce la cara. Vuelve a intentarlo."</string>
@@ -602,7 +602,7 @@
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Permite que la aplicación consulte las estadísticas de sincronización de una cuenta, por ejemplo, el historial de eventos sincronizados y la cantidad de datos sincronizados."</string>
     <string name="permlab_sdcardRead" msgid="1438933556581438863">"ver almacenamiento compartido"</string>
     <string name="permdesc_sdcardRead" msgid="1804941689051236391">"Ver almacenamiento compartido"</string>
-    <string name="permlab_sdcardWrite" msgid="9220937740184960897">"Cambia/borra almac. compartido"</string>
+    <string name="permlab_sdcardWrite" msgid="9220937740184960897">"cambiar o borrar contenido de almacenamiento compartido"</string>
     <string name="permdesc_sdcardWrite" msgid="2834431057338203959">"Editar almacen. compartido"</string>
     <string name="permlab_use_sip" msgid="2052499390128979920">"realizar/recibir llamadas SIP"</string>
     <string name="permdesc_use_sip" msgid="2297804849860225257">"Permite que la aplicación realice y reciba llamadas SIP."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir vínculos con"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir vínculos con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Otorgar acceso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"¿Deseas iniciar el navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Establecer en \"abrir siempre\""</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 90bf8b6..633759b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Mueve el teléfono hacia la izquierda."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Mueve el teléfono hacia la derecha."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Mira de forma más directa al dispositivo."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"No se detecta tu cara. Mira al teléfono."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Coloca la cara directamente frente al teléfono."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"El teléfono se mueve demasiado. Mantenlo quieto."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Vuelve a registrar tu cara."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"No puede reconocer tu cara. Vuelve a intentarlo."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir enlaces con"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir enlaces con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permitir acceso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"¿Iniciar el navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Configurar para que se abra siempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ajustes"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index cf84482..86843c7 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Liigutage telefoni vasakule."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Liigutage telefoni paremale."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Vaadake otse oma seadmesse."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Teie nägu ei ole näha. Vaadake telefoni poole."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Hoidke oma nägu otse telefoni ees."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Liiga palju liikumist. Hoidke telefoni paigal."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registreerige oma nägu uuesti."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Nägu ei õnnestu enam tuvastada. Proovige uuesti."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Avamine:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avamine rakendusega %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ava"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Ava teenuse <xliff:g id="HOST">%1$s</xliff:g> lingid rakendusega"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Ava lingid rakendusega"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Linkide avamine rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Ava teenuse <xliff:g id="HOST">%1$s</xliff:g> lingid rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Juudep. andmine"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Muutmine:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muutmine rakendusega %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Kas käivitada brauser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Kas vastata kõnele?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alati"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Määra alati avama"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Ainult üks kord"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Seaded"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei toeta tööprofiili"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index ba1e0b2..d25fe8c 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -375,7 +375,7 @@
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Beren zati batzuk memoria modu iraunkorrean ezartzeko baimena ematen die aplikazioei. Horrela, beste aplikazioek erabilgarri duten memoria murritz daiteke eta tableta motel daiteke."</string>
     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Beren zati batzuk memorian modu iraunkorrean aktibo uztea baimentzen die aplikazioei. Horrela, beste aplikazioek memoria gutxiago izan lezakete erabilgarri eta telebistak motelago funtziona lezake."</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Beren zati batzuk memoria modu iraunkorrean ezartzeko baimena ematen die aplikazioei. Horrela, beste aplikazioek erabilgarri duten memoria murritz daiteke eta telefonoa motel daiteke."</string>
-    <string name="permlab_foregroundService" msgid="3310786367649133115">"Exekutatu zerbitzuak aurreko planoan"</string>
+    <string name="permlab_foregroundService" msgid="3310786367649133115">"Abiarazi zerbitzuak aurreko planoan"</string>
     <string name="permdesc_foregroundService" msgid="6471634326171344622">"Aurreko planoko zerbitzuak erabiltzea baimentzen dio aplikazioari."</string>
     <string name="permlab_getPackageSize" msgid="7472921768357981986">"neurtu aplikazioen biltegiratzeko tokia"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Bere kodea, datuak eta cache-tamainak eskuratzeko baimena ematen die aplikazioei."</string>
@@ -422,7 +422,7 @@
     <string name="permdesc_accessCoarseLocation" product="tv" msgid="3027871910200890806">"Aplikazioa aurreko planoan dagoenean, zure kokapenaren berri izan dezake sareen iturburuak erabilita; adibidez, telefonia mugikorreko dorreak eta Wi-Fi sareak. Kokapen-zerbitzu horiek aktibatuta eta erabilgarri izan behar dituzu telebistan, aplikazioak erabil ditzan."</string>
     <string name="permdesc_accessCoarseLocation" product="default" msgid="854896049371048754">"Aplikazioa aurreko planoan dagoenean, zure kokapenaren berri izan dezake sareen iturburuak erabilita; adibidez, telefonia mugikorreko dorreak eta Wi-Fi sareak. Kokapen-zerbitzu horiek aktibatuta eta erabilgarri izan behar dituzu telefonoan, aplikazioak erabil ditzan."</string>
     <string name="permlab_accessBackgroundLocation" msgid="3965397804300661062">"Atzitu kokapena atzeko planoan"</string>
-    <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"Baimen hau ematen bada kokapen zehatz edo gutxi gorabeherakorako sarbideaz gain, atzeko planoan exekutatu bitartean atzitu ahalko du aplikazioak kokapena."</string>
+    <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"Baimen hau ematen bada kokapen zehatz edo gutxi gorabeherakorako sarbideaz gain, atzeko planoan abian den bitartean atzitu ahalko du aplikazioak kokapena."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"aldatu audio-ezarpenak"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Audio-ezarpen orokorrak aldatzeko baimena ematen dio; besteak beste, bolumena eta irteerarako zer bozgorailu erabiltzen den."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"grabatu audioa"</string>
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Mugitu telefonoa ezkerretara."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Mugitu telefonoa eskuinetara."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Begiratu zuzenago gailuari."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ez da hautematen aurpegia. Begiratu telefonoari."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Ipini aurrez aurre aurpegia eta telefonoa."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Mugimendu gehiegi dago. Eutsi tinko telefonoari."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Erregistratu berriro aurpegia."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ez dugu ezagutzen aurpegi hori. Saiatu berriro."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ireki honekin:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin %1$s aplikazioarekin"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ireki"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Ireki <xliff:g id="HOST">%1$s</xliff:g> ostalariko estekak honekin:"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Ireki estekak honekin:"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Ireki estekak <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioarekin"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Ireki <xliff:g id="HOST">%1$s</xliff:g> ostalariko estekak <xliff:g id="APPLICATION">%2$s</xliff:g> aplikazioarekin"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Eman sarbidea"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editatu honekin:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu %1$s aplikazioarekin"</string>
@@ -1181,7 +1177,7 @@
     <string name="wait" msgid="7147118217226317732">"Itxaron"</string>
     <string name="webpage_unresponsive" msgid="3272758351138122503">"Orriak ez du erantzuten.\n\nItxi egin nahi duzu?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplikazioa birbideratu da"</string>
-    <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioa exekutatzen ari da."</string>
+    <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioa abian da."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioa lehenago abiarazi da."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Eskala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Erakutsi beti"</string>
@@ -1207,7 +1203,7 @@
     <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> prestatzen."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Aplikazioak abiarazten."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Bertsio-berritzea amaitzen."</string>
-    <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> exekutatzen"</string>
+    <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> abian da"</string>
     <string name="heavy_weight_notification_detail" msgid="2304833848484424985">"Sakatu jokora itzultzeko"</string>
     <string name="heavy_weight_switcher_title" msgid="387882830435195342">"Aukeratu joko bat"</string>
     <string name="heavy_weight_switcher_text" msgid="4176781660362912010">"Funtzionamendu hobea izateko, joko hauetako bat baino ezin da egon irekita aldi berean."</string>
@@ -1445,7 +1441,7 @@
     <string name="ime_action_next" msgid="3138843904009813834">"Hurrengoa"</string>
     <string name="ime_action_done" msgid="8971516117910934605">"Eginda"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"Atzera"</string>
-    <string name="ime_action_default" msgid="2840921885558045721">"Exekutatu"</string>
+    <string name="ime_action_default" msgid="2840921885558045721">"Abiarazi"</string>
     <string name="dial_number_using" msgid="5789176425167573586">"Markatu zenbakia \n<xliff:g id="NUMBER">%s</xliff:g> erabilita"</string>
     <string name="create_contact_using" msgid="4947405226788104538">"Sortu kontaktua\n<xliff:g id="NUMBER">%s</xliff:g> erabilita"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Aplikazio hauetako bat edo gehiago kontua orain eta etorkizunean atzitzeko baimena eskatzen ari dira."</string>
@@ -1555,7 +1551,7 @@
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD txartela"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB bidezko unitatea"</string>
     <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> enpresaren USB bidezko unitatea"</string>
-    <string name="storage_usb" msgid="3017954059538517278">"USB memoria"</string>
+    <string name="storage_usb" msgid="3017954059538517278">"USB bidezko memoria"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Editatu"</string>
     <string name="data_usage_warning_title" msgid="6499834033204801605">"Datuen erabileraren abisua"</string>
     <string name="data_usage_warning_body" msgid="7340198905103751676">"<xliff:g id="APP">%s</xliff:g> erabili dituzu"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Arakatzailea abiarazi nahi duzu?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Deia onartu nahi duzu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Beti"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Ezarri beti irekitzeko"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Behin soilik"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ezarpenak"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s abiarazleak ez du laneko profil hau onartzen"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 280a56ec..48cdafc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"تلفن را به‌سمت چپ حرکت دهید."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"تلفن را به سمت راست حرکت دهید."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"لطفاً مستقیم به دستگاه نگه کنید."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"چهره‌تان دیده نمی‌شود. به تلفن نگاه کنید."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"صورتتان را مستقیماً روبروی تلفن قرار دهید."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"حرکت خیلی زیاد است. تلفن را ثابت نگه‌دارید."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"لطفاً چهره‌تان را مجدداً ثبت کنید."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"دیگر چهره را تشخیص نمی‌دهد. دوباره امتحان کنید."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"باز کردن با"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏باز کردن با %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"باز کردن"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با"</string>
+    <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="HOST">%1$s</xliff:g> با <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ارائه دسترسی"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ویرایش با"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ویرایش با %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"مرورگر راه‌اندازی شود؟"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"تماس را می‌پذیرید؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"همیشه"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"تنظیم روی همیشه باز شدن"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"فقط این بار"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"تنظیمات"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s از نمایه کاری پشتیبانی نمی‌کند"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 7a5003b..cd9a711 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Siirrä puhelinta vasemmalle."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Siirrä puhelinta oikealle."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Katso suoremmin laitteeseen."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Kasvojasi ei näy. Katso puhelinta."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Aseta kasvosi suoraan puhelimen eteen."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Laite liikkui liikaa. Pidä puhelin vakaana."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Rekisteröi kasvot uudelleen."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ei enää tunnista kasvoja. Yritä uudelleen."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Avaa sovelluksessa"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avaa sovelluksessa %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Avaa"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g>-linkit avataan:"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Linkit avataan:"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> avaa linkit"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> avaa linkit (<xliff:g id="HOST">%1$s</xliff:g>)"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Salli"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Muokkaa sovelluksessa"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muokkaa sovelluksessa %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Käynnistetäänkö selain?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vastataanko puheluun?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Aina"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Avaa aina"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Vain kerran"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Asetukset"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei tue työprofiilia"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 0ddb19a..2bfef39 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Déplacez le téléphone vers la gauche."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Déplacez le téléphone vers la droite."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Veuillez regarder plus directement votre appareil."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Visage non détecté. Regardez le téléphone."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Placez votre visage directement devant le téléphone."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Trop de mouvement. Tenez le téléphone immobile."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Veuillez inscrire votre visage à nouveau."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ce visage ne sera plus reconnu. Réessayez."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Ouvrir les liens avec"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Ouvrir les liens avec <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Lancer le navigateur?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Définir cette activité comme toujours ouverte"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne prend pas en charge le profil professionnel"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 5f98a8a..041668f 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Déplacez le téléphone vers la gauche."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Déplacez le téléphone vers la droite."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Veuillez regarder plus directement l\'appareil."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Visage non détecté. Regardez le téléphone."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Placez votre visage en face du téléphone."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Trop de mouvement. Ne bougez pas le téléphone."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Veuillez enregistrer à nouveau votre visage."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Impossible de reconnaître le visage. Réessayez."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Ouvrir les liens avec"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Ouvrir les liens avec <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Lancer le navigateur ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Définir cette activité comme toujours ouverte"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s n\'est pas compatible avec le profil professionnel."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 740f699..b3eed4a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Move o teléfono cara á esquerda."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Move o teléfono cara á dereita."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Mira o dispositivo de forma máis directa."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Non se ve a túa cara. Mira para o teléfono"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Coloca a cara directamente diante do teléfono."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Demasiado movemento. Non movas o teléfono."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Volve rexistrar a túa cara."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Xa non se pode recoñecer a cara. Téntao de novo."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir ligazóns con"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir ligazóns con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acceso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Iniciar o navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceptar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Definir como abrir sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só unha vez"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non admite o perfil de traballo"</string>
@@ -1990,7 +1985,7 @@
     <string name="harmful_app_warning_uninstall" msgid="4837672735619532931">"DESINSTALAR"</string>
     <string name="harmful_app_warning_open_anyway" msgid="596432803680914321">"ABRIR IGUALMENTE"</string>
     <string name="harmful_app_warning_title" msgid="8982527462829423432">"Detectouse unha aplicación daniña"</string>
-    <string name="slices_permission_request" msgid="8484943441501672932">"A aplicación <xliff:g id="APP_0">%1$s</xliff:g> quere mostrar partes de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+    <string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> quere mostrar fragmentos de aplicación de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7867478911006447565">"Editar"</string>
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"As chamadas e as notificacións vibrarán"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"As chamadas e as notificacións estarán silenciadas"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index ddc4aae..1b96172 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ફોનને ડાબી બાજુ ખસેડો."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ફોનને જમણી બાજુ ખસેડો."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"કૃપા કરીને તમારા ડિવાઇસ તરફ સીધું જુઓ."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"તમારો ચહેરો દેખાતો નથી. ફોનની સામે જુઓ."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"તમારો ચહેરો તમારા ફોનની બિલકુલ સામે રાખો."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ડિવાઇસ અસ્થિર છે. ફોનને સ્થિર રાખો."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"કૃપા કરીને તમારા ચહેરાની ફરી નોંધણી કરાવો."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"ચહેરો ઓળખી શકાતો નથી. ફરી પ્રયાસ કરો."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"આની સાથે ખોલો"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s સાથે ખોલો"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ખોલો"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"આના વડે <xliff:g id="HOST">%1$s</xliff:g> લિંક ખોલો"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"આનાથી સંપાદિત કરો"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s સાથે સંપાદિત કરો"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"બ્રાઉઝર લોન્ચ કરીએ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"કૉલ સ્વીકારીએ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"હંમેશા"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"હંમેશાં ખુલ્લી તરીકે સેટ કરો"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ફક્ત એક વાર"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"સેટિંગ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s કાર્ય પ્રોફાઇલનું સમર્થન કરતું નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0a1051b..9f0df13 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"फ़ोन को बाईं ओर घुमाएं."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"फ़ोन को दाईं ओर घुमाएं."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"कृपया अपने डिवाइस की तरफ़ सीधे देखें."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"आपका चेहरा नहीं दिखाई दे रहा. फ़ोन की तरफ़ देखें."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"अपने चेहरे को फोन के ठीक सामने लाएं."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"डिवाइस बहुत ज़्यादा हिल रहा है. फ़ोन को बिना हिलाएं पकड़ें."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"कृपया फिर से अपने चेहरे की पहचान कराएं."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"अब चेहरे की पहचान नहीं कर पा रहा. फिर से कोशिश करें."</string>
@@ -784,7 +784,7 @@
     <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"हमसफ़र"</string>
     <string name="relationTypeFather" msgid="5228034687082050725">"पिता"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"दोस्त"</string>
-    <string name="relationTypeManager" msgid="6365677861610137895">"प्रबंधक"</string>
+    <string name="relationTypeManager" msgid="6365677861610137895">"मैनेजर"</string>
     <string name="relationTypeMother" msgid="4578571352962758304">"मां"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"अभिभावक"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"सहयोगी"</string>
@@ -904,7 +904,7 @@
     <string name="granularity_label_line" msgid="5764267235026120888">"पंक्ति"</string>
     <string name="factorytest_failed" msgid="5410270329114212041">"फ़ैक्‍ट्री परीक्षण विफल"</string>
     <string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TEST का काम केवल /system/app में इंस्‍टॉल किए गए पैकेज के लिए ही हो सकता है."</string>
-    <string name="factorytest_no_action" msgid="872991874799998561">"ऐसा कोई पैकेज नहीं मिला था जो FACTORY_TEST कार्रवाई प्रदान करता हो."</string>
+    <string name="factorytest_no_action" msgid="872991874799998561">"ऐसा कोई पैकेज नहीं मिला था जो FACTORY_TEST कार्रवाई मुहैया करवाता हो."</string>
     <string name="factorytest_reboot" msgid="6320168203050791643">"रीबूट करें"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' पर यह पेज दर्शाता है:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
@@ -1085,7 +1085,7 @@
     <string name="undo" msgid="7905788502491742328">"वापस लाएं"</string>
     <string name="redo" msgid="7759464876566803888">"फिर से करें"</string>
     <string name="autofill" msgid="3035779615680565188">"ऑटोमैटिक भरना"</string>
-    <string name="textSelectionCABTitle" msgid="5236850394370820357">"लेख चयन"</string>
+    <string name="textSelectionCABTitle" msgid="5236850394370820357">"टेक्स्ट चुनें"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"शब्दकोश में जोड़ें"</string>
     <string name="deleteText" msgid="6979668428458199034">"मिटाएं"</string>
     <string name="inputMethod" msgid="1653630062304567879">"इनपुट विधि"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"इसमें खोलें"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s में खोलें"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोलें"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"इसे इस्तेमाल करके <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलें"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"इसके ज़रिये बदलाव करें"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s की मदद से बदलाव करें"</string>
@@ -1288,7 +1284,7 @@
     <item msgid="75483255295529161">"वाई-फ़ाई"</item>
     <item msgid="6862614801537202646">"ब्लूटूथ"</item>
     <item msgid="5447331121797802871">"ईथरनेट"</item>
-    <item msgid="8257233890381651999">"VPN"</item>
+    <item msgid="8257233890381651999">"वीपीएन"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाई-फ़ाई  से कनेक्‍ट नहीं हो सका"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउज़र लॉन्च करें?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकार करें?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"हमेशा"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"\'हमेशा खुला रखें\' पर सेट करें"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"केवल एक बार"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s वर्क प्रोफ़ाइल का समर्थन नहीं करता"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index cc8eb49..21fdc2f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -571,7 +571,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Pomaknite telefon ulijevo."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Pomaknite telefon udesno."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Gledajte izravnije prema uređaju."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Vaše se lice ne vidi. Pogledajte telefon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Postavite lice izravno ispred telefona."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Previše kretanja. Držite telefon mirno."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Ponovo registrirajte svoje lice."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Lice nije prepoznato. Pokušajte ponovo."</string>
@@ -1151,14 +1151,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvaranje pomoću aplikacije"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvaranje pomoću aplikacije %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otvaranje veza s <xliff:g id="HOST">%1$s</xliff:g> u aplikaciji"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otvaranje veza u aplikaciji"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otvaranje veza u aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otvaranje veza s <xliff:g id="HOST">%1$s</xliff:g> u aplikaciji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogući pristup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Uređivanje pomoću aplikacije"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uređivanje pomoću aplikacije %1$s"</string>
@@ -1613,8 +1609,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Pokrenuti preglednik?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Postavi to otvaranje kao zadano"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava radni profil"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 4ce7d42..1198610 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Mozgassa a telefont balra."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Mozgassa a telefont jobbra."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Szemből nézzen az eszközre."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nem látszik az arca. Nézzen a telefonra."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"A telefont közvetlenül az arca elé tegye."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Túl sok a mozgás. Tartsa stabilan a telefont."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Rögzítsen újra képet az arcáról."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Már nem lehet felismerni az arcát. Próbálja újra."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Megnyitás a következővel:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Megnyitás a következővel: %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Megnyitás"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g>-linkek megnyitása a következővel:"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Linkek megnyitása a következővel:"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Linkek megnyitása a következővel: <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g>-linkek megnyitása a következővel: <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Engedély adása"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Szerkesztés a következővel:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Szerkesztés a következővel: %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Böngésző indítása?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Fogadja a hívást?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Mindig"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Megnyitás mindig ezzel"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Csak egyszer"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Beállítások"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"A(z) %1$s nem támogatja a munkaprofilokat."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 2be6d6f..7165df9 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -104,7 +104,7 @@
     <string name="serviceClassFAX" msgid="5566624998840486475">"Ֆաքս"</string>
     <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
     <string name="serviceClassDataAsync" msgid="4523454783498551468">"Չհամաժամեցված"</string>
-    <string name="serviceClassDataSync" msgid="7530000519646054776">"Համաժամել"</string>
+    <string name="serviceClassDataSync" msgid="7530000519646054776">"Համաժամացնել"</string>
     <string name="serviceClassPacket" msgid="6991006557993423453">"Փաթեթ"</string>
     <string name="serviceClassPAD" msgid="3235259085648271037">"Հարթակ"</string>
     <string name="roamingText0" msgid="7170335472198694945">"Ռոումինգի ցուցիչը միացված է"</string>
@@ -169,8 +169,8 @@
     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Չհաջողվեց գտնել հարցվող ֆայլը:"</string>
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Չափից շատ հարցումներ են մշակվում: Փորձեք կրկին ավելի ուշ:"</string>
     <string name="notification_title" msgid="8967710025036163822">"Մուտք գործելու սխալ` <xliff:g id="ACCOUNT">%1$s</xliff:g>-ի համար"</string>
-    <string name="contentServiceSync" msgid="8353523060269335667">"Համաժամեցնել"</string>
-    <string name="contentServiceSyncNotificationTitle" msgid="7036196943673524858">"Չի հաջողվում համաժամեցնել"</string>
+    <string name="contentServiceSync" msgid="8353523060269335667">"Համաժամացնել"</string>
+    <string name="contentServiceSyncNotificationTitle" msgid="7036196943673524858">"Չի հաջողվում համաժամացնել"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="4884451152168188763">"Հետևյալ ծառայությունից չափազանց շատ տարրեր եք ջնջել՝ <xliff:g id="CONTENT_TYPE">%s</xliff:g>:"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Պլանշետի պահոցը լիքն է: Ջնջեք մի քանի ֆայլ` տարածք ազատելու համար:"</string>
     <string name="low_memory" product="watch" msgid="4415914910770005166">"Ժամացույցի ֆայլերի պահեստը լիքն է: Ջնջեք որոշ ֆայլեր՝ տարածք ազատելու համար:"</string>
@@ -346,7 +346,7 @@
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"կարդալ բջջային զեկուցվող հաղորդագրությունները"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Թույլ է տալիս հավելվածին կարդալ ձեր սարքի կողմից ստացված բջջային հեռարձակվող հաղորդագրությունները: Բջջային հեռարձակվող զգուշացումները ուղարկվում են որոշ վայրերում` արտակարգ իրավիճակների մասին ձեզ զգուշացնելու համար: Վնասարար հավելվածները կարող են խանգարել ձեր սարքի արդյունավետությանը կամ շահագործմանը, երբ ստացվում է արտակարգ իրավիճակի մասին բջջային հաղորդում:"</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"կարդալ բաժանորդագրված հոսքերը"</string>
-    <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Թույլ է տալիս հավելվածին մանրամասներ ստանալ ընթացիկ համաժամեցված հոսքերի մասին:"</string>
+    <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Թույլ է տալիս հավելվածին մանրամասներ ստանալ ընթացիկ համաժամացված հոսքերի մասին:"</string>
     <string name="permlab_sendSms" msgid="7544599214260982981">"SMS հաղորդագրությունների ուղարկում և ընթերցում"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Թույլ է տալիս հավելվածին ուղարկել SMS հաղորդագրություններ: Այն կարող է անսպասելի ծախսերի պատճառ դառնալ: Վնասարար հավելվածները կարող են ձեր հաշվից գումար ծախսել` ուղարկելով հաղորդագրություններ`  առանց ձեր հաստատման:"</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"կարդալ ձեր տեքստային հաղորդագրությունները (SMS կամ MMS)"</string>
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Տեղափոխեք հեռախոսը ձախ:"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Տեղափոխեք հեռախոսը աջ:"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Նայեք ուղիղ էկրանին։"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ձեր դեմքը չի երևում։ Նայեք հեռախոսին։"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Պահեք ձեր դեմքն անմիջապես հեռախոսի էկրանի դիմաց:"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Շատ եք շարժում։ Հեռախոսն անշարժ պահեք։"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Նորից փորձեք։"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Չհաջողվեց ճանաչել դեմքը։ Նորից փորձեք:"</string>
@@ -594,12 +594,12 @@
   <string-array name="face_error_vendor">
   </string-array>
     <string name="face_icon_content_description" msgid="4024817159806482191">"Դեմքի պատկերակ"</string>
-    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"կարդալ համաժամեցման կարգավորումները"</string>
-    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Թույլ է տալիս հավելվածին կարդալ համաժամեցման կարգավորումները հաշվի համար: Օրինակ` այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամեցված է հաշվի հետ:"</string>
-    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"համաժամեցումը փոխարկել միացվածի և անջատվածի"</string>
-    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Թույլ է տալիս հավելվածին փոփոխել համաժամեցման կարգավորումները հաշվի համար: Օրինակ, այն կարող է օգտագործվել` միացնելու Մարդիկ հավելվածի համաժամեցումը հաշվի հետ:"</string>
-    <string name="permlab_readSyncStats" msgid="7396577451360202448">"կարդալ համաժամեցման վիճակագրությունը"</string>
-    <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Թույլ է տալիս հավելվածին կարդալ հաշվի համաժամեցման վիճակագրությունը, այդ թվում` համաժամեցման իրադարձությունների պատմությունը և թե որքան տվյալ է համաժամեցված:"</string>
+    <string name="permlab_readSyncSettings" msgid="6201810008230503052">"կարդալ համաժամացման կարգավորումները"</string>
+    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Թույլ է տալիս հավելվածին կարդալ համաժամացման կարգավորումները հաշվի համար: Օրինակ` այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամացված է հաշվի հետ:"</string>
+    <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"համաժամացումը փոխարկել միացվածի և անջատվածի"</string>
+    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Թույլ է տալիս հավելվածին փոփոխել համաժամացման կարգավորումները հաշվի համար: Օրինակ, այն կարող է օգտագործվել` միացնելու Մարդիկ հավելվածի համաժամացումը հաշվի հետ:"</string>
+    <string name="permlab_readSyncStats" msgid="7396577451360202448">"կարդալ համաժամացման վիճակագրությունը"</string>
+    <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Թույլ է տալիս հավելվածին կարդալ հաշվի համաժամացման վիճակագրությունը, այդ թվում` համաժամացման իրադարձությունների պատմությունը և թե որքան տվյալ է համաժամացված:"</string>
     <string name="permlab_sdcardRead" msgid="1438933556581438863">"կարդալ ձեր ընդհանուր հիշողության պարունակությունը"</string>
     <string name="permdesc_sdcardRead" msgid="1804941689051236391">"Հավելվածին թույլ է տալիս կարդալ ձեր ընդհանուր հիշողության պարունակությունը:"</string>
     <string name="permlab_sdcardWrite" msgid="9220937740184960897">"փոփոխել կամ ջնջել ձեր ընդհանուր հիշողության բովանդակությունը"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Բացել հետևյալ ծրագրով՝"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Բացել հավելվածով՝ %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Բացել"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> տեսակի հղումները բացել…"</string>
+    <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="HOST">%1$s</xliff:g> տեսակի հղումները բացել <xliff:g id="APPLICATION">%2$s</xliff:g> դիտարկիչում"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Թույլատրել"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Խմբագրել հետևյալ ծրագրով՝"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Խմբագրել հետևյալով՝ %1$s"</string>
@@ -1156,7 +1152,7 @@
     <string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"Լուսանկարել %1$s հավելվածի օգնությամբ"</string>
     <string name="whichImageCaptureApplicationLabel" msgid="6390303445371527066">"Լուսանկարել"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Օգտագործել ըստ կանխադրման այս գործողության համար:"</string>
-    <string name="use_a_different_app" msgid="8134926230585710243">"Օգտագործել այլ հավելված"</string>
+    <string name="use_a_different_app" msgid="8134926230585710243">"Ուրիշ հավելված"</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Մաքրել լռելյայնը Համակարգի կարգավորումներ &gt; Ծրագրեր &gt;Ներբեռնված էջից:"</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Ընտրել գործողություն"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"Ընտրեք հավելված USB սարքի համար"</string>
@@ -1457,7 +1453,7 @@
     <string name="forward_intent_to_owner" msgid="1207197447013960896">"Դուք օգտագործում եք այս հավելվածը ձեր աշխատանքային պրոֆիլից դուրս"</string>
     <string name="forward_intent_to_work" msgid="621480743856004612">"Դուք օգտագործում եք այս հավելվածը ձեր աշխատանքային պրոֆիլում"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Ներածման եղանակը"</string>
-    <string name="sync_binding_label" msgid="3687969138375092423">"Համաժամել"</string>
+    <string name="sync_binding_label" msgid="3687969138375092423">"Համաժամացնել"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Մատչելիությունը"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Պաստառ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Փոխել պաստառը"</string>
@@ -1590,9 +1586,8 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Գործարկե՞լ զննարկիչը:"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ընդունե՞լ զանգը:"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Միշտ"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
-    <string name="activity_resolver_use_once" msgid="2404644797149173758">"Միայն մեկ անգամ"</string>
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Միշտ բացել"</string>
+    <string name="activity_resolver_use_once" msgid="2404644797149173758">"Միայն այս անգամ"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Կարգավորումներ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s-ը չի աջակցում աշխատանքային պրոֆիլներ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Գրասալիկ"</string>
@@ -1619,7 +1614,7 @@
     <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ներկառուցված էկրան"</string>
     <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI էկրան"</string>
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Վերածածկ #<xliff:g id="ID">%1$d</xliff:g>"</string>
-    <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>. <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> կմվ"</string>
+    <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>. <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> կմչ"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", անվտանգ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Մոռացել եմ սխեման"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Սխալ սխեմա"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e71ab41..ca369eb 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Gerakkan ponsel ke kiri."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Gerakkan ponsel ke kanan."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Lihat langsung ke perangkat."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Tidak dapat melihat wajah Anda. Lihat ke ponsel."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posisikan wajah Anda langsung di depan ponsel."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Terlalu banyak gerakan. Stabilkan ponsel."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Daftarkan ulang wajah Anda."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Tidak lagi dapat mengenali wajah. Coba lagi."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Buka link <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Buka link dengan"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Buka link dengan <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Buka link <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
@@ -1383,7 +1379,7 @@
     <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"Tampilkan di atas apl lain"</string>
     <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> ditampilkan di atas aplikasi lain"</string>
     <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> ditampilkan di atas aplikasi lain"</string>
-    <string name="alert_windows_notification_message" msgid="8917232109522912560">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, tap untuk membuka setelan dan menonaktifkannya."</string>
+    <string name="alert_windows_notification_message" msgid="8917232109522912560">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, ketuk untuk membuka setelan dan menonaktifkannya."</string>
     <string name="alert_windows_notification_turn_off_action" msgid="2902891971380544651">"Nonaktifkan"</string>
     <string name="ext_media_checking_notification_title" msgid="4411133692439308924">"Memeriksa <xliff:g id="NAME">%s</xliff:g>…"</string>
     <string name="ext_media_checking_notification_message" msgid="410185170877285434">"Meninjau konten saat ini"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Luncurkan Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Selalu"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Setel untuk selalu membuka"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setelan"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak mendukung profil kerja"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 3d2acd9..572313a 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Færðu símann til vinstri."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Færðu símann til hægri."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Horfðu beint á tækið."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Sé ekki andlit þitt. Horfðu á símann."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Hafðu andlitið beint fyrir framan símann."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Of mikil hreyfing. Haltu símanum stöðugum."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Skráðu nafnið þitt aftur."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Andlit þekkist ekki lengur. Reyndu aftur."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Opna með"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Opna með %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Opna"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Opna <xliff:g id="HOST">%1$s</xliff:g> tengla með"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Opna tengla með"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Opna tengla með <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Opna <xliff:g id="HOST">%1$s</xliff:g> tengla með <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Veita aðgang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Breyta með"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Breyta með %1$s"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Opna vafra?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Samþykkja símtal?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltaf"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Stilla á „Alltaf opið“"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara einu sinni"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Stillingar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s styður ekki vinnusnið"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 6d1d132..6c579b8 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -325,7 +325,7 @@
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Consente di toccare, far scorrere, pizzicare ed eseguire altri gesti."</string>
     <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesti con sensore di impronte digitali"</string>
     <string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"È in grado di rilevare i gesti compiuti con il sensore di impronte digitali dei dispositivi."</string>
-    <string name="permlab_statusBar" msgid="7417192629601890791">"disattivare o modificare la barra di stato"</string>
+    <string name="permlab_statusBar" msgid="7417192629601890791">"disattivazione o modifica della barra di stato"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ruolo di barra di stato"</string>
     <string name="permdesc_statusBarService" msgid="716113660795976060">"Consente di visualizzare l\'applicazione nella barra di stato."</string>
@@ -337,7 +337,7 @@
     <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Consente all\'applicazione di rimuovere le scorciatoie della schermata Home automaticamente."</string>
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"reindirizzamento chiamate in uscita"</string>
     <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Consente all\'app di rilevare il numero digitato durante una chiamata in uscita, con la possibilità di reindirizzare la telefonata a un numero diverso o interromperla del tutto."</string>
-    <string name="permlab_answerPhoneCalls" msgid="4077162841226223337">"rispondi a telefonate in arrivo"</string>
+    <string name="permlab_answerPhoneCalls" msgid="4077162841226223337">"risposta a telefonate in arrivo"</string>
     <string name="permdesc_answerPhoneCalls" msgid="2901889867993572266">"Consente all\'app di rispondere a una telefonata in arrivo."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"ricezione messaggi di testo (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"Consente all\'applicazione di ricevere ed elaborare messaggi SMS. Significa che l\'applicazione potrebbe monitorare o eliminare i messaggi inviati al tuo dispositivo senza mostrarteli."</string>
@@ -347,7 +347,7 @@
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Consente all\'applicazione di leggere i messaggi cell broadcast ricevuti dal dispositivo. Gli avvisi cell broadcast vengono trasmessi in alcune località per avvertire di eventuali situazioni di emergenza. Le applicazioni dannose potrebbero interferire con il rendimento o con il funzionamento del dispositivo quando si riceve un messaggio cell broadcast di emergenza."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lettura feed sottoscritti"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Consente all\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
-    <string name="permlab_sendSms" msgid="7544599214260982981">"inviare e visualizzare SMS"</string>
+    <string name="permlab_sendSms" msgid="7544599214260982981">"invio e visualizzazione di SMS"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Consente all\'applicazione di inviare messaggi SMS. Ciò potrebbe comportare costi imprevisti. Applicazioni dannose potrebbero generare dei costi inviando messaggi senza la tua conferma."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"lettura messaggi di testo personali (SMS o MMS)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"Questa app può leggere tutti i messaggi di testo (SMS) memorizzati sul tablet."</string>
@@ -375,7 +375,7 @@
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Consente all\'applicazione di rendere persistenti in memoria alcune sue parti. Ciò può limitare la memoria disponibile per altre applicazioni, rallentando il tablet."</string>
     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Consente all\'app di rendere alcune sue parti persistenti nella memoria. Potrebbe così essere limitata la memoria a disposizione di altre app ed essere rallentata la TV."</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Consente all\'applicazione di rendere persistenti in memoria alcune sue parti. Ciò può limitare la memoria disponibile per altre applicazioni, rallentando il telefono."</string>
-    <string name="permlab_foregroundService" msgid="3310786367649133115">"esegui servizio in primo piano"</string>
+    <string name="permlab_foregroundService" msgid="3310786367649133115">"esecuzione servizio in primo piano"</string>
     <string name="permdesc_foregroundService" msgid="6471634326171344622">"Consente all\'app di utilizzare i servizi in primo piano."</string>
     <string name="permlab_getPackageSize" msgid="7472921768357981986">"calcolo spazio di archiviazione applicazioni"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Consente all\'applicazione di recuperare il suo codice, i suoi dati e le dimensioni della cache"</string>
@@ -405,7 +405,7 @@
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Consente all\'applicazione di modificare il registro chiamate del telefono, inclusi i dati sulle chiamate in arrivo e in uscita. Le applicazioni dannose potrebbero farne uso per cancellare o modificare il registro chiamate."</string>
     <string name="permlab_bodySensors" msgid="4683341291818520277">"accesso ai sensori (come il cardiofrequenzimetro)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Consente all\'app di accedere ai dati relativi ai sensori che monitorano le tue condizioni fisiche, ad esempio la frequenza cardiaca."</string>
-    <string name="permlab_readCalendar" msgid="6716116972752441641">"Leggi eventi di calendario e dettagli"</string>
+    <string name="permlab_readCalendar" msgid="6716116972752441641">"lettura di eventi di calendario e dettagli"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"Questa app può leggere tutti gli eventi di calendario memorizzati sul tablet e condividere o salvare i dati di calendario."</string>
     <string name="permdesc_readCalendar" product="tv" msgid="8837931557573064315">"Questa app può leggere tutti gli eventi di calendario memorizzati sulla TV e condividere o salvare i dati di calendario."</string>
     <string name="permdesc_readCalendar" product="default" msgid="4373978642145196715">"Questa app può leggere tutti gli eventi di calendario memorizzati sul telefono e condividere o salvare i dati di calendario."</string>
@@ -415,9 +415,9 @@
     <string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Questa app può aggiungere, rimuovere o modificare eventi di calendario sul telefono. Può inviare messaggi che possono sembrare inviati dai proprietari del calendario o modificare eventi senza notificare i proprietari."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi provider di geolocalizz."</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Consente all\'app di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'app di interferire con il funzionamento del GPS o di altre fonti di geolocalizzazione."</string>
-    <string name="permlab_accessFineLocation" msgid="6265109654698562427">"Accesso alla posizione esatta solo in primo piano"</string>
+    <string name="permlab_accessFineLocation" msgid="6265109654698562427">"accesso alla posizione esatta solo in primo piano"</string>
     <string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Questa app può recuperare la tua posizione esatta solo quando è in primo piano. Questi servizi di geolocalizzazione devono essere attivi e disponibili sul telefono affinché l\'app possa usarli. Potrebbe aumentare il consumo della batteria."</string>
-    <string name="permlab_accessCoarseLocation" msgid="3707180371693213469">"Accesso alla posizione approssimativa (in base alla rete) solo in primo piano"</string>
+    <string name="permlab_accessCoarseLocation" msgid="3707180371693213469">"accesso alla posizione approssimativa (in base alla rete) solo in primo piano"</string>
     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="8594719010575779120">"Questa app può recuperare la tua posizione tramite fonti di rete quali ripetitori di telefonia mobile e reti Wi-Fi, ma soltanto quando l\'app è in primo piano. Questi servizi di geolocalizzazione devono essere attivi e disponibili sul tablet affinché l\'app possa usarli."</string>
     <string name="permdesc_accessCoarseLocation" product="tv" msgid="3027871910200890806">"Questa app può recuperare la tua posizione tramite fonti di rete quali ripetitori di telefonia mobile e reti Wi-Fi, ma soltanto quando l\'app è in primo piano. Questi servizi di geolocalizzazione devono essere attivi e disponibili sulla TV affinché l\'app possa usarli."</string>
     <string name="permdesc_accessCoarseLocation" product="default" msgid="854896049371048754">"Questa app può recuperare la tua posizione tramite fonti di rete quali ripetitori di telefonia mobile e reti Wi-Fi, ma soltanto quando l\'app è in primo piano. Questi servizi di geolocalizzazione devono essere attivi e disponibili sul telefono affinché l\'app possa usarli."</string>
@@ -425,7 +425,7 @@
     <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"Se concedi l\'autorizzazione insieme all\'accesso alla posizione precisa o approssimativa, l\'app potrà accedere alla posizione mentre viene eseguita in background."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifica impostazioni audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Consente all\'applicazione di modificare le impostazioni audio globali, come il volume e quale altoparlante viene utilizzato per l\'uscita."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"registrare audio"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"registrazione audio"</string>
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"Questa app può registrare audio tramite il microfono in qualsiasi momento."</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"invio di comandi alla SIM"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Consente all\'app di inviare comandi alla SIM. Questo è molto pericoloso."</string>
@@ -437,7 +437,7 @@
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Consente all\'applicazione di controllare la vibrazione."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Consente all\'applicazione di chiamare numeri di telefono senza il tuo intervento. Ciò può comportare chiamate o addebiti imprevisti. Tieni presente che ciò non consente all\'applicazione di chiamare numeri di emergenza. Applicazioni dannose potrebbero generare dei costi effettuando chiamate senza la tua conferma."</string>
-    <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Accesso al servizio di chiamata IMS"</string>
+    <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesso al servizio di chiamata IMS"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Consente all\'app di utilizzare il servizio IMS per fare chiamate senza il tuo intervento."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"lettura stato e identità telefono"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Consente all\'applicazione di accedere alle funzioni telefoniche del dispositivo. Questa autorizzazione consente all\'applicazione di determinare il numero di telefono e gli ID dei dispositivi, se una chiamata è attiva e il numero remoto connesso da una chiamata."</string>
@@ -445,12 +445,12 @@
     <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Consente all\'app di indirizzare le proprie chiamate tramite il sistema al fine di migliorare l\'esperienza di chiamata."</string>
     <string name="permlab_callCompanionApp" msgid="3599252979411970473">"visualizzazione e controllo delle chiamate tramite il sistema."</string>
     <string name="permdesc_callCompanionApp" msgid="4567344683275099090">"Consente all\'app di visualizzare e controllare le chiamate in corso sul dispositivo. Sono incluse informazioni quali i numeri e lo stato relativi alle chiamate."</string>
-    <string name="permlab_acceptHandover" msgid="2661534649736022409">"Continuazione di una chiamata da un\'altra app"</string>
+    <string name="permlab_acceptHandover" msgid="2661534649736022409">"continuazione di una chiamata da un\'altra app"</string>
     <string name="permdesc_acceptHandovers" msgid="4570660484220539698">"Consente all\'app di continuare una chiamata che è stata iniziata in un\'altra app."</string>
     <string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"lettura dei numeri di telefono"</string>
     <string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"Consente all\'app di accedere ai numeri di telefono del dispositivo."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"disattivazione stand-by del tablet"</string>
-    <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"divieto di attivazione della modalità di sospensione della TV"</string>
+    <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"disattivazione della modalità di sospensione della TV"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Consente all\'applicazione di impedire lo stand-by del tablet."</string>
     <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"Consente all\'app di impedire l\'attivazione della modalità di sospensione della TV."</string>
@@ -483,7 +483,7 @@
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Consente all\'applicazione di visualizzare informazioni sulle reti Wi-Fi, ad esempio di rilevare se il Wi-Fi è abilitato e il nome dei dispositivi Wi-Fi connessi."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"connessione e disconnessione dal Wi-Fi"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Consente all\'applicazione di connettersi/disconnettersi da punti di accesso Wi-Fi e di apportare modifiche alla configurazione del dispositivo per le reti Wi-Fi."</string>
-    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"consenti ricezione multicast Wi-Fi"</string>
+    <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"ricezione multicast Wi-Fi"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Consente all\'applicazione di ricevere pacchetti inviati a tutti i dispositivi su una rete Wi-Fi utilizzando indirizzi multicast, non solo il tuo tablet. Viene consumata più batteria rispetto alla modalità non multicast."</string>
     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Consente all\'app di ricevere pacchetti inviati a tutti i dispositivi tramite una rete Wi-Fi utilizzando indirizzi multicast, non soltanto la TV. Questa modalità consuma più energia della modalità non multicast."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Consente all\'applicazione di ricevere pacchetti inviati a tutti i dispositivi su una rete Wi-Fi utilizzando indirizzi multicast, non solo il tuo telefono. Viene consumata più batteria rispetto alla modalità non multicast."</string>
@@ -505,21 +505,21 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Consente all\'applicazione di comunicare con tag, schede e lettori NFC (Near Field Communication)."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"disattivazione blocco schermo"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Consente all\'applicazione di disattivare il blocco tastiera ed eventuali protezioni tramite password associate. Ad esempio, il telefono disattiva il blocco tastiera quando riceve una telefonata in arrivo e lo riattiva al termine della chiamata."</string>
-    <string name="permlab_requestPasswordComplexity" msgid="202650535669249674">"richiedi complessità del blocco schermo"</string>
+    <string name="permlab_requestPasswordComplexity" msgid="202650535669249674">"richiesta di complessità del blocco schermo"</string>
     <string name="permdesc_requestPasswordComplexity" msgid="4730994229754212347">"Consente all\'app di conoscere il livello di complessità del blocco schermo (alto, medio, basso o nessuno), che indica l\'intervallo di caratteri possibile e il tipo di blocco schermo. L\'app può inoltre suggerire agli utenti di aggiornare il blocco schermo a un livello specifico di complessità, ma gli utenti possono ignorare liberamente il suggerimento e uscire. Tieni presente che il blocco schermo non viene memorizzato come testo non crittografato, quindi l\'app non conosce la password esatta."</string>
-    <string name="permlab_useBiometric" msgid="8837753668509919318">"Utilizzo di hardware biometrico"</string>
+    <string name="permlab_useBiometric" msgid="8837753668509919318">"utilizzo di hardware biometrico"</string>
     <string name="permdesc_useBiometric" msgid="8389855232721612926">"Consente all\'app di utilizzare hardware biometrico per eseguire l\'autenticazione"</string>
-    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestisci hardware per il riconoscimento delle impronte digitali"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestione di hardware per il riconoscimento delle impronte digitali"</string>
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Consente all\'app di richiamare metodi per aggiungere e rimuovere modelli di impronte digitali da utilizzare."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizzo di hardware per il riconoscimento delle impronte digitali"</string>
     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Consente all\'app di utilizzare l\'hardware per il riconoscimento delle impronte digitali per eseguire l\'autenticazione"</string>
-    <string name="permlab_audioWrite" msgid="2661772059799779292">"Modifica della tua raccolta musicale"</string>
+    <string name="permlab_audioWrite" msgid="2661772059799779292">"modifica della tua raccolta musicale"</string>
     <string name="permdesc_audioWrite" msgid="8888544708166230494">"Consente all\'app di modificare la tua raccolta musicale."</string>
-    <string name="permlab_videoWrite" msgid="128769316366746446">"Modifica della tua raccolta di video"</string>
+    <string name="permlab_videoWrite" msgid="128769316366746446">"modifica della tua raccolta di video"</string>
     <string name="permdesc_videoWrite" msgid="5448565757490640841">"Consente all\'app di modificare la tua raccolta di video."</string>
-    <string name="permlab_imagesWrite" msgid="3391306186247235510">"Modifica della tua raccolta di foto"</string>
+    <string name="permlab_imagesWrite" msgid="3391306186247235510">"modifica della tua raccolta di foto"</string>
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Consente all\'app di modificare la tua raccolta di foto."</string>
-    <string name="permlab_mediaLocation" msgid="8675148183726247864">"Lettura delle posizioni dalla tua raccolta multimediale"</string>
+    <string name="permlab_mediaLocation" msgid="8675148183726247864">"lettura delle posizioni dalla tua raccolta multimediale"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Consente all\'app di leggere le posizioni dalla tua raccolta multimediale."</string>
     <string name="biometric_dialog_default_title" msgid="881952973720613213">"Verifica la tua identità"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometrico non disponibile"</string>
@@ -551,9 +551,9 @@
   <string-array name="fingerprint_error_vendor">
   </string-array>
     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icona dell\'impronta digitale"</string>
-    <string name="permlab_manageFace" msgid="7262837876352591553">"gestisci l\'hardware per Sblocco col sorriso"</string>
+    <string name="permlab_manageFace" msgid="7262837876352591553">"gestione dell\'hardware per Sblocco col sorriso"</string>
     <string name="permdesc_manageFace" msgid="8919637120670185330">"Consente all\'app di richiamare i metodi per aggiungere e rimuovere i modelli di volti."</string>
-    <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"utilizza l\'hardware per Sblocco col sorriso"</string>
+    <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"utilizzo dell\'hardware per Sblocco col sorriso"</string>
     <string name="permdesc_useFaceAuthentication" msgid="4712947955047607722">"Consente all\'app di utilizzare hardware per l\'autenticazione con Sblocco col sorriso"</string>
     <string name="face_recalibrate_notification_name" msgid="1913676850645544352">"Sblocco col sorriso"</string>
     <string name="face_recalibrate_notification_title" msgid="4087620069451499365">"Registra di nuovo il volto"</string>
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Sposta il telefono verso sinistra."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Sposta il telefono verso destra."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Guarda più direttamente verso il dispositivo."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Impossibile vedere il volto. Guarda il telefono."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posiziona il viso davanti al telefono."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Troppo movimento. Tieni fermo il telefono."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Ripeti l\'acquisizione del volto."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Non è più possibile riconoscere il volto. Riprova."</string>
@@ -600,21 +600,21 @@
     <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Consente a un\'applicazione di modificare le impostazioni di sincronizzazione per un account. Ad esempio, può servire per attivare la sincronizzazione dell\'applicazione Persone con un account."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"lettura statistiche di sincronizz."</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Consente a un\'applicazione di leggere le statistiche di sincronizzazione per un account, incluse la cronologia degli eventi di sincronizzazione e la quantità di dati sincronizzati."</string>
-    <string name="permlab_sdcardRead" msgid="1438933556581438863">"leggere i contenuti dell\'archivio condiviso"</string>
+    <string name="permlab_sdcardRead" msgid="1438933556581438863">"lettura dei contenuti dell\'archivio condiviso"</string>
     <string name="permdesc_sdcardRead" msgid="1804941689051236391">"Consente all\'app di leggere i contenuti del tuo archivio condiviso."</string>
-    <string name="permlab_sdcardWrite" msgid="9220937740184960897">"modificare/eliminare i contenuti dell\'archivio condiviso"</string>
+    <string name="permlab_sdcardWrite" msgid="9220937740184960897">"modifica/eliminazione dei contenuti dell\'archivio condiviso"</string>
     <string name="permdesc_sdcardWrite" msgid="2834431057338203959">"Consente all\'app di modificare i contenuti del tuo archivio condiviso."</string>
-    <string name="permlab_use_sip" msgid="2052499390128979920">"fare/ricevere chiamate SIP"</string>
+    <string name="permlab_use_sip" msgid="2052499390128979920">"invio/ricezione di chiamate SIP"</string>
     <string name="permdesc_use_sip" msgid="2297804849860225257">"Consente all\'app di effettuare e ricevere chiamate SIP."</string>
     <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"registrazione di nuove connessioni SIM di telecomunicazione"</string>
     <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"Consente all\'app di registrare nuove connessioni SIM di telecomunicazione."</string>
     <string name="permlab_register_call_provider" msgid="108102120289029841">"registrazione di nuove connessioni di telecomunicazione"</string>
     <string name="permdesc_register_call_provider" msgid="7034310263521081388">"Consente all\'app di registrare nuove connessioni di telecomunicazione."</string>
-    <string name="permlab_connection_manager" msgid="1116193254522105375">"gestisci connessioni di telecomunicazione"</string>
+    <string name="permlab_connection_manager" msgid="1116193254522105375">"gestione di connessioni di telecomunicazione"</string>
     <string name="permdesc_connection_manager" msgid="5925480810356483565">"Consente all\'app di gestire connessioni di telecomunicazione."</string>
     <string name="permlab_bind_incall_service" msgid="6773648341975287125">"interazione con lo schermo durante una chiamata"</string>
     <string name="permdesc_bind_incall_service" msgid="8343471381323215005">"Consente all\'app di stabilire quando e come l\'utente vede lo schermo durante una chiamata."</string>
-    <string name="permlab_bind_connection_service" msgid="3557341439297014940">"interagire con i servizi di telefonia"</string>
+    <string name="permlab_bind_connection_service" msgid="3557341439297014940">"interazione con i servizi di telefonia"</string>
     <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Consente all\'app di interagire con i servizi di telefonia per effettuare/ricevere chiamate."</string>
     <string name="permlab_control_incall_experience" msgid="9061024437607777619">"offerta di un\'esperienza utente durante le chiamate"</string>
     <string name="permdesc_control_incall_experience" msgid="915159066039828124">"Consente all\'app di offrire un\'esperienza utente durante le chiamate."</string>
@@ -630,7 +630,7 @@
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Consente al titolare di vincolarsi all\'interfaccia di primo livello di un servizio listener di notifica. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"collegamento a un servizio provider di condizioni"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio provider di condizioni. Non dovrebbe essere mai necessaria per le normali app."</string>
-    <string name="permlab_bindDreamService" msgid="4153646965978563462">"associa a servizio dream"</string>
+    <string name="permlab_bindDreamService" msgid="4153646965978563462">"associazione a servizio dream"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Consente all\'utente di associare l\'interfaccia di primo livello di un servizio dream. Questa impostazione non è mai necessaria per le app normali."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"richiamo dell\'app di configurazione operatore-provider"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
@@ -646,7 +646,7 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Consente a un\'applicazione di rimuovere certificati DRM. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"associazione a un servizio di messaggi dell\'operatore"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Consente l\'associazione di un servizio di messaggi dell\'operatore all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
-    <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"Collegamento a servizi dell\'operatore"</string>
+    <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"associazione a servizi dell\'operatore"</string>
     <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Consente al titolare di collegarsi a servizi dell\'operatore. Non dovrebbe mai essere necessaria per le normali app."</string>
     <string name="permlab_access_notification_policy" msgid="4247510821662059671">"accesso alla funzione Non disturbare"</string>
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Consente all\'app di leggere e modificare la configurazione della funzione Non disturbare."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Apri con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Apri con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Apri"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Apri i link <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Apri i link con"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Apri i link con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Apri i link <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Fornisci accesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifica con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifica con %1$s"</string>
@@ -1434,7 +1430,7 @@
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Consente a un\'applicazione di richiedere l\'installazione di pacchetti."</string>
     <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"richiesta di eliminazione dei pacchetti"</string>
     <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Consente a un\'applicazione di richiedere l\'eliminazione di pacchetti."</string>
-    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"chiedi di ignorare le ottimizzazioni della batteria"</string>
+    <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"richiesta di ignorare le ottimizzazioni della batteria"</string>
     <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Consente a un\'app di chiedere l\'autorizzazione a ignorare le ottimizzazioni della batteria per quell\'app."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocca due volte per il comando dello zoom"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Aggiunta del widget non riuscita."</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Avviare l\'applicazione Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accettare la chiamata?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Imposta per aprire sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una volta"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Impostazioni"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non supporta il profilo di lavoro"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8add3d7..437b31b 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -574,7 +574,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"צריך להזיז את הטלפון שמאלה."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"צריך להזיז את הטלפון ימינה."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"יש להביט ישירות אל המכשיר."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"אי אפשר לראות את הפנים שלך. צריך להביט אל הטלפון."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"עליך למקם את הפנים ישירות מול הטלפון."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"יותר מדי תנועה. יש להחזיק את הטלפון בצורה יציבה."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"יש לרשום מחדש את הפנים."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"כבר לא ניתן לזהות פנים. יש לנסות שוב."</string>
@@ -1171,14 +1171,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"פתח באמצעות"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏פתח באמצעות %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"פתח"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"פתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות"</string>
+    <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="HOST">%1$s</xliff:g> באמצעות <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"הענקת גישה"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ערוך באמצעות"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ערוך באמצעות %1$s"</string>
@@ -1636,8 +1632,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"להפעיל את הדפדפן?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"האם לקבל את השיחה?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"תמיד"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"הגדרה כברירת מחדל לפתיחה"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"רק פעם אחת"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"הגדרות"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s אינו תומך בפרופיל עבודה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 2d09d67..b558a31 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"スマートフォンを左に動かしてください。"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"スマートフォンを右に動かしてください。"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"もっとまっすぐデバイスに顔を向けてください。"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"顔を確認できません。スマートフォンを見てください。"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"顔をスマートフォンの真正面に向けてください。"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"あまり動かさないでください。安定させてください。"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"顔を登録し直してください。"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"顔を認識できなくなりました。もう一度お試しください。"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"アプリで開く"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sで開く"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"開く"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> のリンクを開くブラウザ / アプリの選択"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"編集に使用"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sで編集"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ブラウザを起動しますか?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"通話を受けますか?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"常時"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"[常に開く] に設定"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"1回のみ"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sは仕事用プロファイルをサポートしていません"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index f810678..3570d4c 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"გადაანაცვლეთ ტელეფონი მარცხნივ."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"გადაანაცვლეთ ტელეფონი მარჯვნივ."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"გთხოვთ, უფრო პირდაპირ შეხედოთ თქვენს მოწყობილობას."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"თქვენი სახე არ ჩანს. შეხედეთ ტელეფონს."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"დაიჭირეთ სახე უშუალოდ ტელეფონის წინ."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"მეტისმეტად მოძრაობთ. მყარად დაიჭირეთ ტელეფონი."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"გთხოვთ, ხელახლა დაარეგისტრიროთ თქვენი სახე."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"სახის ამოცნობა ვეღარ ხერხდება. ცადეთ ხელახლა."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"გახსნა აპით"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s-ით გახსნა"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"გახსნა"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების გახსნა შემდეგით:"</string>
+    <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="HOST">%1$s</xliff:g> ბმულების <xliff:g id="APPLICATION">%2$s</xliff:g>-ით გახსნა"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"წვდომის მინიჭება"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"რედაქტირება აპით:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"რედაქტირება %1$s-ით"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"გსურთ ბრაუზერის გაშვება?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"უპასუხებთ ზარს?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ყოველთვის"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"ყოველთვის გახსნის დაყენება"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"მხოლოდ ერთხელ"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"პარამეტრები"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s მხარს არ უჭერს სამუშაო პროფილს"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 3c42986..2ed1e5b 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Телефонды солға жылжытыңыз."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Телефонды оңға жылжытыңыз."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Құрылғының камерасына тура қараңыз."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Бетіңіз көрінбейді. Телефонға қараңыз."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Бетіңізді телефонға тура қаратыңыз."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Қозғалыс тым көп. Телефонды қозғалтпаңыз."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Қайта тіркеліңіз."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Енді бет анықтау мүмкін емес. Әрекетті қайталаңыз."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Басқаша ашу"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s қолданбасымен ашу"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ашу"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін келесімен ашу:"</string>
+    <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="HOST">%1$s</xliff:g> сілтемелерін <xliff:g id="APPLICATION">%2$s</xliff:g> браузерімен ашу"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Рұқсат беру"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Келесімен өңдеу"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s көмегімен өңдеу"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Браузер қосылсын ба?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Қоңырауды қабылдау?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Үнемі"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Әрдайым ашық күйге орнату"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Бір рет қана"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Параметрлер"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жұмыс профилін қолдамайды"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index b088f4e..02c6ba8 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ផ្លាស់ទី​ទូរសព្ទទៅខាងឆ្វេង។"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ផ្លាស់ទីទូរសព្ទទៅខាងស្ដាំ។"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"សូមមើល​ឱ្យចំ​ឧបករណ៍​របស់អ្នក​ជាងមុន។"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"មើលមិនឃើញ​មុខ​របស់អ្នកទេ។ សូមសម្លឹងមើល​ទូរសព្ទ។"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"បែរមុខ​របស់អ្នក​ឱ្យចំ​ពីមុខ​ទូរសព្ទ​ផ្ទាល់។"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"មាន​ចលនា​ខ្លាំងពេក។ សូមកាន់​ទូរសព្ទ​ឱ្យនឹង។"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"សូម​​ស្កេន​បញ្ចូល​មុខរបស់អ្នក​ម្ដងទៀត។"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"មិន​អាច​សម្គាល់មុខ​បាន​ទៀតទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
@@ -1133,14 +1133,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"បើក​ជា​មួយ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"បើក​ជាមួយ %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"បើក"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"បើក​តំណ <xliff:g id="HOST">%1$s</xliff:g> ជាមួយ"</string>
+    <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="HOST">%1$s</xliff:g> ជាមួយ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ផ្តល់​សិទ្ធិ​ចូល​ប្រើ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"កែសម្រួល​ជាមួយ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"កែសម្រួល​ជាមួយ​ %1$s"</string>
@@ -1592,8 +1588,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ចាប់ផ្ដើម​កម្មវិធី​អ៊ីនធឺណិត?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"ទទួល​ការ​ហៅ​?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ជា​និច្ច"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"កំណត់​ឱ្យ​បើក​ជានិច្ច"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"តែ​ម្ដង"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ការកំណត់"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s មិន​គាំទ្រ​ប្រវត្តិរូប​ការងារ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 6da7eec..875ecd4 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ಫೋನ್ ಅನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ಫೋನ್ ಅನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಹೆಚ್ಚಿನದ್ದನ್ನು ನೇರವಾಗಿ ನೋಡಿ."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"ನಿಮ್ಮ ಮುಖ ಕಾಣಿಸುತ್ತಿಲ್ಲ. ಫೋನ್ ಕಡೆಗೆ ನೋಡಿ."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"ನಿಮ್ಮ ಮುಖವನ್ನು ಫೋನ್‌ಗೆ ನೇರವಾಗಿ ಇರಿಸಿ."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ತುಂಬಾ ಅಲುಗಾಡುತ್ತಿದೆ ಫೋನ್ ಅನ್ನು ಸ್ಥಿರವಾಗಿ ಹಿಡಿಯಿರಿ."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"ನಿಮ್ಮ ಮುಖವನ್ನು ಮರುನೋಂದಣಿ ಮಾಡಿ."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"ಮುಖ ಗುರುತಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ಇದರ ಮೂಲಕ ತೆರೆಯಿರಿ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ಜೊತೆಗೆ ತೆರೆಯಿರಿ"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ತೆರೆ"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"ಇವುಗಳ ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"ಇವರ ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ಬ್ರೌಸರ್ ಪ್ರಾರಂಭಿಸುವುದೇ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"ಕರೆ ಸ್ವೀಕರಿಸುವುದೇ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ಯಾವಾಗಲೂ"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"ಯಾವಾಗಲೂ ತೆರೆಯುವುದಕ್ಕೆ ಹೊಂದಿಸಿ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ಒಮ್ಮೆ ಮಾತ್ರ"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 853ccff..9077145 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"휴대전화를 왼쪽으로 이동하세요."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"휴대전화를 오른쪽으로 이동하세요."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"기기에서 더 똑바로 바라보세요."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"얼굴이 보이지 않습니다. 휴대전화를 바라보세요."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"휴대전화가 얼굴 정면을 향하도록 두세요."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"너무 많이 움직였습니다. 휴대전화를 흔들리지 않게 잡으세요."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"얼굴을 다시 등록해 주세요."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"더 이상 얼굴을 인식할 수 없습니다. 다시 시도하세요."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"연결 프로그램"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s(으)로 열기"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"열기"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> 링크를 열 때 사용할 앱"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"편집 프로그램:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s(으)로 수정"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"브라우저를 실행하시겠습니까?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"통화를 수락하시겠습니까?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"항상"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"항상 열도록 설정"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"한 번만"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"설정"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s에서 직장 프로필을 지원하지 않습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e5b11ba..8cac363 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Телефонду солго жылдырыңыз."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Телефонду оңго жылдырыңыз."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Түзмөгүңүзгө түз караңыз."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Жүзүңүз көрүнбөй жатат. Телефонду караңыз."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Телефонду жүзүңүздүн маңдайында кармаңыз."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Кыймылдап жибердиңиз. Телефонду түз кармаңыз."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Жүзүңүздү кайра таанытыңыз."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Жүз таанылган жок. Кайра аракет кылыңыз."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Төмөнкү менен ачуу"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s менен ачуу"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ачуу"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> шилтемелерин төмөнкү колдонмодо ачуу:"</string>
+    <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="HOST">%1$s</xliff:g> шилтемелерин <xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосунда ачуу"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Мүмкүнчүлүк берүү"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Төмөнкү менен түзөтүү"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s менен түзөтүү"</string>
@@ -1592,8 +1588,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Серепчи иштетилсинби?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Чалуу кабыл алынсынбы?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Дайыма"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Ар дайым ачылсын деп жөндөө"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Бир жолу гана"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Жөндөөлөр"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жумуш профилин колдоого албайт"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 74b311a..47b0fe4 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ຍ້າຍໂທລະສັບໄປທາງຊ້າຍ."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ຍ້າຍໂທລະສັບໄປທາງຂວາ."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ກະລຸນາເບິ່ງອຸປະກອນຂອງທ່ານໃຫ້ຊື່ໆ."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"ບໍ່ສາມາດເບິ່ງເຫັນໜ້າຂອງທ່ານໄດ້. ກະລຸນາເບິ່ງໂທລະສັບ."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"ຫັນໜ້າຂອງທ່ານໄປໃສ່ໜ້າໂທລະສັບໂດຍກົງ."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ເຄື່ອນໄຫວຫຼາຍເກີນໄປ. ກະລຸນາຖືໂທລະສັບໄວ້ຊື່ໆ."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"ກະລຸນາລົງທະບຽນອຸປະກອນຂອງທ່ານອີກເທື່ອໜຶ່ງ."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້ອີກຕໍ່ໄປ. ກະລຸນາລອງໃໝ່."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ເປີດໂດຍໃຊ້"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"ເປີດ​ໂດຍ​ໃຊ້ %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ເປີດ"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"ເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ໂດຍໃຊ້"</string>
+    <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="HOST">%1$s</xliff:g> ໂດຍໃຊ້ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ໃຫ້ສິດອະນຸຍາດ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"​ແກ້​ໄຂ​ໃນ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"ແກ້​ໄຂ​ໃນ %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ເປີດໂປຣແກຣມທ່ອງເວັບ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"ຮັບການໂທບໍ່?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ທຸກຄັ້ງ"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"ຕັ້ງໃຫ້ເປັນເປີດທຸກເທື່ອ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ຄັ້ງດຽວ"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ການຕັ້ງຄ່າ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ບໍ່​ຮອງ​ຮັບ​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 191108a..6f8e2df 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -574,7 +574,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Pasukite telefoną kairėn."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Pasukite telefoną dešinėn."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Žiūrėkite tiesiai į įrenginį."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nematau jūsų veido. Žiūrėkite į telefoną."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Veidas turi būti prieš telefoną."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Įrenginys per daug judinamas. Nejudink. telefono."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Užregistruokite veidą iš naujo."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Nebegalima atpažinti veido. Bandykite dar kartą."</string>
@@ -1171,14 +1171,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Atidaryti naudojant"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atidaryti naudojant %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atidaryti"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Atidaryti nuorodas naudojant"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Atidaryti nuorodas naudojant „<xliff:g id="APPLICATION">%1$s</xliff:g>“"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant „<xliff:g id="APPLICATION">%2$s</xliff:g>“"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Suteikti prieigą"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redaguoti naudojant"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redaguoti naudojant %1$s"</string>
@@ -1636,8 +1632,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Paleisti naršyklę?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Priimti skambutį?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Visada"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Nustatyti parinktį „Visada atidaryti“"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tik kartą"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nustatymai"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nepalaiko darbo profilio"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 94f1489..253ff72 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -571,7 +571,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Pārvietojiet tālruni pa kreisi."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Pārvietojiet tālruni pa labi."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Lūdzu, tiešāk skatieties uz savu ierīci."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Jūsu seja nav redzama. Paskatieties uz tālruni."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Novietojiet savu seju tieši pretī tālrunim."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Pārāk daudz kustību. Nekustīgi turiet tālruni."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Lūdzu, atkārtoti reģistrējiet savu seju."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Seju vairs nevar atpazīt. Mēģiniet vēlreiz."</string>
@@ -1151,14 +1151,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Atvērt, izmantojot"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atvērt, izmantojot %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atvērt"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> saišu atvēršana, izmantojot:"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Saišu atvēršana, izmantojot:"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Saišu atvēršana, izmantojot pārlūku <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> saišu atvēršana, izmantojot pārlūku <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Atļaut piekļuvi"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Rediģēt, izmantojot"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediģēt, izmantojot %1$s"</string>
@@ -1613,8 +1609,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vai palaist pārlūkprogrammu?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vai atbildēt uz zvanu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vienmēr"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Iestatīt uz “Vienmēr atvērt”"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tikai vienreiz"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Iestatījumi"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Programma %1$s neatbalsta darba profilus"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 71d695a..19c1c85 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Поместете го телефонот налево."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Поместете го телефонот надесно."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Погледнете подиректно во уредот."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Не ви се гледа ликот. Гледајте во телефонот."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Наместете го лицето директно пред телефонот."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Премногу движење. Држете го телефонот стабилно."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Повторно регистрирајте го лицето."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ликот не се препознава. Обидете се повторно."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Отвори со"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отвори со %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Отворајте врски на <xliff:g id="HOST">%1$s</xliff:g> со"</string>
+    <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="HOST">%1$s</xliff:g> со <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи пристап"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Измени со"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измени со %1$s"</string>
@@ -1593,8 +1589,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Стартувај прелистувач?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прифати повик?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Секогаш"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Поставете на секогаш отворај"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Само еднаш"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Поставки"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддржува работен профил"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index b58f195..b2e9b64 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ഫോൺ ഇടത്തോട്ട് നീക്കുക."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ഫോൺ വലത്തോട്ട് നീക്കുക."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"നിങ്ങളുടെ ഉപകരണത്തിന് നേരെ കൂടുതൽ നന്നായി നോക്കുക."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"നിങ്ങളുടെ മുഖം കാണാനാവുന്നില്ല. ഫോണിലേക്ക് നോക്കൂ."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"നിങ്ങളുടെ മുഖം ക്യാമറയ്‌ക്ക് നേരെയാക്കുക."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"വളരെയധികം ചലനം. ഫോൺ അനക്കാതെ നേരെ പിടിക്കുക."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"നിങ്ങളുടെ മുഖം വീണ്ടും എൻറോൾ ചെയ്യുക."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"ഇനി മുഖം തിരിച്ചറിയാനാവില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ഇത് ഉപയോഗിച്ച് തുറക്കുക"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ഉപയോഗിച്ച് തുറക്കുക"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"തുറക്കുക"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച് <xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ തുറക്കുക"</string>
+    <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="HOST">%1$s</xliff:g> ലിങ്കുകൾ <xliff:g id="APPLICATION">%2$s</xliff:g> ഉപയോഗിച്ച് തുറക്കുക"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ആക്‌സസ് നൽകുക"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ഇത് ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ബ്രൗസർ സമാരംഭിക്കണോ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"കോൾ സ്വീകരിക്കണോ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"എല്ലായ്പ്പോഴും"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"\'എല്ലായ്‌പ്പോഴും തുറക്കുക\' എന്നതിലേക്കാക്കുക"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ഒരിക്കൽ മാത്രം"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ക്രമീകരണം"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, ഔദ്യോഗിക പ്രൊഫൈലിനെ പിന്തുണയ്‌ക്കുന്നില്ല"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 9f1de46..a229713 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Утсаа зүүн тийш болгоно уу."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Утсаа баруун тийш болгоно уу."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Төхөөрөмж рүүгээ аль болох эгц харна уу."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Таны царайг харахгүй байна. Утас руу харна уу."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Царайгаа утасны урд эгц байрлуулна уу"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Хэт их хөдөлгөөнтэй байна. Утсаа хөдөлгөөнгүй барина уу."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Нүүрээ дахин бүртгүүлнэ үү."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Царайг таних боломжгүй боллоо. Дахин оролдоно уу."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Нээх"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ашиглан нээх"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Нээх"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосуудыг дараахаар нээх"</string>
+    <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="HOST">%1$s</xliff:g>-н холбоосуудыг <xliff:g id="APPLICATION">%2$s</xliff:g>-р нээх"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Хандалт өгөх"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Засварлах"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ашиглан засварлах"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Хөтөч ажиллуулах уу?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Дуудлагыг зөвшөөрөх үү?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Байнга"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Тогтмол нээлттэй гэж тохируулах"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Нэг удаа"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Тохиргоо"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ажлын профайлыг дэмждэггүй"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f2111e7..a86caa5 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"फोन डावीकडे हलवा."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"फोन उजवीकडे हलवा."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"कृपया तुमच्या डिव्हाइसकडे थेट पाहा"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"तुमचा चेहरा दिसत नाही. फोनकडे पहा."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"तुमचा चेहरा थेट फोन समोर आणा."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"खूप हलत आहे. फोन स्थिर धरून ठेवा."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"कृपया तुमच्या चेहऱ्याची पुन्हा नोंदणी करा."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"चेहरा ओळखू शकत नाही. पुन्हा प्रयत्न करा."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"यासह उघडा"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s सह उघडा"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"उघडा"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"वापरून <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडा"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"सह संपादित करा"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s सह संपादित करा"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउझर लाँच करायचा?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकारायचा?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"नेहमी"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"नेहमी उघडावर सेट करा"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"फक्त एकदाच"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग्ज"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफाईलचे समर्थन करीत नाही"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 49a5578..c18e078 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Alihkan telefon ke kiri."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Alihkan telefon ke kanan."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Sila lihat terus pada peranti anda."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Gagal mengesan wajah anda. Lihat telefon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Letakkan wajah anda betul-betul di depan telefon."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Terlalu bnyk gerakan. Pegang telefon dgn stabil."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Sila daftarkan semula wajah anda."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Tidak lagi dapat mengecam wajah. Cuba lagi."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Buka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Buka pautan dengan"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Buka pautan dengan <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Buka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Lancarkan Penyemak Imbas?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sentiasa"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Tetapkan agar sentiasa dibuka"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Tetapan"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak menyokong profil kerja"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index bbe115f..55e7b01 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ဖုန်းကို ဘယ်ဘက်သို့ရွှေ့ပါ။"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ဖုန်းကို ညာဘက်သို့ ရွှေ့ပါ။"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"သင့်စက်ပစ္စည်းကို တည့်တည့်ကြည့်ပါ။"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"သင့်မျက်နှာကို မမြင်ရပါ။ ဖုန်းကိုကြည့်ပါ။"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"မျက်နှာကို ဖုန်းရှေ့တွင် တည့်အောင်ထားပါ။"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"လှုပ်လွန်းသည်။ ဖုန်းကို ငြိမ်ငြိမ်ကိုင်ပါ။"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"သင့်မျက်နှာကို ပြန်စာရင်းသွင်းပါ။"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"မျက်နှာ မမှတ်သားနိုင်တော့ပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"...ဖြင့် ဖွင့်မည်"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ဖြင့် ဖွင့်မည်"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ဖွင့်ပါ"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို အောက်ပါဖြင့် ဖွင့်ရန်−"</string>
+    <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="HOST">%1$s</xliff:g> လင့်ခ်များကို <xliff:g id="APPLICATION">%2$s</xliff:g> ဖြင့် ဖွင့်ရန်"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ဖွင့်ခွင့်ပေးရန်"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"...နှင့် တည်းဖြတ်ရန်"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s နှင့် တည်းဖြတ်ရန်"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ဘရောက်ဇာ ဖွင့်မည်လား။"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"ဖုန်းခေါ်ဆိုမှုကို လက်ခံမလား?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"အမြဲတမ်း"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"အမြဲဖွင့်မည်အဖြစ် သတ်မှတ်ရန်"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"တစ်ခါတည်း"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ဆက်တင်များ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s က အလုပ်ပရိုဖိုင်ကို မပံ့ပိုးပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 34275df..a589389 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Flytt telefonen til venstre."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Flytt telefonen til høyre."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Se mer direkte på enheten din."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Kan ikke se ansiktet ditt. Se på telefonen."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Hold ansiktet ditt rett foran telefonen."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"For mye bevegelse. Hold telefonen stødig."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registrer ansiktet ditt på nytt."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Kan ikke gjenkjenne ansiktet lenger. Prøv igjen."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Åpne med"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åpne med %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åpne"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Åpne linker med"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Åpne linker med <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Gi tilgang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vil du starte nettleseren?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare anropet?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Angi som alltid åpen"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bare én gang"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Innstillinger"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s støtter ikke arbeidsprofiler"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 80bd83a..89e75b4 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"फोन बायाँतिर सार्नुहोस्।"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"फोन दायाँतिर सार्नुहोस्।"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"कृपया अझ सीधा गरी आफ्नो स्क्रिनमा हेर्नुहोस्।"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"तपाईंको अनुहार देखिएन। फोनमा हेर्नुहोस्।"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"आफ्नो अनुहार फोनको सीधा अगाडि पार्नुहोस्।"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"अत्यधिक हल्लियो। फोन स्थिर राख्नुहोस्।"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"कृपया आफ्नो अनुहार पुनः दर्ता गर्नुहोस्।"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"अब उप्रान्त अनुहार पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
@@ -1135,14 +1135,10 @@
     <!-- no translation found for whichViewApplicationNamed (2286418824011249620) -->
     <skip />
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोल्नुहोस्"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"निम्नमार्फत <xliff:g id="HOST">%1$s</xliff:g> का लिंकहरू खोल्नुहोस्"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"सँग सम्पादन गर्नुहोस्"</string>
     <!-- String.format failed for translation -->
@@ -1596,8 +1592,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउजर सुरु गर्ने हो?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"कल स्वीकार गर्नुहुन्छ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"सधैँ"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"सधैँ खुला राख्ने गरी सेट गर्नुहोस्"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"एक पटक मात्र"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिङहरू"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s  कार्य प्रोफाइल समर्थन गर्दैन"</string>
@@ -1975,7 +1970,7 @@
     <string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"तटीय क्षेत्र र नदीछेउका ठाउँहरू छाडी उच्च सतहमा अवस्थित कुनै अझ सुरक्षित ठाउँमा जानुहोस्।"</string>
     <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"शान्त रहनुहोस् र नजिकै आश्रयस्थल खोज्नुहोस्।"</string>
     <string name="etws_primary_default_message_test" msgid="2709597093560037455">"आपतकालीन सन्देशहरूको परीक्षण"</string>
-    <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"जवाफ दिनुहोस्"</string>
+    <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"जवाफ दिनु…"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
     <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM मार्फत भ्वाइस कल गर्न मिल्दैन"</string>
     <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM मार्फत भ्वाइस कल गर्ने प्रावधान छैन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7c23e2c..4194eb1 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Beweeg je telefoon meer naar links."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Beweeg je telefoon meer naar rechts."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Kijk rechter naar je apparaat."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Je gezicht is niet te zien. Kijk naar de telefoon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Houd je gezicht recht voor de telefoon."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Te veel beweging. Houd je telefoon stil."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registreer je gezicht opnieuw."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Herkent gezicht niet meer. Probeer het nog eens."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Openen met"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Openen met %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Openen"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Links van <xliff:g id="HOST">%1$s</xliff:g> openen met"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Links openen met"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Links openen met <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Links van <xliff:g id="HOST">%1$s</xliff:g> openen met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Toegang geven"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Bewerken met"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Bewerken met %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Browser starten?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Gesprek accepteren?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altijd"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Instellen op altijd openen"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Één keer"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellingen"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ondersteunt werkprofielen niet"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 257dd06..0f3472c 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ବାମ ପଟକୁ ଫୋନ୍ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ଡାହାଣ ପଟକୁ ଫୋନ୍ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ଦୟାକରି ଆପଣଙ୍କ ଡିଭାଇସ୍‌କୁ ସିଧାସଳଖ ଦେଖନ୍ତୁ।"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"ଆପଣଙ୍କର ମୁହଁ ଦେଖି ପାରୁନାହିଁ। ଫୋନ୍‌କୁ ଦେଖନ୍ତୁ।"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"ଆପଣଙ୍କ ମୁହଁକୁ ଫୋନ୍ ସାମ୍ନାରେ ସିଧାସଳଖ ରଖନ୍ତୁ।"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ଅତ୍ୟଧିକ ଅସ୍ଥିର। ଫୋନ୍‍କୁ ସ୍ଥିର ଭାବେ ଧରନ୍ତୁ।"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"ଦୟାକରି ଆପଣଙ୍କର ମୁହଁ ପୁଣି-ଏନ୍‍ରୋଲ୍ କରନ୍ତୁ।"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"ଆଉ ମୁହଁ ଚିହ୍ନଟ କରିହେଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ସହିତ ଖୋଲନ୍ତୁ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ସହିତ ଖୋଲନ୍ତୁ"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ଖୋଲନ୍ତୁ"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"ଏଥିରେ <xliff:g id="HOST">%1$s</xliff:g> ଲିଙ୍କ୍‍ଗୁଡ଼ିକ ଖୋଲନ୍ତୁ"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"ସହିତ ଏଡିଟ୍‌ କରନ୍ତୁ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sରେ ସଂଶୋଧନ କରନ୍ତୁ"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ବ୍ରାଉଜର୍‍ ଲଞ୍ଚ କରିବେ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"କଲ୍‍ ସ୍ୱୀକାର କରିବେ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ସର୍ବଦା"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"\'ସର୍ବଦା ଖୋଲା\' ଭାବରେ ସେଟ୍ କରନ୍ତୁ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ଥରେ ମାତ୍ର"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ସେଟିଂସ୍"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ୱର୍କ ପ୍ରୋଫାଇଲ୍‌କୁ ସପୋର୍ଟ କରୁନାହିଁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 104fb40..8245546 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ਫ਼ੋਨ ਨੂੰ ਖੱਬੇ ਪਾਸੇ ਲਿਜਾਓ।"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ਫ਼ੋਨ ਨੂੰ ਸੱਜੇ ਪਾਸੇ ਲਿਜਾਓ।"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ਕਿਰਪਾ ਕਰਕੇ ਸਿੱਧਾ ਆਪਣੇ ਡੀਵਾਈਸ ਵੱਲ ਦੇਖੋ।"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"ਤੁਹਾਡਾ ਚਿਹਰਾ ਨਹੀਂ ਦਿਸ ਰਿਹਾ। ਫ਼ੋਨ ਵੱਲ ਦੇਖੋ।"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"ਆਪਣਾ ਚਿਹਰਾ ਫ਼ੋਨ ਦੇ ਬਿਲਕੁਲ ਸਾਹਮਣੇ ਰੱਖੋ।"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਹਿਲਜੁਲ। ਫ਼ੋਨ ਨੂੰ ਸਥਿਰ ਰੱਖੋ।"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"ਕਿਰਪਾ ਕਰਕੇ ਆਪਣਾ ਚਿਹਰਾ ਦੁਬਾਰਾ ਦਰਜ ਕਰੋ।"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"ਹੁਣ ਚਿਹਰਾ ਪਛਾਣਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ਨਾਲ ਖੋਲ੍ਹੋ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ਨਾਲ ਖੋਲ੍ਹੋ"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ਖੋਲ੍ਹੋ"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ ਇਸ ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+    <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="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਖੋਲ੍ਹੋ"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ਪਹੁੰਚ ਦਿਓ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ਇਸ ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ਕੀ ਬ੍ਰਾਊਜ਼ਰ ਲਾਂਚ ਕਰਨਾ ਹੈ?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"ਕੀ ਕਾਲ ਸਵੀਕਾਰ ਕਰਨੀ ਹੈ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ਹਮੇਸ਼ਾਂ"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"ਹਮੇਸ਼ਾਂ ਖੁੱਲ੍ਹਾ \'ਤੇ ਸੈੱਟ ਕਰੋ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ਕੇਵਲ ਇੱਕ ਵਾਰ"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a61555b..054a456 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -574,7 +574,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Przesuń telefon w lewo."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Przesuń telefon w prawo."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Patrz prosto na urządzenie."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nie widzę Twojej twarzy. Spójrz na telefon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Ustaw twarz dokładnie na wprost telefonu."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Telefon się porusza. Trzymaj go nieruchomo."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Zarejestruj swoją twarz ponownie."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Nie można już rozpoznać twarzy. Spróbuj ponownie."</string>
@@ -1171,14 +1171,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otwórz w aplikacji"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otwórz w aplikacji %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otwórz"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otwieraj linki z: <xliff:g id="HOST">%1$s</xliff:g> w"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otwieraj linki w"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otwieraj linki w aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otwieraj linki z: <xliff:g id="HOST">%1$s</xliff:g> w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udziel uprawnień"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edytuj w aplikacji"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edytuj w aplikacji %1$s"</string>
@@ -1636,8 +1632,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Uruchomić przeglądarkę?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Odebrać połączenie?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Zawsze"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Zawsze otwieraj"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tylko raz"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ustawienia"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nie obsługuje profilu do pracy"</string>
@@ -1717,7 +1712,7 @@
     <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Gdy skrót jest włączony, jednoczesne naciśnięcie przez trzy sekundy obu klawiszy sterowania głośnością uruchomi funkcję ułatwień dostępu.\n\nBieżąca funkcja ułatwień dostępu:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nFunkcję możesz zmienić, wybierając Ustawienia &gt; Ułatwienia dostępu."</string>
     <string name="disable_accessibility_shortcut" msgid="627625354248453445">"Wyłącz skrót"</string>
     <string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Użyj skrótu"</string>
-    <string name="color_inversion_feature_name" msgid="4231186527799958644">"Inwersja kolorów"</string>
+    <string name="color_inversion_feature_name" msgid="4231186527799958644">"Odwrócenie kolorów"</string>
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcja kolorów"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 11c6a28..742fa81 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Mova o smartphone para a esquerda."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Mova o smartphone para a direita."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Olhe mais diretamente para o dispositivo."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Não é possível ver o rosto. Olhe para o telefone."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Deixe o rosto diretamente na frente do smartphone."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Muito movimento. Não mova o smartphone."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registre seu rosto novamente."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"O rosto não é mais reconhecido. Tente novamente."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir links com"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir links com <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Abrir Navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Definir como \"Sempre abrir\""</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ed26c2d..85fb7fd 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Mova o telemóvel para a esquerda."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Mova o telemóvel para a direita."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Olhe mais diretamente para o dispositivo."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Não consigo ver o rosto. Olhe para o telemóvel."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posicione o rosto em frente ao telemóvel."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Demasiado movimento. Mantenha o telemóvel firme."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Volte a inscrever o rosto."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Impossível reconhecer o rosto. Tente novamente."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com:"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abra os links com:"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abra os links com a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com a aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Iniciar Navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Definir como abrir sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Apenas uma vez"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Definições"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não suporta o perfil de trabalho"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 11c6a28..742fa81 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Mova o smartphone para a esquerda."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Mova o smartphone para a direita."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Olhe mais diretamente para o dispositivo."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Não é possível ver o rosto. Olhe para o telefone."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Deixe o rosto diretamente na frente do smartphone."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Muito movimento. Não mova o smartphone."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registre seu rosto novamente."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"O rosto não é mais reconhecido. Tente novamente."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir links com"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir links com <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Abrir Navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Definir como \"Sempre abrir\""</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index edbc2a4..2f464e9 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -571,7 +571,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Mutați telefonul spre stânga."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Mutați telefonul spre dreapta."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Priviți mai direct spre dispozitiv."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nu vi se vede fața. Uitați-vă la telefon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Stați cu capul direct în fața telefonului."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Prea multă mișcare. Țineți telefonul nemișcat."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Reînregistrați-vă chipul."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Nu se mai poate recunoaște fața. Încercați din nou."</string>
@@ -1151,14 +1151,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Deschideți cu"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Deschideți cu %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Deschideți"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Deschideți linkurile <xliff:g id="HOST">%1$s</xliff:g> cu"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Deschideți linkurile cu"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Deschideți linkurile cu <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Deschideți linkurile <xliff:g id="HOST">%1$s</xliff:g> cu <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permiteți accesul"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editați cu"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editați cu %1$s"</string>
@@ -1613,8 +1609,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Lansați browserul?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Acceptați apelul?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Întotdeauna"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Schimbați la „Deschideți întotdeauna”"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Numai o dată"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setări"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nu acceptă profilul de serviciu"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a7c5c7a..c4b61b2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -574,7 +574,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Переместите телефон влево."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Переместите телефон вправо."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Смотрите прямо на устройство."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Вашего лица не видно. Смотрите на телефон."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Держите телефон прямо перед лицом."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Не перемещайте устройство. Держите его неподвижно."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Повторите попытку."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Не удалось распознать лицо. Повторите попытку."</string>
@@ -1171,14 +1171,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Открыть с помощью приложения:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Открыть с помощью приложения \"%1$s\""</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Открыть"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Открывать ссылки вида <xliff:g id="HOST">%1$s</xliff:g> с помощью:"</string>
+    <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="HOST">%1$s</xliff:g> в браузере <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Открыть доступ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редактировать с помощью приложения:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактировать с помощью приложения \"%1$s\""</string>
@@ -1636,8 +1632,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Запустить браузер?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ответить?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Всегда"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Всегда открывать"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Только сейчас"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддерживает рабочие профили"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index c23728e..ddeb94b 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"දුරකථනය වමට ගෙන යන්න."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"දුරකථනය දකුණට ගෙන යන්න."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ඔබේ උපාංගය වෙත තවත් ඍජුව බලන්න."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"ඔබේ මුහුණ දැකිය නොහැක. දුරකථනය වෙත බලන්න."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"ඔබේ මුහුණ දුරකථනයට සෘජුවම ඉදිරියෙන් ස්ථානගත කරන්න."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"චලනය ඉතා වැඩියි. දුරකථනය ස්ථිරව අල්ලා සිටින්න."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"ඔබේ මුහුණ යළි ලියාපදිංචි කරන්න."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"තවදුරටත් මුහුණ හඳුනාගත නොහැක. නැවත උත්සාහ කරන්න."</string>
@@ -1133,14 +1133,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"සමඟ විවෘත කරන්න"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s සමඟ විවෘත කරන්න"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"විවෘත කරන්න"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"සමග <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කරන්න"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"සමඟ සංස්කරණය කරන්න"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s සමඟ සංස්කරණය කරන්න"</string>
@@ -1592,8 +1588,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"බ්‍රවුසරය දියත් කරන්නද?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"ඇමතුම පිළිගන්නවාද?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"සැම විටම"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"සැම විට විවෘත ලෙස සකසන්න"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"එක් වාරයයි"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"සැකසීම්"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s කාර්යාල පැතිකඩ සඳහා සහාය ලබනොදේ."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 76b211a..4d19308 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -574,7 +574,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Posuňte telefón doľava."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Posuňte telefón doprava."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Pozrite sa priamejšie na zariadenie."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nie je vidieť vašu tvár. Pozrite sa na telefón."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Umiestnite svoju tvár priamo pred telefón."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Priveľa pohybu. Nehýbte telefónom."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Znova zaregistrujte svoju tvár."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Tvár už nie je možné rozpoznať. Skúste to znova."</string>
@@ -1171,14 +1171,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvoriť v aplikácii"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvoriť v aplikácii %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvoriť"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otvárajte odkazy z webu <xliff:g id="HOST">%1$s</xliff:g> v prehliadači alebo aplikácii"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otvárajte odkazy v prehliadači"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otvárajte odkazy v prehliadači <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otvárajte odkazy z webu <xliff:g id="HOST">%1$s</xliff:g> v prehliadači <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udeliť prístup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Upraviť pomocou"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upraviť v aplikácii %1$s"</string>
@@ -1636,8 +1632,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Spustiť prehliadač?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prijať hovor?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Nastaviť na Vždy otvárať"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Len raz"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavenia"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Spúšťač %1$s nepodporuje pracovné profily"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 943e9e2..b2b3109 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -574,7 +574,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Telefon premaknite v levo."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Telefon premaknite v desno."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Glejte bolj naravnost v napravo."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Obraz ni viden. Poglejte v telefon."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Obraz nastavite naravnost pred telefon."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Preveč se premikate. Držite telefon pri miru."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Znova prijavite svoj obraz."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Obraza ni več mogoče prepoznati. Poskusite znova."</string>
@@ -1171,14 +1171,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Odpiranje z aplikacijo"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Odpiranje z aplikacijo %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Odpiranje"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Odpiranje povezav z"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Odpiranje povezav z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogoči dostop"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Urejanje z aplikacijo"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Urejanje z aplikacijo %1$s"</string>
@@ -1636,8 +1632,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Ali želite odpreti brskalnik?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ali želite sprejeti klic?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vedno"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Nastavi na »vedno odpri«"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo tokrat"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavitve"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podpira delovnega profila"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 28f6062..afed336 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Lëvize telefonin majtas."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Lëvize telefonin djathtas"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Shiko më drejt në pajisjen tënde."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Fytyra jote nuk shfaqet. Shiko te telefoni."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Pozicionoje fytyrën tënde direkt përpara telefonit."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Ka shumë lëvizje. Mbaje telefonin të palëvizur."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Regjistroje përsëri fytyrën tënde."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Fytyra nuk mund të njihet më. Provo përsëri."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Hap me"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Hap me %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Hap"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Hapi lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Hapi lidhjet me"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Hapi lidhjet me <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Hapi lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Jep qasje"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redakto me"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redakto me %1$s"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Të hapet shfletuesi?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Dëshiron ta pranosh telefonatën?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Gjithmonë"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Caktoje si gjithmonë të hapur"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Vetëm një herë"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cilësimet"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nuk e mbështet profilin e punës"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4fdf301..110b31d 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -571,7 +571,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Померите телефон улево."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Померите телефон удесно."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Гледајте право у уређај."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Не види се лице. Гледајте у телефон."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Поставите лице директно испред телефона"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Много се померате. Држите телефон мирно."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Поново региструјте лице."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Више не може да се препозна лице. Пробајте поново."</string>
@@ -1151,14 +1151,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Отворите помоћу"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отворите помоћу апликације %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Отварајте <xliff:g id="HOST">%1$s</xliff:g> линкове помоћу"</string>
+    <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="HOST">%1$s</xliff:g> линкове помоћу апликације <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи приступ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Измените помоћу"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измените помоћу апликације %1$s"</string>
@@ -1613,8 +1609,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Желите ли да покренете прегледач?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Желите ли да прихватите позив?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Увек"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Подеси на „увек отварај“"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Само једном"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Подешавања"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не подржава пословни профил"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index ff82a14..bc1752e 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Flytta mobilen åt vänster."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Flytta mobilen åt höger."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Titta rakt på enheten."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ansiktet syns inte. Titta på mobilen."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Ha ansiktet direkt framför telefonen."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"För mycket rörelse. Håll mobilen stilla."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registrera ansiktet på nytt."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ansiktet kan inte längre kännas igen. Försök igen."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Öppna med"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Öppna med %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öppna"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Öppna länkar på <xliff:g id="HOST">%1$s</xliff:g> med"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Öppna länkar med"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Öppna länkar med <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Öppna länkar på <xliff:g id="HOST">%1$s</xliff:g> med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ge åtkomst"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redigera med"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigera med %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vill du öppna webbläsaren?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vill du ta emot samtal?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Ställ in på att alltid öppnas"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara en gång"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Inställningar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s har inte stöd för arbetsprofil"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 528d5d7a..92510ea 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Sogeza simu upande wa kushoto."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Sogeza simu upande wa kulia."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Tafadhali angalia kifaa chako moja kwa moja."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Uso wako hauonekani. Angalia simu."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Weka uso wako moja kwa moja mbele ya simu."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Inatikisika sana. Ishike simu iwe thabiti."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Tafadhali sajili uso wako tena."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Haiwezi tena kutambua uso. Jaribu tena."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Fungua ukitumia"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Fungua ukitumia %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Fungua"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Fungua viungo vya <xliff:g id="HOST">%1$s</xliff:g> ukitumia"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Fungua viungo ukitumia"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Fungua viungo ukitumia <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Fungua viungo vya <xliff:g id="HOST">%1$s</xliff:g> ukitumia <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Idhinisha ufikiaji"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Badilisha kwa"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Badilisha kwa %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Zindua Kivinjari?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Kubali simu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Kila mara"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Weka ifunguke kila wakati"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Mara moja tu"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mipangilio"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s haitumii wasifu wa kazini"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 39cd685..8ddcfe6 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"மொபைலை இடப்புறம் நகர்த்தவும்."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"மொபைலை வலப்புறம் நகர்த்தவும்."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"முழுமுகம் தெரியுமாறு நேராகப் பார்க்கவும்."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"முகம் சரியாகத் தெரியவில்லை. மொபைலைப் பார்க்கவும்."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"முகத்தை மொபைலுக்கு நேராக வைக்கவும்."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"அதிகமாக அசைகிறது. மொபைலை அசைக்காமல் பிடிக்கவும்."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"உங்கள் முகத்தை மீண்டும் பதிவுசெய்யுங்கள்."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"முகத்தைக் கண்டறிய இயலவில்லை. மீண்டும் முயலவும்."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"இதன்மூலம் திற"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s மூலம் திற"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"திற"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளை இதன் மூலம் திற:"</string>
+    <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="HOST">%1$s</xliff:g> இணைப்புகளை <xliff:g id="APPLICATION">%2$s</xliff:g> ஆப்ஸில் திறத்தல்"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"அணுகலை வழங்கு"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"இதன் மூலம் திருத்து"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s மூலம் திருத்து"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"உலாவியைத் துவக்கவா?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"அழைப்பை ஏற்கவா?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"எப்போதும்"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"எப்போதும் திறக்குமாறு அமைத்தல்"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"இப்போது மட்டும்"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"அமைப்புகள்"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s பணிக் கணக்கை ஆதரிக்காது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 3ba794a..649e17c 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"ఫోన్‌ను ఎడమవైపునకు జరపండి."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"ఫోన్‌ను కుడివైపునకు జరపండి."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"దయచేసి మీ పరికరం వైపు మరింత నేరుగా చూడండి."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"మీ ముఖం కనిపించడం లేదు. ఫోన్ వైపు చూడండి."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"మీ ముఖాన్ని ఫోన్‌కు ఎదురుగా ఉంచండి."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"బాగా కదుపుతున్నారు. ఫోన్‌ను స్థిరంగా పట్టుకోండి"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"దయచేసి మీ ముఖాన్ని మళ్లీ నమోదు చేయండి."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"ఇక ముఖం గుర్తించలేదు. మళ్లీ ప్రయత్నించండి."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"దీనితో తెరువు"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sతో తెరువు"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"తెరువు"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"దీనితో <xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను తెరవండి"</string>
+    <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="HOST">%1$s</xliff:g> లింక్‌లను <xliff:g id="APPLICATION">%2$s</xliff:g>తో తెరవండి"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"యాక్సెస్ ఇవ్వండి"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"దీనితో సవరించు"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sతో సవరించు"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"బ్రౌజర్‌ను ప్రారంభించాలా?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"కాల్‌ను ఆమోదించాలా?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ఎల్లప్పుడూ"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"ఎల్లప్పుడూ తెరవడానికి సెట్ చేయి"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ఒకసారి మాత్రమే"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"సెట్టింగ్‌లు"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s కార్యాలయ ప్రొఫైల్‌కు మద్దతు ఇవ్వదు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 437d89e..4e69430 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"เลื่อนโทรศัพท์ไปทางซ้าย"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"เลื่อนโทรศัพท์ไปทางขวา"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"โปรดมองตรงมาที่อุปกรณ์"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"ไม่เห็นหน้าเลย ลองมองที่โทรศัพท์"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"หันหน้าให้ตรงกับโทรศัพท์"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"มีการเคลื่อนไหวมากเกินไป ถือโทรศัพท์นิ่งๆ"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"โปรดลงทะเบียนใบหน้าอีกครั้ง"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"จำใบหน้าไม่ได้แล้ว ลองอีกครั้ง"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"เปิดด้วย"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"เปิดด้วย %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"เปิด"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"เปิดลิงก์ <xliff:g id="HOST">%1$s</xliff:g> ด้วย"</string>
+    <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="HOST">%1$s</xliff:g> ด้วย <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ให้สิทธิ์"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"แก้ไขด้วย"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"แก้ไขด้วย %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"เปิดเบราว์เซอร์หรือไม่"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"รับสายหรือไม่"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ทุกครั้ง"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"ตั้งค่าให้เปิดทุกครั้ง"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"เฉพาะครั้งนี้"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"การตั้งค่า"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ไม่สนับสนุนโปรไฟล์งาน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 8469e7b..6843528 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Igalaw ang telepono pakaliwa."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Igalaw ang telepono pakanan."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Tumingin nang mas direkta sa iyong device."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Hindi makita ang mukha mo. Tumingin sa telepono."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Itapat ang mukha mo sa mismong harap ng telepono."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Masyadong magalaw. Hawakang mabuti ang telepono."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Paki-enroll muli ang iyong mukha."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Hindi na makilala ang mukha. Subukang muli."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Buksan gamit ang"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buksan gamit ang %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buksan"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> gamit ang"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Buksan ang mga link gamit ang"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Buksan ang mga link gamit ang <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> gamit ang <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Bigyan ng access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"I-edit gamit ang"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"I-edit gamit ang %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Ilunsad ang Browser?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Tanggapin ang tawag?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Palagi"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Itakda sa palaging buksan"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Isang beses lang"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mga Setting"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Hindi sinusuportahan ng %1$s ang profile sa trabaho"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8a28a0d..3592df9 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Telefonu sola hareket ettirin."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Telefonu sağa hareket ettirin."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Lütfen cihazınıza daha doğrudan bakın."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Yüzünüz görülmüyor. Telefona bakın."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Yüzünüz telefonun tam karşısına gelmelidir."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Çok fazla hareket ediyorsunuz. Telefonu sabit tutun."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Lütfen yüzünüzü yeniden kaydedin."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Yüz artık tanınamıyor. Tekrar deneyin."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Şununla aç:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ile aç"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Aç"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> bağlantılarını şununla aç:"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Bağlantıları şununla aç:"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Bağlantıları <xliff:g id="APPLICATION">%1$s</xliff:g> ile aç"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> bağlantılarını <xliff:g id="APPLICATION">%2$s</xliff:g> ile aç"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Erişim ver"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Şununla düzenle:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ile düzenle"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Tarayıcı Başlatılsın mı?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Çağrı kabul edilsin mi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Her zaman"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Her zaman açılmak üzere ayarla"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Yalnızca bir defa"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, iş profilini desteklemiyor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b02208f..347c81f 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -574,7 +574,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Тримайте телефон лівіше."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Тримайте телефон правіше."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Дивіться просто на пристрій."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Обличчя не видно. Дивіться на телефон."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Тримайте телефон просто перед обличчям."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Забагато рухів. Тримайте телефон нерухомо."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Повторно проскануйте обличчя."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Розпізнати обличчя вже не вдається. Повторіть спробу."</string>
@@ -1171,14 +1171,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Відкрити за допомогою"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Відкрити за допомогою %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Відкрити"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Відкривати посилання <xliff:g id="HOST">%1$s</xliff:g> за допомогою"</string>
+    <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="HOST">%1$s</xliff:g> за допомогою додатка <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволити"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редагувати за допомогою"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редагувати за допомогою %1$s"</string>
@@ -1636,8 +1632,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Запустити веб-переглядач?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прийняти виклик?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Завжди"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Вибрати додаток для відкривання посилань"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Лише цього разу"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налаштування"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не підтримує робочий профіль"</string>
@@ -2076,7 +2071,7 @@
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"показ поверх інших додатків на екрані"</string>
     <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Сповіщення про послідовнсть дій"</string>
     <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Акумулятор може розрядитися раніше ніж зазвичай"</string>
-    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Режим економії заряду акумулятора активовано для збільшення часу його роботи"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Режим енергозбереження активовано для збільшення часу роботи акумулятора"</string>
     <string name="battery_saver_notification_channel_name" msgid="2083316159716201806">"Режим енергозбереження"</string>
     <string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"Режим енергозбереження не ввімкнеться, доки рівень заряду знову не знизиться"</string>
     <string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"Акумулятор заряджено достатньо. Режим енергозбереження буде знову ввімкнено, коли рівень заряду знизиться."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 5adf84e..3fd6fe7 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"فون کو بائیں جانب لے جائيں۔"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"فون کو دائیں جانب لے جائیں۔"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"براہ کرم اپنے آلہ کی طرف چہرے کو سیدھا رکھیں۔"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"آپ کا چہرہ دکھائی نہیں دے رہا۔ فون کی طرف دیکھیں۔"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"اپنے چہرے کو براہ راست فون کے سامنے رکھیں۔"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"کافی حرکت ہو رہی ہے۔ فون کو مضبوطی سے پکڑیں۔"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"براہ کرم اپنے چہرے کو دوبارہ مندرج کریں۔"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"اب چہرے کی شناخت نہیں کر سکتے۔ پھر آزمائيں۔"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"اس کے ساتھ کھولیں"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏%1$s کے ساتھ کھولیں"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"کھولیں"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> لنکس کے ساتھ کھولیں"</string>
+    <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="HOST">%1$s</xliff:g> لنکس کو <xliff:g id="APPLICATION">%2$s</xliff:g> کے ذریعے کھولیں"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"رسائی دیں"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"اس کے ساتھ ترمیم کریں"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏%1$s کے ساتھ ترمیم کریں"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"براؤزر شروع کریں؟"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"کال قبول کریں؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ہمیشہ"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"ہمیشہ کھلا ہوا ہونے پر سیٹ کریں"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"بس ایک مرتبہ"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ترتیبات"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s دفتری پروفائل کا تعاون نہیں کرتا ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 1452573..85ebe00 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Telefonni chapga suring."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Telefonni oʻngga suring."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Qurilmaga tik qarang."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Yuzingiz koʻrinmayapti. Telefonga qarang."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Telefoningizga yuzingizni tik tuting."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Ortiqcha harakatlanmoqda. Qimirlatmasdan ushlang."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Yuzingizni qaytadan qayd qildiring."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Yuz tanilmadi. Qaytadan urining."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ochish…"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s bilan ochish"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ochish"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini quyidagi orqali ochish"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Havolalarni quyidagi orqali ochish"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Havolalarni <xliff:g id="APPLICATION">%1$s</xliff:g> orqali ochish"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini <xliff:g id="APPLICATION">%2$s</xliff:g> orqali ochish"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ruxsat berish"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Tahrirlash…"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"“%1$s” yordamida tahrirlash"</string>
@@ -1591,8 +1587,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Brauzer ishga tushirilsinmi?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Qo‘ng‘iroqni qabul qilasizmi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Har doim"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Doim ochish"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Faqat hozir"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Sozlamalar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"“%1$s” ishchi profilni qo‘llab-quvvatlamaydi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index b27e389..78c4290 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -521,7 +521,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Cho phép ứng dụng này sửa đổi bộ sưu tập ảnh của bạn."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"đọc vị trí từ bộ sưu tập phương tiện"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Cho phép ứng dụng này đọc vị trí từ bộ sưu tập phương tiện của bạn."</string>
-    <string name="biometric_dialog_default_title" msgid="881952973720613213">"Hãy xác minh đó là bạn"</string>
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"Xác minh danh tính của bạn"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Không có phần cứng sinh trắc học"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Đã hủy xác thực"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Không nhận dạng được"</string>
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Đưa điện thoại sang bên trái."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Đưa điện thoại sang bên phải."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Vui lòng nhìn thẳng vào thiết bị."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Hệ thống không phát hiện được khuôn mặt bạn. Hãy nhìn vào điện thoại."</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Hướng thẳng khuôn mặt về phía trước điện thoại."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Thiết bị di chuyển quá nhiều. Giữ yên thiết bị."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Vui lòng đăng ký lại khuôn mặt của bạn."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Không nhận ra khuôn mặt. Hãy thử lại."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Mở bằng"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mở bằng %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Mở"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Mở đường dẫn liên kết bằng"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Mở đường dẫn liên kết bằng <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Cấp quyền truy cập"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Chỉnh sửa bằng"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Chỉnh sửa bằng %1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Chạy trình duyệt?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn chọn"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Đặt thành luôn mở"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Chỉ một lần"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cài đặt"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s không hỗ trợ hồ sơ công việc"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 162b880..1012337 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"请将手机向左移动。"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"请将手机向右移动。"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"请直视您的设备。"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"看不到您的脸部,请直视手机。"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"请将你的面部正对手机。"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"摄像头过于晃动。请将手机拿稳。"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"请重新注册您的面孔。"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"已无法识别人脸,请重试。"</string>
@@ -661,8 +661,8 @@
     <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定平板电脑或清空此用户的所有数据。"</string>
     <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定电视或清空此用户的所有数据。"</string>
     <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定手机或清空此用户的所有数据。"</string>
-    <string name="policylab_resetPassword" msgid="4934707632423915395">"更改锁屏密码"</string>
-    <string name="policydesc_resetPassword" msgid="1278323891710619128">"更改锁屏密码。"</string>
+    <string name="policylab_resetPassword" msgid="4934707632423915395">"更改锁屏方式"</string>
+    <string name="policydesc_resetPassword" msgid="1278323891710619128">"更改锁屏方式。"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"锁定屏幕"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"控制屏幕锁定的方式和时间。"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"清除所有数据"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"打开方式"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用%1$s打开"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"打开"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> 链接打开方式"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"编辑方式"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用%1$s编辑"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"要启动浏览器吗?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"要接听电话吗?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"始终"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"设置为始终打开"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"仅此一次"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"设置"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s不支持工作资料"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index f4ec4d0..884772e 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -551,11 +551,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>
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"請將手機向左移。"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"請將手機向右移。"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"請以更直視的角度看著裝置。"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"看不到您的臉。請看著手機。"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"將手機對準您的臉孔正面。"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"裝置不夠穩定。請拿穩手機。"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"請重新註冊臉孔。"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"無法再識別臉孔。請再試一次。"</string>
@@ -581,15 +581,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 +818,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 +888,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>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"選擇開啟方式"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用 %1$s 開啟"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結的方式"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"使用以下選擇器編輯:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"要啟動「瀏覽器」嗎?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"設為一律開啟"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"只此一次"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援公司檔案"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 547736a..580a1dc 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"請將手機向左移動。"</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"請將手機向右移動。"</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"請儘可能直視裝置正面。"</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"無法偵測你的臉孔,請直視手機。"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"將你的臉孔正對手機。"</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"鏡頭過度晃動,請拿穩手機。"</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"請重新註冊你的臉孔。"</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"已無法辨識臉孔,請再試一次。"</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"選擇開啟工具"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"透過 %1$s 開啟"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結時使用的瀏覽器/應用程式"</string>
+    <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="whichEditApplication" msgid="144727838241402655">"選擇編輯工具"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"啟動「瀏覽器」嗎?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"設為一律開啟"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"僅限一次"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援工作設定檔"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index fa8eff3..c4f8823 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -568,7 +568,7 @@
     <string name="face_acquired_too_right" msgid="3667075962661863218">"Hambisa ifoni ngakwesokunxele."</string>
     <string name="face_acquired_too_left" msgid="3148242963894703424">"Hambisa ifoni ngakwesokudla."</string>
     <string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Sicela ubheke ngokuqondile kakhulu kudivayisi yakho."</string>
-    <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ayikwazi ukubona ubuso bakho. Bheka ifoni"</string>
+    <string name="face_acquired_not_detected" msgid="1879714205006680222">"Beka ubuso bakho ngqo phambi kwefoni."</string>
     <string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Ukunyakaza okuningi kakhulu. Bamba ifoni iqine."</string>
     <string name="face_acquired_recalibrate" msgid="8077949502893707539">"Sicela uphinde ubhalise ubuso bakho."</string>
     <string name="face_acquired_too_different" msgid="7663983770123789694">"Ayisakwazi ukubona ubuso. Zama futhi."</string>
@@ -1131,14 +1131,10 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Vula nge-"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Vula nge-%1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Kuvuliwe"</string>
-    <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
-    <skip />
-    <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
-    <skip />
-    <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
-    <skip />
+    <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Vula izixhumanisi ze-<xliff:g id="HOST">%1$s</xliff:g> nge"</string>
+    <string name="whichOpenLinksWith" msgid="6392123355599572804">"Vula izixhumanisi nge"</string>
+    <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Vula izixhumanisi nge-<xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+    <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Vula izixhumanisi ze-<xliff:g id="HOST">%1$s</xliff:g> nge-<xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
     <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Nikeza ukufinyel"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Hlela nge-"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Hlela nge-%1$s"</string>
@@ -1590,8 +1586,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Qala Isiphequluli?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Amukela ucingo?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Njalo"</string>
-    <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
-    <skip />
+    <string name="activity_resolver_set_always" msgid="1422574191056490585">"Setha ukuthi kuhlale kuvuliwe"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Kanye nje"</string>
     <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Izilungiselelo"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ayisekeli iphrofayela yomsebenzi"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 77fca8f..3ea8a77 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1315,7 +1315,11 @@
          it will yield the baseIntent to any activity that it launches in the same task. This
          continues until an activity is encountered which has this attribute set to false. False
          is the default. This attribute set to true also permits activity's use of the
-         TaskDescription to change labels, colors and icons in the recent task list. -->
+         TaskDescription to change labels, colors and icons in the recent task list.
+
+         <p>NOTE: Setting this flag to <code>true</code> will not change the affinity of the task,
+         which is used for intent resolution during activity launch. The task's root activity will
+         always define its affinity. -->
     <attr name="relinquishTaskIdentity" format="boolean" />
 
     <!-- Indicate that it is okay for this activity be resumed while the previous
@@ -1739,6 +1743,13 @@
                  - {@code true} for apps with targetSdkVersion < 29.
              -->
         <attr name="requestLegacyExternalStorage" format="boolean" />
+
+        <!-- If {@code true} this app declares that it should be visible to all other apps on
+             device, regardless of what they declare via the {@code queries} tags in their
+             manifest.
+
+             The default value is {@code false}. -->
+        <attr name="forceQueryable" format="boolean" />
     </declare-styleable>
     <!-- The <code>permission</code> tag declares a security permission that can be
          used to control access from other packages to specific components or
@@ -1973,6 +1984,12 @@
         <attr name="name" />
     </declare-styleable>
 
+    <declare-styleable name="AndroidManifestQueries" parent="AndroidManifest" />
+    <declare-styleable name="AndroidManifestQueriesPackage" parent="AndroidManifestQueries">
+        <attr name="name" />
+    </declare-styleable>
+    <declare-styleable name="AndroidManifestQueriesIntent" parent="AndroidManifestQueries" />
+
 
     <!-- The <code>static-library</code> tag declares that this apk is providing itself
        as a static shared library for other applications to use. Any app can declare such
@@ -2473,6 +2490,7 @@
             <!-- High dynamic range color mode. -->
             <enum name="hdr" value="2" />
         </attr>
+        <attr name="forceQueryable" format="boolean" />
     </declare-styleable>
 
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bc7e3b7..dce4bf3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1115,6 +1115,22 @@
          regularly selected color mode will be used if this value is negative. -->
     <integer name="config_accessibilityColorMode">-1</integer>
 
+    <!-- The following two arrays specify which color space to use for display composition when a
+         certain color mode is active.
+         Composition color spaces are defined in android.view.Display.COLOR_MODE_xxx, and color
+         modes are defined in ColorDisplayManager.COLOR_MODE_xxx and
+         ColorDisplayManager.VENDOR_COLOR_MODE_xxx.
+         The color space COLOR_MODE_DEFAULT (0) lets the system select the most appropriate
+         composition color space for currently displayed content. Other values (e.g.,
+         COLOR_MODE_SRGB) override system selection; these other color spaces must be supported by
+         the device for for display composition.
+         If a color mode does not have a corresponding color space specified in this array, the
+         currently set composition color space will not be modified.-->
+    <integer-array name="config_displayCompositionColorModes">
+    </integer-array>
+    <integer-array name="config_displayCompositionColorSpaces">
+    </integer-array>
+
     <!-- Indicate whether to allow the device to suspend when the screen is off
          due to the proximity sensor.  This resource should only be set to true
          if the sensor HAL correctly handles the proximity sensor as a wake-up source.
@@ -1684,6 +1700,12 @@
         <!-- Add packages here -->
     </string-array>
 
+    <string-array name="config_forceQueryablePackages" translatable="false">
+        <item>com.android.settings</item>
+        <!-- Add packages here -->
+    </string-array>
+
+
     <!-- Component name of the default wallpaper. This will be ImageWallpaper if not
          specified -->
     <string name="default_wallpaper_component" translatable="false">@null</string>
@@ -4133,8 +4155,27 @@
          for higher refresh rates to be automatically used out of the box -->
     <integer name="config_defaultPeakRefreshRate">60</integer>
 
-    <!-- The default brightness threshold that allows to switch to higher refresh rate -->
-    <integer name="config_brightnessThresholdOfPeakRefreshRate">-1</integer>
+    <!-- The display uses different gamma curves for different refresh rates. It's hard for panel
+         vendor to tune the curves to have exact same brightness for different refresh rate. So
+         flicker could be observed at switch time. The issue is worse at the gamma lower end.
+         In addition, human eyes are more sensitive to the flicker at darker environment.
+         To prevent flicker, we only support higher refresh rates if the display brightness is above
+         a threshold. And the darker environment could have higher threshold.
+         For example, no higher refresh rate if
+             display brightness <= disp0 && ambient brightness <= amb0
+             || display brightness <= disp1 && ambient brightness <= amb1 -->
+    <integer-array translatable="false" name="config_brightnessThresholdsOfPeakRefreshRate">
+         <!--
+           <item>disp0</item>
+           <item>disp1</item>
+        -->
+    </integer-array>
+    <integer-array translatable="false" name="config_ambientThresholdsOfPeakRefreshRate">
+         <!--
+           <item>amb0</item>
+           <item>amb1</item>
+        -->
+    </integer-array>
 
     <!-- The type of the light sensor to be used by the display framework for things like
          auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 5363ef9..6653879 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -90,6 +90,24 @@
         orientation. If zero, the value of rounded_corner_radius is used. -->
     <dimen name="rounded_corner_radius_bottom">0dp</dimen>
 
+    <!-- Default adjustment for the software rounded corners since corners are not perfectly
+        round. This value is used when retrieving the "radius" of the rounded corner in cases
+        where the exact bezier curve cannot be retrieved.  This value will be subtracted from
+        rounded_corner_radius to more accurately provide a "radius" for the rounded corner. -->
+    <dimen name="rounded_corner_radius_adjustment">0px</dimen>
+    <!-- Top adjustment for the software rounded corners since corners are not perfectly
+        round.  This value is used when retrieving the "radius" of the top rounded corner in cases
+        where the exact bezier curve cannot be retrieved.  This value will be subtracted from
+        rounded_corner_radius_top to more accurately provide a "radius" for the top rounded corners.
+         -->
+    <dimen name="rounded_corner_radius_top_adjustment">0px</dimen>
+    <!-- Bottom adjustment for the software rounded corners since corners are not perfectly
+        round.  This value is used when retrieving the "radius" of the bottom rounded corner in
+        cases where the exact bezier curve cannot be retrieved.  This value will be subtracted from
+        rounded_corner_radius_bottom to more accurately provide a "radius" for the bottom rounded
+        corners. -->
+    <dimen name="rounded_corner_radius_bottom_adjustment">0px</dimen>
+
     <!-- Width of the window of the divider bar used to resize docked stacks. -->
     <dimen name="docked_stack_divider_thickness">48dp</dimen>
 
@@ -261,7 +279,7 @@
     <dimen name="notification_expand_button_padding_top">1dp</dimen>
 
     <!-- Height of a small notification in the status bar -->
-    <dimen name="notification_min_height">92dp</dimen>
+    <dimen name="notification_min_height">106dp</dimen>
 
     <!-- The width of the big icons in notifications. -->
     <dimen name="notification_large_icon_width">64dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 498e60e..123deeb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -786,6 +786,7 @@
   <java-symbol type="string" name="widget_default_class_name" />
   <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="string" name="eventTypeAnniversary" />
   <java-symbol type="string" name="eventTypeBirthday" />
   <java-symbol type="string" name="eventTypeCustom" />
@@ -3196,6 +3197,8 @@
   <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
   <java-symbol type="array" name="config_availableColorModes" />
   <java-symbol type="integer" name="config_accessibilityColorMode" />
+  <java-symbol type="array" name="config_displayCompositionColorModes" />
+  <java-symbol type="array" name="config_displayCompositionColorSpaces" />
   <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
   <java-symbol type="bool" name="config_displayWhiteBalanceEnabledDefault" />
   <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" />
@@ -3708,6 +3711,9 @@
   <java-symbol type="dimen" name="rounded_corner_radius" />
   <java-symbol type="dimen" name="rounded_corner_radius_top" />
   <java-symbol type="dimen" name="rounded_corner_radius_bottom" />
+  <java-symbol type="dimen" name="rounded_corner_radius_adjustment" />
+  <java-symbol type="dimen" name="rounded_corner_radius_top_adjustment" />
+  <java-symbol type="dimen" name="rounded_corner_radius_bottom_adjustment" />
   <java-symbol type="bool" name="config_supportsRoundedCornersOnWindows" />
 
   <java-symbol type="string" name="config_defaultModuleMetadataProvider" />
@@ -3790,12 +3796,14 @@
 
   <!-- For high refresh rate displays -->
   <java-symbol type="integer" name="config_defaultPeakRefreshRate" />
-  <java-symbol type="integer" name="config_brightnessThresholdOfPeakRefreshRate" />
+  <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
+  <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
 
   <!-- For Auto-Brightness -->
   <java-symbol type="string" name="config_displayLightSensorType" />
 
   <java-symbol type="drawable" name="iconfactory_adaptive_icon_drawable_wrapper"/>
+  <java-symbol type="dimen" name="notification_min_height" />
   <java-symbol type="dimen" name="resolver_icon_size"/>
   <java-symbol type="dimen" name="resolver_badge_size"/>
   <java-symbol type="dimen" name="resolver_button_bar_spacing"/>
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
index b2254c5..eadf226 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java
@@ -17,12 +17,10 @@
 
 import static org.junit.Assert.*;
 
-import android.hardware.broadcastradio.V2_0.ProgramInfo;
 import android.hardware.broadcastradio.V2_0.ProgramListChunk;
 import android.hardware.radio.ProgramList;
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
-import android.hardware.radio.RadioMetadata;
 import android.test.suitebuilder.annotation.MediumTest;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -30,7 +28,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -45,55 +42,58 @@
 
     private final ProgramSelector.Identifier mAmFmIdentifier =
             new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, 88500);
-    private final RadioManager.ProgramInfo mAmFmInfo = makeProgramInfo(
+    private final RadioManager.ProgramInfo mAmFmInfo = TestUtils.makeProgramInfo(
             ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
 
     private final ProgramSelector.Identifier mRdsIdentifier =
             new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI, 15019);
-    private final RadioManager.ProgramInfo mRdsInfo = makeProgramInfo(
+    private final RadioManager.ProgramInfo mRdsInfo = TestUtils.makeProgramInfo(
             ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 0);
 
     private final ProgramSelector.Identifier mDabEnsembleIdentifier =
             new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, 1337);
-    private final RadioManager.ProgramInfo mDabEnsembleInfo = makeProgramInfo(
+    private final RadioManager.ProgramInfo mDabEnsembleInfo = TestUtils.makeProgramInfo(
             ProgramSelector.PROGRAM_TYPE_DAB, mDabEnsembleIdentifier, 0);
 
     private final ProgramSelector.Identifier mVendorCustomIdentifier =
             new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, 9001);
-    private final RadioManager.ProgramInfo mVendorCustomInfo = makeProgramInfo(
+    private final RadioManager.ProgramInfo mVendorCustomInfo = TestUtils.makeProgramInfo(
             ProgramSelector.PROGRAM_TYPE_VENDOR_START, mVendorCustomIdentifier, 0);
 
     // HAL-side ProgramInfoCache containing all of the above ProgramInfos.
-    private final ProgramInfoCache mAllProgramInfos = new ProgramInfoCache(null, mAmFmInfo,
+    private final ProgramInfoCache mAllProgramInfos = new ProgramInfoCache(null, true, mAmFmInfo,
             mRdsInfo, mDabEnsembleInfo, mVendorCustomInfo);
 
     @Test
     public void testUpdateFromHal() {
-        // First test a purging chunk.
-        ProgramInfoCache cache = new ProgramInfoCache(null, mAmFmInfo);
+        // First test updating an incomplete cache with a purging, complete chunk.
+        ProgramInfoCache cache = new ProgramInfoCache(null, false, mAmFmInfo);
         ProgramListChunk chunk = new ProgramListChunk();
         chunk.purge = true;
-        chunk.modified.add(programInfoToHal(mRdsInfo));
-        chunk.modified.add(programInfoToHal(mDabEnsembleInfo));
-        cache.updateFromHalProgramListChunk(chunk);
         chunk.complete = true;
+        chunk.modified.add(TestUtils.programInfoToHal(mRdsInfo));
+        chunk.modified.add(TestUtils.programInfoToHal(mDabEnsembleInfo));
+        cache.updateFromHalProgramListChunk(chunk);
         assertTrue(cache.programInfosAreExactly(mRdsInfo, mDabEnsembleInfo));
+        assertTrue(cache.isComplete());
 
-        // Then test a non-purging chunk.
+        // Then test a non-purging, incomplete chunk.
         chunk.purge = false;
+        chunk.complete = false;
         chunk.modified.clear();
-        RadioManager.ProgramInfo updatedRdsInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_FM,
-                mRdsIdentifier, 1);
-        chunk.modified.add(programInfoToHal(updatedRdsInfo));
-        chunk.modified.add(programInfoToHal(mVendorCustomInfo));
+        RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(
+                ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 1);
+        chunk.modified.add(TestUtils.programInfoToHal(updatedRdsInfo));
+        chunk.modified.add(TestUtils.programInfoToHal(mVendorCustomInfo));
         chunk.removed.add(Convert.programIdentifierToHal(mDabEnsembleIdentifier));
         cache.updateFromHalProgramListChunk(chunk);
         assertTrue(cache.programInfosAreExactly(updatedRdsInfo, mVendorCustomInfo));
+        assertFalse(cache.isComplete());
     }
 
     @Test
     public void testNullFilter() {
-        ProgramInfoCache cache = new ProgramInfoCache(null);
+        ProgramInfoCache cache = new ProgramInfoCache(null, true);
         cache.filterAndUpdateFrom(mAllProgramInfos, false);
         assertTrue(cache.programInfosAreExactly(mAmFmInfo, mRdsInfo, mDabEnsembleInfo,
                   mVendorCustomInfo));
@@ -140,11 +140,11 @@
 
     @Test
     public void testPurgeUpdateChunks() {
-        ProgramInfoCache cache = new ProgramInfoCache(null, mAmFmInfo);
+        ProgramInfoCache cache = new ProgramInfoCache(null, false, mAmFmInfo);
         List<ProgramList.Chunk> chunks =
                 cache.filterAndUpdateFromInternal(mAllProgramInfos, true, 3, 3);
         assertEquals(2, chunks.size());
-        verifyChunkListFlags(chunks, true);
+        verifyChunkListFlags(chunks, true, true);
         verifyChunkListModified(chunks, 3, mAmFmInfo, mRdsInfo, mDabEnsembleInfo,
                 mVendorCustomInfo);
         verifyChunkListRemoved(chunks, 0);
@@ -154,23 +154,26 @@
     public void testDeltaUpdateChunksModificationsIncluded() {
         // Create a cache with a filter that allows modifications, and set its contents to
         // mAmFmInfo, mRdsInfo, mDabEnsembleInfo, and mVendorCustomInfo.
-        ProgramInfoCache cache = new ProgramInfoCache(null, mAmFmInfo, mRdsInfo, mDabEnsembleInfo,
-                mVendorCustomInfo);
+        ProgramInfoCache cache = new ProgramInfoCache(null, true, mAmFmInfo, mRdsInfo,
+                mDabEnsembleInfo, mVendorCustomInfo);
 
         // Create a HAL cache that:
+        // - Is complete.
         // - Retains mAmFmInfo.
         // - Replaces mRdsInfo with updatedRdsInfo.
         // - Drops mDabEnsembleInfo and mVendorCustomInfo.
         // - Introduces a new SXM info.
-        RadioManager.ProgramInfo updatedRdsInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_FM,
-                mRdsIdentifier, 1);
-        RadioManager.ProgramInfo newSxmInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_SXM,
+        RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(
+                ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 1);
+        RadioManager.ProgramInfo newSxmInfo = TestUtils.makeProgramInfo(
+                ProgramSelector.PROGRAM_TYPE_SXM,
                 new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL, 12345),
                 0);
-        ProgramInfoCache halCache = new ProgramInfoCache(null, mAmFmInfo, updatedRdsInfo,
+        ProgramInfoCache halCache = new ProgramInfoCache(null, true, mAmFmInfo, updatedRdsInfo,
                 newSxmInfo);
 
         // Update the cache and verify:
+        // - The final chunk's complete flag is set.
         // - mAmFmInfo is retained and not reported in the chunks.
         // - updatedRdsInfo should appear as an update to mRdsInfo.
         // - newSxmInfo should appear as a new entry.
@@ -178,7 +181,7 @@
         List<ProgramList.Chunk> chunks = cache.filterAndUpdateFromInternal(halCache, false, 5, 1);
         assertTrue(cache.programInfosAreExactly(mAmFmInfo, updatedRdsInfo, newSxmInfo));
         assertEquals(2, chunks.size());
-        verifyChunkListFlags(chunks, false);
+        verifyChunkListFlags(chunks, false, true);
         verifyChunkListModified(chunks, 5, updatedRdsInfo, newSxmInfo);
         verifyChunkListRemoved(chunks, 1, mDabEnsembleIdentifier, mVendorCustomIdentifier);
     }
@@ -188,63 +191,50 @@
         // Create a cache with a filter that excludes modifications, and set its contents to
         // mAmFmInfo, mRdsInfo, mDabEnsembleInfo, and mVendorCustomInfo.
         ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new HashSet<Integer>(),
-                new HashSet<ProgramSelector.Identifier>(), true, true), mAmFmInfo, mRdsInfo,
+                new HashSet<ProgramSelector.Identifier>(), true, true), true, mAmFmInfo, mRdsInfo,
                 mDabEnsembleInfo, mVendorCustomInfo);
 
         // Create a HAL cache that:
+        // - Is incomplete.
         // - Retains mAmFmInfo.
         // - Replaces mRdsInfo with updatedRdsInfo.
         // - Drops mDabEnsembleInfo and mVendorCustomInfo.
         // - Introduces a new SXM info.
-        RadioManager.ProgramInfo updatedRdsInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_FM,
-                mRdsIdentifier, 1);
-        RadioManager.ProgramInfo newSxmInfo = makeProgramInfo(ProgramSelector.PROGRAM_TYPE_SXM,
+        RadioManager.ProgramInfo updatedRdsInfo = TestUtils.makeProgramInfo(
+                ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 1);
+        RadioManager.ProgramInfo newSxmInfo = TestUtils.makeProgramInfo(
+                ProgramSelector.PROGRAM_TYPE_SXM,
                 new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL, 12345),
                 0);
-        ProgramInfoCache halCache = new ProgramInfoCache(null, mAmFmInfo, updatedRdsInfo,
+        ProgramInfoCache halCache = new ProgramInfoCache(null, false, mAmFmInfo, updatedRdsInfo,
                 newSxmInfo);
 
         // Update the cache and verify:
+        // - All complete flags are false.
         // - mAmFmInfo and mRdsInfo are retained and not reported in the chunks.
         // - newSxmInfo should appear as a new entry.
         // - mDabEnsembleInfo and mVendorCustomInfo should be reported as removed.
         List<ProgramList.Chunk> chunks = cache.filterAndUpdateFromInternal(halCache, false, 5, 1);
         assertTrue(cache.programInfosAreExactly(mAmFmInfo, mRdsInfo, newSxmInfo));
         assertEquals(2, chunks.size());
-        verifyChunkListFlags(chunks, false);
+        verifyChunkListFlags(chunks, false, false);
         verifyChunkListModified(chunks, 5, newSxmInfo);
         verifyChunkListRemoved(chunks, 1, mDabEnsembleIdentifier, mVendorCustomIdentifier);
     }
 
-    private static RadioManager.ProgramInfo makeProgramInfo(int programType,
-            ProgramSelector.Identifier identifier, int signalQuality) {
-        // Note: If you set new fields, check if programInfoToHal() needs to be updated as well.
-        return new RadioManager.ProgramInfo(new ProgramSelector(programType, identifier, null,
-                null), null, null, null, 0, signalQuality, new RadioMetadata.Builder().build(),
-                new HashMap<String, String>());
-    }
-
-    private static ProgramInfo programInfoToHal(RadioManager.ProgramInfo info) {
-        // Note that because Convert does not by design provide functions for all conversions, this
-        // function only copies fields that are set by makeProgramInfo().
-        ProgramInfo hwInfo = new ProgramInfo();
-        hwInfo.selector = Convert.programSelectorToHal(info.getSelector());
-        hwInfo.signalQuality = info.getSignalStrength();
-        return hwInfo;
-    }
-
     // Verifies that:
     // - The first chunk's purge flag matches expectPurge.
-    // - The last chunk's complete flag is set.
+    // - The last chunk's complete flag matches expectComplete.
     // - All other flags are false.
-    private static void verifyChunkListFlags(List<ProgramList.Chunk> chunks, boolean expectPurge) {
+    private static void verifyChunkListFlags(List<ProgramList.Chunk> chunks, boolean expectPurge,
+            boolean expectComplete) {
         if (chunks.isEmpty()) {
             return;
         }
         for (int i = 0; i < chunks.size(); i++) {
             ProgramList.Chunk chunk = chunks.get(i);
             assertEquals(i == 0 && expectPurge, chunk.isPurge());
-            assertEquals(i == chunks.size() - 1, chunk.isComplete());
+            assertEquals(i == chunks.size() - 1 && expectComplete, chunk.isComplete());
         }
     }
 
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
new file mode 100644
index 0000000..f9e3798
--- /dev/null
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -0,0 +1,353 @@
+/*
+ * 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.broadcastradio.hal2;
+
+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;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
+import android.hardware.broadcastradio.V2_0.ITunerCallback;
+import android.hardware.broadcastradio.V2_0.ITunerSession;
+import android.hardware.broadcastradio.V2_0.ProgramFilter;
+import android.hardware.broadcastradio.V2_0.ProgramListChunk;
+import android.hardware.broadcastradio.V2_0.Result;
+import android.hardware.radio.ProgramList;
+import android.hardware.radio.ProgramSelector;
+import android.hardware.radio.RadioManager;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+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;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for v2 HAL RadioModule.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class StartProgramListUpdatesFanoutTest {
+    private static final String TAG = "BroadcastRadioTests.hal2.StartProgramListUpdatesFanout";
+
+    // Mocks
+    @Mock IBroadcastRadio mBroadcastRadioMock;
+    @Mock ITunerSession mHalTunerSessionMock;
+    private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
+
+    // RadioModule under test
+    private RadioModule mRadioModule;
+
+    // Objects created by mRadioModule
+    private ITunerCallback mHalTunerCallback;
+    private TunerSession[] mTunerSessions;
+
+    // Data objects used during tests
+    private final ProgramSelector.Identifier mAmFmIdentifier =
+            new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, 88500);
+    private final RadioManager.ProgramInfo mAmFmInfo = TestUtils.makeProgramInfo(
+            ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 0);
+    private final RadioManager.ProgramInfo mModifiedAmFmInfo = TestUtils.makeProgramInfo(
+            ProgramSelector.PROGRAM_TYPE_FM, mAmFmIdentifier, 1);
+
+    private final ProgramSelector.Identifier mRdsIdentifier =
+            new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI, 15019);
+    private final RadioManager.ProgramInfo mRdsInfo = TestUtils.makeProgramInfo(
+            ProgramSelector.PROGRAM_TYPE_FM, mRdsIdentifier, 0);
+
+    private final ProgramSelector.Identifier mDabEnsembleIdentifier =
+            new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, 1337);
+    private final RadioManager.ProgramInfo mDabEnsembleInfo = TestUtils.makeProgramInfo(
+            ProgramSelector.PROGRAM_TYPE_DAB, mDabEnsembleIdentifier, 0);
+
+    @Before
+    public void setup() throws RemoteException {
+        MockitoAnnotations.initMocks(this);
+
+        mRadioModule = new RadioModule(mBroadcastRadioMock, new RadioManager.ModuleProperties(0, "",
+                  0, "", "", "", "", 0, 0, false, false, null, false, new int[] {}, new int[] {},
+                  null, null));
+
+        doAnswer((Answer) invocation -> {
+            mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
+            IBroadcastRadio.openSessionCallback cb = (IBroadcastRadio.openSessionCallback)
+                    invocation.getArguments()[1];
+            cb.onValues(Result.OK, mHalTunerSessionMock);
+            return null;
+        }).when(mBroadcastRadioMock).openSession(any(), any());
+        when(mHalTunerSessionMock.startProgramListUpdates(any())).thenReturn(Result.OK);
+    }
+
+    @Test
+    public void testFanout() throws RemoteException {
+        // Open 3 clients that will all use the same filter, and start updates on two of them for
+        // now. The HAL TunerSession should only see 1 filter update.
+        openAidlClients(3);
+        ProgramList.Filter aidlFilter = new ProgramList.Filter(new HashSet<Integer>(),
+                new HashSet<ProgramSelector.Identifier>(), true, false);
+        ProgramFilter halFilter = Convert.programFilterToHal(aidlFilter);
+        for (int i = 0; i < 2; i++) {
+            mTunerSessions[i].startProgramListUpdates(aidlFilter);
+        }
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+        // Initiate a program list update from the HAL side and verify both connected AIDL clients
+        // receive the update.
+        updateHalProgramInfo(true, Arrays.asList(mAmFmInfo, mRdsInfo), null);
+        for (int i = 0; i < 2; i++) {
+            verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[i], true, Arrays.asList(
+                    mAmFmInfo, mRdsInfo), null);
+        }
+
+        // Repeat with a non-purging update.
+        updateHalProgramInfo(false, Arrays.asList(mModifiedAmFmInfo),
+                Arrays.asList(mRdsIdentifier));
+        for (int i = 0; i < 2; i++) {
+            verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[i], false,
+                    Arrays.asList(mModifiedAmFmInfo), Arrays.asList(mRdsIdentifier));
+        }
+
+        // Now start updates on the 3rd client. Verify the HAL function has not been called again
+        // and client receives the appropriate update.
+        mTunerSessions[2].startProgramListUpdates(aidlFilter);
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(any());
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[2], true,
+                Arrays.asList(mModifiedAmFmInfo), null);
+    }
+
+    @Test
+    public void testFiltering() throws RemoteException {
+        // Open 4 clients that will use the following filters:
+        // [0]: ID mRdsIdentifier, modifications excluded
+        // [1]: No categories, modifications excluded
+        // [2]: Type IDENTIFIER_TYPE_AMFM_FREQUENCY, modifications excluded
+        // [3]: Type IDENTIFIER_TYPE_AMFM_FREQUENCY, modifications included
+        openAidlClients(4);
+        ProgramList.Filter idFilter = new ProgramList.Filter(new HashSet<Integer>(),
+                new HashSet<ProgramSelector.Identifier>(Arrays.asList(mRdsIdentifier)), true, true);
+        ProgramList.Filter categoryFilter = new ProgramList.Filter(new HashSet<Integer>(),
+                new HashSet<ProgramSelector.Identifier>(), false, true);
+        ProgramList.Filter typeFilterWithoutModifications = new ProgramList.Filter(
+                new HashSet<Integer>(Arrays.asList(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)),
+                new HashSet<ProgramSelector.Identifier>(), true, true);
+        ProgramList.Filter typeFilterWithModifications = new ProgramList.Filter(
+                new HashSet<Integer>(Arrays.asList(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)),
+                new HashSet<ProgramSelector.Identifier>(), true, false);
+
+        // Start updates on the clients in order. The HAL filter should get updated after each
+        // client except [2].
+        mTunerSessions[0].startProgramListUpdates(idFilter);
+        ProgramFilter halFilter = Convert.programFilterToHal(idFilter);
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+        mTunerSessions[1].startProgramListUpdates(categoryFilter);
+        halFilter.identifiers.clear();
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+        mTunerSessions[2].startProgramListUpdates(typeFilterWithoutModifications);
+        verify(mHalTunerSessionMock, times(2)).startProgramListUpdates(any());
+
+        mTunerSessions[3].startProgramListUpdates(typeFilterWithModifications);
+        halFilter.excludeModifications = false;
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+        // Adding mRdsInfo should update clients [0] and [1].
+        updateHalProgramInfo(false, Arrays.asList(mRdsInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], false, Arrays.asList(mRdsInfo),
+                null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], false, Arrays.asList(mRdsInfo),
+                null);
+
+        // Adding mAmFmInfo should update clients [1], [2], and [3].
+        updateHalProgramInfo(false, Arrays.asList(mAmFmInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], false, Arrays.asList(mAmFmInfo),
+                null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[2], false, Arrays.asList(mAmFmInfo),
+                null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[3], false, Arrays.asList(mAmFmInfo),
+                null);
+
+        // Modifying mAmFmInfo to mModifiedAmFmInfo should update only [3].
+        updateHalProgramInfo(false, Arrays.asList(mModifiedAmFmInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[3], false,
+                Arrays.asList(mModifiedAmFmInfo), null);
+
+        // Adding mDabEnsembleInfo should not update any client.
+        updateHalProgramInfo(false, Arrays.asList(mDabEnsembleInfo), null);
+        verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[1], times(2)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[2], times(1)).onProgramListUpdated(any());
+        verify(mAidlTunerCallbackMocks[3], times(2)).onProgramListUpdated(any());
+    }
+
+    @Test
+    public void testClientClosing() throws RemoteException {
+        // Open 2 clients that use different filters that are both sensitive to mAmFmIdentifier.
+        openAidlClients(2);
+        ProgramList.Filter idFilter = new ProgramList.Filter(new HashSet<Integer>(),
+                new HashSet<ProgramSelector.Identifier>(Arrays.asList(mAmFmIdentifier)), true,
+                false);
+        ProgramList.Filter typeFilter = new ProgramList.Filter(
+                new HashSet<Integer>(Arrays.asList(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)),
+                new HashSet<ProgramSelector.Identifier>(), true, false);
+
+        // Start updates on the clients, and verify the HAL filter is updated after each one.
+        mTunerSessions[0].startProgramListUpdates(idFilter);
+        ProgramFilter halFilter = Convert.programFilterToHal(idFilter);
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+        mTunerSessions[1].startProgramListUpdates(typeFilter);
+        halFilter.identifiers.clear();
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(halFilter);
+
+        // Update the HAL with mAmFmInfo, and verify both clients are updated.
+        updateHalProgramInfo(true, Arrays.asList(mAmFmInfo), null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[0], true, Arrays.asList(mAmFmInfo),
+                null);
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true, Arrays.asList(mAmFmInfo),
+                null);
+
+        // Stop updates on the first client and verify the HAL filter is updated.
+        mTunerSessions[0].stopProgramListUpdates();
+        verify(mHalTunerSessionMock, times(1)).startProgramListUpdates(Convert.programFilterToHal(
+                typeFilter));
+
+        // Update the HAL with mModifiedAmFmInfo, and verify only the remaining client is updated.
+        updateHalProgramInfo(true, Arrays.asList(mModifiedAmFmInfo), null);
+        verify(mAidlTunerCallbackMocks[0], times(1)).onProgramListUpdated(any());
+        verifyAidlClientReceivedChunk(mAidlTunerCallbackMocks[1], true,
+                Arrays.asList(mModifiedAmFmInfo), null);
+
+        // Close the other client without explicitly stopping updates, and verify HAL updates are
+        // stopped as well.
+        mTunerSessions[1].close();
+        verify(mHalTunerSessionMock).stopProgramListUpdates();
+    }
+
+    private void openAidlClients(int numClients) throws RemoteException {
+        mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients];
+        mTunerSessions = new TunerSession[numClients];
+        for (int i = 0; i < numClients; i++) {
+            mAidlTunerCallbackMocks[i] = mock(android.hardware.radio.ITunerCallback.class);
+            mTunerSessions[i] = mRadioModule.openSession(mAidlTunerCallbackMocks[i]);
+        }
+    }
+
+    private void updateHalProgramInfo(boolean purge, List<RadioManager.ProgramInfo> modified,
+            List<ProgramSelector.Identifier> removed) throws RemoteException {
+        ProgramListChunk programListChunk = new ProgramListChunk();
+        programListChunk.purge = purge;
+        programListChunk.complete = true;
+        if (modified != null) {
+            for (RadioManager.ProgramInfo mod : modified) {
+                programListChunk.modified.add(TestUtils.programInfoToHal(mod));
+            }
+        }
+        if (removed != null) {
+            for (ProgramSelector.Identifier id : removed) {
+                programListChunk.removed.add(Convert.programIdentifierToHal(id));
+            }
+        }
+        mHalTunerCallback.onProgramListUpdated(programListChunk);
+    }
+
+    private void verifyAidlClientReceivedChunk(android.hardware.radio.ITunerCallback clientMock,
+            boolean purge, List<RadioManager.ProgramInfo> modified,
+            List<ProgramSelector.Identifier> removed) throws RemoteException {
+        HashSet<RadioManager.ProgramInfo> modifiedSet = new HashSet<>();
+        if (modified != null) {
+            modifiedSet.addAll(modified);
+        }
+        HashSet<ProgramSelector.Identifier> removedSet = new HashSet<>();
+        if (removed != null) {
+            removedSet.addAll(removed);
+        }
+        ProgramList.Chunk expectedChunk = new ProgramList.Chunk(purge, true, modifiedSet,
+                removedSet);
+        verify(clientMock).onProgramListUpdated(argThat(new ChunkMatcher(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/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java
new file mode 100644
index 0000000..4944803
--- /dev/null
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TestUtils.java
@@ -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.server.broadcastradio.hal2;
+
+import android.hardware.broadcastradio.V2_0.ProgramInfo;
+import android.hardware.radio.ProgramSelector;
+import android.hardware.radio.RadioManager;
+import android.hardware.radio.RadioMetadata;
+
+import java.util.HashMap;
+
+final class TestUtils {
+    static RadioManager.ProgramInfo makeProgramInfo(int programType,
+            ProgramSelector.Identifier identifier, int signalQuality) {
+        // Note: If you set new fields, check if programInfoToHal() needs to be updated as well.
+        return new RadioManager.ProgramInfo(new ProgramSelector(programType, identifier, null,
+                null), null, null, null, 0, signalQuality, new RadioMetadata.Builder().build(),
+                new HashMap<String, String>());
+    }
+
+    static ProgramInfo programInfoToHal(RadioManager.ProgramInfo info) {
+        // Note that because Convert does not by design provide functions for all conversions, this
+        // function only copies fields that are set by makeProgramInfo().
+        ProgramInfo hwInfo = new ProgramInfo();
+        hwInfo.selector = Convert.programSelectorToHal(info.getSelector());
+        hwInfo.signalQuality = info.getSignalStrength();
+        return hwInfo;
+    }
+}
diff --git a/core/tests/coretests/res/values/overlayable_icons_test.xml b/core/tests/coretests/res/values/overlayable_icons_test.xml
deleted file mode 100644
index 6503f3e..0000000
--- a/core/tests/coretests/res/values/overlayable_icons_test.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-<!--
-   Copyright (C) 2019 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
--->
-<resources>
-  <!-- overlayable_icons references all of the drawables in this package
-       that are being overlayed by resource overlays. If you remove/rename
-       any of these resources, you must also change the resource overlay icons.-->
-  <array name="overlayable_icons">
-    <item>@*android:drawable/ic_audio_alarm</item>
-    <item>@*android:drawable/ic_audio_alarm_mute</item>
-    <item>@*android:drawable/ic_battery_80_24dp</item>
-    <item>@*android:drawable/ic_bluetooth_share_icon</item>
-    <item>@*android:drawable/ic_bt_headphones_a2dp</item>
-    <item>@*android:drawable/ic_bt_headset_hfp</item>
-    <item>@*android:drawable/ic_bt_hearing_aid</item>
-    <item>@*android:drawable/ic_bt_laptop</item>
-    <item>@*android:drawable/ic_bt_misc_hid</item>
-    <item>@*android:drawable/ic_bt_network_pan</item>
-    <item>@*android:drawable/ic_bt_pointing_hid</item>
-    <item>@*android:drawable/ic_corp_badge</item>
-    <item>@*android:drawable/ic_expand_more</item>
-    <item>@*android:drawable/ic_faster_emergency</item>
-    <item>@*android:drawable/ic_file_copy</item>
-    <item>@*android:drawable/ic_lock</item>
-    <item>@*android:drawable/ic_lock_bugreport</item>
-    <item>@*android:drawable/ic_lock_open</item>
-    <item>@*android:drawable/ic_lock_power_off</item>
-    <item>@*android:drawable/ic_lockscreen_ime</item>
-    <item>@*android:drawable/ic_mode_edit</item>
-    <item>@*android:drawable/ic_notifications_alerted</item>
-    <item>@*android:drawable/ic_phone</item>
-    <item>@*android:drawable/ic_qs_airplane</item>
-    <item>@*android:drawable/ic_qs_auto_rotate</item>
-    <item>@*android:drawable/ic_qs_battery_saver</item>
-    <item>@*android:drawable/ic_qs_bluetooth</item>
-    <item>@*android:drawable/ic_qs_dnd</item>
-    <item>@*android:drawable/ic_qs_flashlight</item>
-    <item>@*android:drawable/ic_qs_night_display_on</item>
-    <item>@*android:drawable/ic_qs_ui_mode_night</item>
-    <item>@*android:drawable/ic_restart</item>
-    <item>@*android:drawable/ic_screenshot</item>
-    <item>@*android:drawable/ic_settings_bluetooth</item>
-    <item>@*android:drawable/ic_signal_cellular_0_4_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_0_5_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_1_4_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_1_5_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_2_4_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_2_5_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_3_4_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_3_5_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_4_4_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_4_5_bar</item>
-    <item>@*android:drawable/ic_signal_cellular_5_5_bar</item>
-    <item>@*android:drawable/ic_signal_location</item>
-    <item>@*android:drawable/ic_wifi_signal_0</item>
-    <item>@*android:drawable/ic_wifi_signal_1</item>
-    <item>@*android:drawable/ic_wifi_signal_2</item>
-    <item>@*android:drawable/ic_wifi_signal_3</item>
-    <item>@*android:drawable/ic_wifi_signal_4</item>
-    <item>@*android:drawable/perm_group_activity_recognition</item>
-    <item>@*android:drawable/perm_group_aural</item>
-    <item>@*android:drawable/perm_group_calendar</item>
-    <item>@*android:drawable/perm_group_call_log</item>
-    <item>@*android:drawable/perm_group_camera</item>
-    <item>@*android:drawable/perm_group_contacts</item>
-    <item>@*android:drawable/perm_group_location</item>
-    <item>@*android:drawable/perm_group_microphone</item>
-    <item>@*android:drawable/perm_group_phone_calls</item>
-    <item>@*android:drawable/perm_group_sensors</item>
-    <item>@*android:drawable/perm_group_sms</item>
-    <item>@*android:drawable/perm_group_storage</item>
-    <item>@*android:drawable/perm_group_visual</item>
-  </array>
-</resources>
diff --git a/core/tests/coretests/res/values/styles.xml b/core/tests/coretests/res/values/styles.xml
index dbc4626..0bf4b92 100644
--- a/core/tests/coretests/res/values/styles.xml
+++ b/core/tests/coretests/res/values/styles.xml
@@ -39,4 +39,7 @@
         <item name="android:colorBackground">@null</item>
         <item name="android:windowBackgroundFallback">#0000FF</item>
     </style>
+    <style name="ViewDefaultBackground">
+        <item name="android:background">#00000000</item>
+    </style>
 </resources>
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index d2b18cb..51da0c8 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -416,7 +416,8 @@
                 IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
                 boolean b2, boolean b3, Configuration configuration,
                 CompatibilityInfo compatibilityInfo, Map map, Bundle bundle1, String s1,
-                AutofillOptions ao, ContentCaptureOptions co) throws RemoteException {
+                AutofillOptions ao, ContentCaptureOptions co, long[] disableCompatChanges)
+                throws RemoteException {
         }
 
         @Override
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteTokenizerTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteTokenizerTest.java
new file mode 100644
index 0000000..a9d1482
--- /dev/null
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteTokenizerTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.database.sqlite;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class SQLiteTokenizerTest {
+    private List<String> getTokens(String sql) {
+        return SQLiteTokenizer.tokenize(sql, SQLiteTokenizer.OPTION_NONE);
+    }
+
+    private void checkTokens(String sql, String spaceSeparatedExpectedTokens) {
+        final List<String> expected = spaceSeparatedExpectedTokens == null
+                ? new ArrayList<>()
+                : Arrays.asList(spaceSeparatedExpectedTokens.split(" +"));
+
+        assertEquals(expected, getTokens(sql));
+    }
+
+    private void assertInvalidSql(String sql, String message) {
+        try {
+            getTokens(sql);
+            fail("Didn't throw InvalidSqlException");
+        } catch (IllegalArgumentException e) {
+            assertTrue("Expected " + e.getMessage() + " to contain " + message,
+                    e.getMessage().contains(message));
+        }
+    }
+
+    @Test
+    public void testWhitespaces() {
+        checkTokens("  select  \t\r\n a\n\n  ", "select a");
+        checkTokens("a b", "a b");
+    }
+
+    @Test
+    public void testComment() {
+        checkTokens("--\n", null);
+        checkTokens("a--\n", "a");
+        checkTokens("a--abcdef\n", "a");
+        checkTokens("a--abcdef\nx", "a x");
+        checkTokens("a--\nx", "a x");
+        assertInvalidSql("a--abcdef", "Unterminated comment");
+        assertInvalidSql("a--abcdef\ndef--", "Unterminated comment");
+
+        checkTokens("/**/", null);
+        assertInvalidSql("/*", "Unterminated comment");
+        assertInvalidSql("/*/", "Unterminated comment");
+        assertInvalidSql("/*\n* /*a", "Unterminated comment");
+        checkTokens("a/**/", "a");
+        checkTokens("/**/b", "b");
+        checkTokens("a/**/b", "a b");
+        checkTokens("a/* -- \n* /* **/b", "a b");
+    }
+
+    @Test
+    public void testStrings() {
+        assertInvalidSql("'", "Unterminated quote");
+        assertInvalidSql("a'", "Unterminated quote");
+        assertInvalidSql("a'''", "Unterminated quote");
+        assertInvalidSql("a''' ", "Unterminated quote");
+        checkTokens("''", null);
+        checkTokens("''''", null);
+        checkTokens("a''''b", "a b");
+        checkTokens("a' '' 'b", "a b");
+        checkTokens("'abc'", null);
+        checkTokens("'abc\ndef'", null);
+        checkTokens("a'abc\ndef'", "a");
+        checkTokens("'abc\ndef'b", "b");
+        checkTokens("a'abc\ndef'b", "a b");
+        checkTokens("a'''abc\nd''ef'''b", "a b");
+    }
+
+    @Test
+    public void testDoubleQuotes() {
+        assertInvalidSql("\"", "Unterminated quote");
+        assertInvalidSql("a\"", "Unterminated quote");
+        assertInvalidSql("a\"\"\"", "Unterminated quote");
+        assertInvalidSql("a\"\"\" ", "Unterminated quote");
+        checkTokens("\"\"", "");
+        checkTokens("\"\"\"\"", "\"");
+        checkTokens("a\"\"\"\"b", "a \" b");
+        checkTokens("a\"\t\"\"\t\"b", "a  \t\"\t  b");
+        checkTokens("\"abc\"", "abc");
+        checkTokens("\"abc\ndef\"", "abc\ndef");
+        checkTokens("a\"abc\ndef\"", "a abc\ndef");
+        checkTokens("\"abc\ndef\"b", "abc\ndef b");
+        checkTokens("a\"abc\ndef\"b", "a abc\ndef b");
+        checkTokens("a\"\"\"abc\nd\"\"ef\"\"\"b", "a \"abc\nd\"ef\" b");
+    }
+
+    @Test
+    public void testBackQuotes() {
+        assertInvalidSql("`", "Unterminated quote");
+        assertInvalidSql("a`", "Unterminated quote");
+        assertInvalidSql("a```", "Unterminated quote");
+        assertInvalidSql("a``` ", "Unterminated quote");
+        checkTokens("``", "");
+        checkTokens("````", "`");
+        checkTokens("a````b", "a ` b");
+        checkTokens("a`\t``\t`b", "a  \t`\t  b");
+        checkTokens("`abc`", "abc");
+        checkTokens("`abc\ndef`", "abc\ndef");
+        checkTokens("a`abc\ndef`", "a abc\ndef");
+        checkTokens("`abc\ndef`b", "abc\ndef b");
+        checkTokens("a`abc\ndef`b", "a abc\ndef b");
+        checkTokens("a```abc\nd``ef```b", "a `abc\nd`ef` b");
+    }
+
+    @Test
+    public void testBrackets() {
+        assertInvalidSql("[", "Unterminated quote");
+        assertInvalidSql("a[", "Unterminated quote");
+        assertInvalidSql("a[ ", "Unterminated quote");
+        assertInvalidSql("a[[ ", "Unterminated quote");
+        checkTokens("[]", "");
+        checkTokens("[[]", "[");
+        checkTokens("a[[]b", "a [ b");
+        checkTokens("a[\t[\t]b", "a  \t[\t  b");
+        checkTokens("[abc]", "abc");
+        checkTokens("[abc\ndef]", "abc\ndef");
+        checkTokens("a[abc\ndef]", "a abc\ndef");
+        checkTokens("[abc\ndef]b", "abc\ndef b");
+        checkTokens("a[abc\ndef]b", "a abc\ndef b");
+        checkTokens("a[[abc\nd[ef[]b", "a [abc\nd[ef[ b");
+    }
+
+    @Test
+    public void testSemicolons() {
+        assertInvalidSql(";", "Semicolon is not allowed");
+        assertInvalidSql("  ;", "Semicolon is not allowed");
+        assertInvalidSql(";  ", "Semicolon is not allowed");
+        assertInvalidSql("-;-", "Semicolon is not allowed");
+        checkTokens("--;\n", null);
+        checkTokens("/*;*/", null);
+        checkTokens("';'", null);
+        checkTokens("[;]", ";");
+        checkTokens("`;`", ";");
+    }
+
+    @Test
+    public void testTokens() {
+        checkTokens("a,abc,a00b,_1,_123,abcdef", "a abc a00b _1 _123 abcdef");
+        checkTokens("a--\nabc/**/a00b''_1'''ABC'''`_123`abc[d]\"e\"f",
+                "a abc a00b _1 _123 abc d e f");
+    }
+}
diff --git a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
index d5163e1..eff4826 100644
--- a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
+++ b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
@@ -64,7 +64,7 @@
     @Test
     public void testSingleByte() throws Exception {
         final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY,
-                new long[] { 10, 11 }).getFileDescriptor();
+                new long[] { 10, 11 }, new long[] {}).getFileDescriptor();
 
         final byte[] buf = new byte[1_000];
         assertEquals(buf.length, Os.read(fd, buf, 0, buf.length));
@@ -80,7 +80,7 @@
     @Test
     public void testRanges() throws Exception {
         final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY,
-                new long[] { 100, 200, 300, 400 }).getFileDescriptor();
+                new long[] { 100, 200, 300, 400 }, new long[] {}).getFileDescriptor();
 
         final byte[] buf = new byte[10];
         assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 90));
@@ -102,7 +102,7 @@
     @Test
     public void testEntireFile() throws Exception {
         final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY,
-                new long[] { 0, 5_000_000 }).getFileDescriptor();
+                new long[] { 0, 5_000_000 }, new long[] {}).getFileDescriptor();
 
         try (FileInputStream in = new FileInputStream(fd)) {
             int val;
@@ -115,7 +115,7 @@
     @Test
     public void testReadWrite() throws Exception {
         final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
-                new long[] { 100, 200, 300, 400 }).getFileDescriptor();
+                new long[] { 100, 200, 300, 400 }, new long[] {}).getFileDescriptor();
 
         // Redacted at first
         final byte[] buf = new byte[10];
@@ -168,4 +168,76 @@
         assertArrayEquals(new long[] { 100, 200 },
                 removeRange(new long[] { 100, 200 }, 150, 150));
     }
+
+    @Test
+    public void testFreeAtStart() throws Exception {
+        final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+                new long[] { 1, 10 }, new long[] {1}).getFileDescriptor();
+
+        final byte[] buf = new byte[10];
+        assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+        assertArrayEquals(
+                new byte[] { 64, (byte) 'f', (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0, 0, 0 },
+                buf);
+    }
+
+    @Test
+    public void testFreeAtOffset() throws Exception {
+        final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+                new long[] { 1, 10 }, new long[] {3}).getFileDescriptor();
+
+        final byte[] buf = new byte[10];
+        assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+        assertArrayEquals(
+                new byte[] { 64, 0, 0, (byte) 'f', (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0 },
+                buf);
+    }
+
+    @Test
+    public void testFreeAcrossRedactionStart() throws Exception {
+        final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+                new long[] { 1, 10 }, new long[] {0}).getFileDescriptor();
+
+        final byte[] buf = new byte[10];
+        assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+        assertArrayEquals(
+                new byte[] { 64, (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0, 0, 0, 0 },
+                buf);
+    }
+
+    @Test
+    public void testFreeAcrossRedactionEnd() throws Exception {
+        final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+                new long[] { 1, 3 }, new long[] {2}).getFileDescriptor();
+
+        final byte[] buf = new byte[10];
+        assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+        assertArrayEquals(
+                new byte[] { 64, 0, (byte) 'f', 64, 64, 64, 64, 64, 64, 64 },
+                buf);
+    }
+
+    @Test
+    public void testFreeOutsideRedaction() throws Exception {
+        final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+                new long[] { 1, 8 }, new long[] { 8 }).getFileDescriptor();
+
+        final byte[] buf = new byte[10];
+        assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+        assertArrayEquals(
+                new byte[] { 64, 0, 0, 0, 0, 0, 0, 0, 64, 64 },
+                buf);
+    }
+
+    @Test
+    public void testFreeMultipleRedactions() throws Exception {
+        final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+                new long[] { 1, 2, 3, 4 }, new long[] { 0 }).getFileDescriptor();
+
+        final byte[] buf = new byte[10];
+        assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+        assertArrayEquals(
+                new byte[] { 64, (byte) 'r', 64, (byte) 'e', 64, 64, 64, 64, 64, 64 },
+                buf);
+    }
 }
diff --git a/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java b/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java
new file mode 100644
index 0000000..b605520
--- /dev/null
+++ b/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.text.format;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimeMigrationUtilsTest {
+
+    private static final int ONE_DAY_IN_SECONDS = 24 * 60 * 60;
+
+    private Locale mDefaultLocale;
+    private TimeZone mDefaultTimeZone;
+
+    @Before
+    public void setUp() {
+        mDefaultLocale = Locale.getDefault();
+        mDefaultTimeZone = TimeZone.getDefault();
+    }
+
+    @After
+    public void tearDown() {
+        Locale.setDefault(mDefaultLocale);
+        TimeZone.setDefault(mDefaultTimeZone);
+    }
+
+    @Test
+    public void formatMillisWithFixedFormat_fixes2038Issue() {
+        Locale.setDefault(Locale.UK);
+        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+
+        // The following cannot be represented properly using Time because they are outside of the
+        // supported range.
+        long y2038Issue1 = (((long) Integer.MIN_VALUE) - ONE_DAY_IN_SECONDS) * 1000L;
+        assertEquals(
+                "1901-12-12 20:45:52", TimeMigrationUtils.formatMillisWithFixedFormat(y2038Issue1));
+        long y2038Issue2 = (((long) Integer.MAX_VALUE) + ONE_DAY_IN_SECONDS) * 1000L;
+        assertEquals(
+                "2038-01-20 03:14:07", TimeMigrationUtils.formatMillisWithFixedFormat(y2038Issue2));
+    }
+
+    /**
+     * Compares TimeMigrationUtils.formatSimpleDateTime() with the code it is replacing.
+     */
+    @Test
+    public void formatMillisAsDateTime_matchesOldBehavior() {
+        // A selection of interesting locales.
+        Locale[] locales = new Locale[] {
+                Locale.US,
+                Locale.UK,
+                Locale.FRANCE,
+                Locale.JAPAN,
+                Locale.CHINA,
+                // Android supports RTL locales like arabic and arabic with latin numbers.
+                Locale.forLanguageTag("ar-AE"),
+                Locale.forLanguageTag("ar-AE-u-nu-latn"),
+        };
+        // A selection of interesting time zones.
+        String[] timeZoneIds = new String[] {
+                "UTC", "Europe/London", "America/New_York", "America/Los_Angeles", "Asia/Shanghai",
+        };
+        // Some arbitrary times when the two formatters should agree.
+        long[] timesMillis = new long[] {
+                System.currentTimeMillis(),
+                0,
+                // The Time class only works in 32-bit range, the replacement works beyond that. To
+                // avoid messing around with offsets and complicating the test, below there are a
+                // day after / before the known limits.
+                (Integer.MIN_VALUE + ONE_DAY_IN_SECONDS) * 1000L,
+                (Integer.MAX_VALUE - ONE_DAY_IN_SECONDS) * 1000L,
+        };
+
+        for (Locale locale : locales) {
+            Locale.setDefault(locale);
+            for (String timeZoneId : timeZoneIds) {
+                TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
+                TimeZone.setDefault(timeZone);
+                for (long timeMillis : timesMillis) {
+                    Time time = new Time();
+                    time.set(timeMillis);
+                    String oldResult = time.format("%Y-%m-%d %H:%M:%S");
+                    String newResult = TimeMigrationUtils.formatMillisWithFixedFormat(timeMillis);
+                    assertEquals(
+                            "locale=" + locale + ", timeZoneId=" + timeZoneId
+                                    + ", timeMillis=" + timeMillis,
+                            oldResult, newResult);
+                }
+            }
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index 182fe78..d5a0dfa 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -104,8 +104,8 @@
 
     @Test
     public void testExtractBoundsFromList_top_and_bottom() {
-        Rect safeInsets = new Rect(0, 1, 0, 10);
-        Rect boundTop = new Rect(80, 0, 120, 10);
+        Rect safeInsets = new Rect(0, 10, 0, 10);
+        Rect boundTop = new Rect(0, 0, 120, 10);
         Rect boundBottom = new Rect(80, 190, 120, 200);
         assertThat(extractBoundsFromList(safeInsets,
                 Arrays.asList(new Rect[]{boundTop, boundBottom})),
diff --git a/core/tests/coretests/src/android/view/WindowInfoTest.java b/core/tests/coretests/src/android/view/WindowInfoTest.java
index 037a0d9..05e8bd8 100644
--- a/core/tests/coretests/src/android/view/WindowInfoTest.java
+++ b/core/tests/coretests/src/android/view/WindowInfoTest.java
@@ -91,7 +91,7 @@
         assertFalse(w.focused);
         assertFalse(w.inPictureInPicture);
         assertFalse(w.hasFlagWatchOutsideTouch);
-        assertTrue(w.boundsInScreen.isEmpty());
+        assertTrue(w.regionInScreen.isEmpty());
     }
 
     @SmallTest
@@ -114,7 +114,7 @@
         equality &= w1.childTokens.equals(w2.childTokens);
         equality &= w1.parentToken == w2.parentToken;
         equality &= w1.activityToken == w2.activityToken;
-        equality &= w1.boundsInScreen.equals(w2.boundsInScreen);
+        equality &= w1.regionInScreen.equals(w2.regionInScreen);
         return equality;
     }
 
@@ -132,6 +132,6 @@
         windowInfo.focused = true;
         windowInfo.inPictureInPicture = true;
         windowInfo.hasFlagWatchOutsideTouch = true;
-        windowInfo.boundsInScreen.set(0, 0, 1080, 1080);
+        windowInfo.regionInScreen.set(0, 0, 1080, 1080);
     }
 }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 683d16b..682416c 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -21,6 +21,7 @@
 import android.content.pm.ParceledListSlice;
 import android.graphics.Region;
 import android.os.Bundle;
+import android.os.IBinder;
 
 import java.util.List;
 
@@ -131,7 +132,13 @@
 
     public void sendGesture(int sequence, ParceledListSlice gestureSteps) {}
 
+    public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {}
+
     public boolean isFingerprintGestureDetectionAvailable() {
         return false;
     }
+
+    public IBinder getOverlayWindowToken(int displayId) {
+        return null;
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index aadfcbc..abee1da2 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -71,7 +71,7 @@
 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
 import com.android.internal.util.test.FakeSettingsProvider;
 
-import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -136,6 +136,7 @@
 
         mContentResolver = new MockContentResolver(mContext);
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        FakeSettingsProvider.clearSettingsProvider();
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
 
         when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(anyInt()))
@@ -193,8 +194,9 @@
         when(mTextToSpeech.getVoice()).thenReturn(mVoice);
     }
 
-    @After
-    public void tearDown() {
+    @AfterClass
+    public static void cleanUpSettingsProvider() {
+        FakeSettingsProvider.clearSettingsProvider();
     }
 
     @Test
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 008085e..a935737 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -68,12 +68,7 @@
     private WakeLockInfo createWakeLockInfo(String name, int activeCount, long totalTime) {
         WakeLockInfo info = new WakeLockInfo();
         info.name = name;
-        info.pid = 1;
         info.activeCount = activeCount;
-        info.isActive = true;
-        info.activeSince = 0;
-        info.lastChange = 0;
-        info.maxTime = 0;
         info.totalTime = totalTime;
         return info;
     }
@@ -89,7 +84,7 @@
                                                         byte[] buffer, WakeLockInfo[] wlStats) {
         mReader.updateVersion(staleStats);
         mReader.parseProcWakelocks(buffer, buffer.length, true, staleStats);
-        mReader.getNativeWakelockStats(wlStats, staleStats);
+        mReader.updateWakelockStats(wlStats, staleStats);
         return mReader.removeOldStats(staleStats);
     }
 
@@ -101,7 +96,7 @@
         mReader = new KernelWakelockReader();
     }
 
-// ------------------------- Kernel Wakelock Stats Test ------------------------
+// ------------------------- Legacy Wakelock Stats Test ------------------------
     @SmallTest
     public void testParseEmptyFile() throws Exception {
         KernelWakelockStats staleStats = mReader.parseProcWakelocks(new byte[0], 0, true,
@@ -196,10 +191,10 @@
         assertFalse(staleStats.containsKey("Fakelock"));
     }
 
-// -------------------- Native (SystemSuspend) Wakelock Stats Test -------------------
+// -------------------- SystemSuspend Wakelock Stats Test -------------------
     @SmallTest
     public void testEmptyWakeLockInfoList() {
-        KernelWakelockStats staleStats = mReader.getNativeWakelockStats(new WakeLockInfo[0],
+        KernelWakelockStats staleStats = mReader.updateWakelockStats(new WakeLockInfo[0],
                 new KernelWakelockStats());
 
         assertTrue(staleStats.isEmpty());
@@ -208,9 +203,9 @@
     @SmallTest
     public void testOneWakeLockInfo() {
         WakeLockInfo[] wlStats = new WakeLockInfo[1];
-        wlStats[0] = createWakeLockInfo("WakeLock", 20, 10000);
+        wlStats[0] = createWakeLockInfo("WakeLock", 20, 1000);   // Milliseconds
 
-        KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
+        KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
                 new KernelWakelockStats());
 
         assertEquals(1, staleStats.size());
@@ -219,16 +214,16 @@
 
         KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
         assertEquals(20, entry.mCount);
-        assertEquals(10000, entry.mTotalTime);
+        assertEquals(1000 * 1000, entry.mTotalTime);   // Microseconds
     }
 
     @SmallTest
     public void testTwoWakeLockInfos() {
         WakeLockInfo[] wlStats = new WakeLockInfo[2];
-        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
-        wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000);
+        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds
+        wlStats[1] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds
 
-        KernelWakelockStats staleStats = mReader.getNativeWakelockStats(wlStats,
+        KernelWakelockStats staleStats = mReader.updateWakelockStats(wlStats,
                 new KernelWakelockStats());
 
         assertEquals(2, staleStats.size());
@@ -238,17 +233,17 @@
 
         KernelWakelockStats.Entry entry1 = staleStats.get("WakeLock1");
         assertEquals(10, entry1.mCount);
-        assertEquals(1000, entry1.mTotalTime);
+        assertEquals(1000 * 1000, entry1.mTotalTime); // Microseconds
 
         KernelWakelockStats.Entry entry2 = staleStats.get("WakeLock2");
         assertEquals(20, entry2.mCount);
-        assertEquals(2000, entry2.mTotalTime);
+        assertEquals(2000 * 1000, entry2.mTotalTime); // Microseconds
     }
 
     @SmallTest
     public void testWakeLockInfosBecomeStale() {
         WakeLockInfo[] wlStats = new WakeLockInfo[1];
-        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000);
+        wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds
 
         KernelWakelockStats staleStats = new KernelWakelockStats();
 
@@ -259,9 +254,9 @@
         assertTrue(staleStats.containsKey("WakeLock1"));
         KernelWakelockStats.Entry entry = staleStats.get("WakeLock1");
         assertEquals(10, entry.mCount);
-        assertEquals(1000, entry.mTotalTime);
+        assertEquals(1000 * 1000, entry.mTotalTime);  // Microseconds
 
-        wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000);
+        wlStats[0] = createWakeLockInfo("WakeLock2", 20, 2000); // Milliseconds
 
         readKernelWakelockStats(staleStats, new byte[0], wlStats);
 
@@ -271,146 +266,6 @@
         assertTrue(staleStats.containsKey("WakeLock2"));
         entry = staleStats.get("WakeLock2");
         assertEquals(20, entry.mCount);
-        assertEquals(2000, entry.mTotalTime);
-    }
-
-// -------------------- 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);
-
-        readKernelWakelockStats(staleStats, buffer, wlStats);
-
-        assertEquals(1, staleStats.size());
-
-        assertTrue(staleStats.containsKey("WakeLock"));
-
-        KernelWakelockStats.Entry entry = staleStats.get("WakeLock");
-        assertEquals(10, entry.mCount);
-        assertEquals(1000, entry.mTotalTime);
-    }
-
-    @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);
-
-        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, entry2.mTotalTime);
-    }
-
-    @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);
-        wlStats[1] = createWakeLockInfo("WakeLock4", 20, 2000);
-
-        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, entry3.mTotalTime);
-
-        KernelWakelockStats.Entry entry4 = staleStats.get("WakeLock4");
-        assertEquals(20, entry4.mCount);
-        assertEquals(2000, entry4.mTotalTime);
-
-        buffer = new ProcFileBuilder()
-                .addLine("WakeLock1", 45, 789)  // Milliseconds
-                .addLine("WakeLock1", 56, 123)  // Milliseconds
-                .getBytes();
-        wlStats = new WakeLockInfo[1];
-        wlStats[0] = createWakeLockInfo("WakeLock4", 40, 4000);
-
-        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, entry4.mTotalTime);
+        assertEquals(2000 * 1000, entry.mTotalTime); // Micro seconds
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/policy/DecorViewTest.java b/core/tests/coretests/src/com/android/internal/policy/DecorViewTest.java
new file mode 100644
index 0000000..62e4efe
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/policy/DecorViewTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.internal.policy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class DecorViewTest {
+
+    private Context mContext;
+    private DecorView mDecorView;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        PhoneWindow phoneWindow = new PhoneWindow(mContext);
+        mDecorView = (DecorView) phoneWindow.getDecorView();
+    }
+
+    @Test
+    public void setBackgroundDrawableSameAsSetWindowBackground() {
+        Drawable bitmapDrawable = mContext.getResources()
+                .getDrawable(R.drawable.test16x12, mContext.getTheme());
+        int w = 16;
+        int h = 12;
+        Bitmap expectedBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+
+        mDecorView.setWindowBackground(bitmapDrawable);
+        Canvas testCanvas = new Canvas(expectedBitmap);
+        mDecorView.draw(testCanvas);
+        testCanvas.release();
+
+        Drawable expectedBackground = mDecorView.getBackground();
+
+        mDecorView.setBackgroundDrawable(bitmapDrawable);
+        Bitmap resultBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+        Canvas resCanvas = new Canvas(resultBitmap);
+        mDecorView.draw(resCanvas);
+        resCanvas.release();
+
+        // Check that the drawable is the same.
+        assertThat(mDecorView.getBackground()).isEqualTo(expectedBackground);
+        assertThat(mDecorView.getBackground()).isEqualTo(bitmapDrawable);
+
+        // Check that canvas is the same.
+        int[] expPixels = new int[w * h];
+        int[] resPixels = new int[w * h];
+        resultBitmap.getPixels(resPixels, 0, w, 0, 0, w, h);
+        expectedBitmap.getPixels(expPixels, 0, w, 0, 0, w, h);
+        assertThat(Arrays.toString(expPixels)).isEqualTo(Arrays.toString(resPixels));
+    }
+
+    @Test
+    public void setBackgroundWithNoWindow() {
+        PhoneWindow phoneWindow = new PhoneWindow(mContext);
+        // Set a theme that defines a non-null value for android:background
+        mContext.setTheme(R.style.ViewDefaultBackground);
+        DecorView decorView = (DecorView) phoneWindow.getDecorView();
+        assertThat(decorView.getBackground()).isNotNull();
+    }
+}
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index ae7fe6c..0e635c7 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -63,7 +63,7 @@
  * <h3>Creating a RenderNode</h3>
  * <pre class="prettyprint">
  *     RenderNode renderNode = new RenderNode("myRenderNode");
- *     renderNode.setLeftTopRightBottom(0, 0, 50, 50); // Set the size to 50x50
+ *     renderNode.setPosition(0, 0, 50, 50); // Set the size to 50x50
  *     RecordingCanvas canvas = renderNode.beginRecording();
  *     try {
  *         // Draw with the canvas
@@ -104,7 +104,7 @@
  * <pre class="prettyprint">
  *     private void createDisplayList() {
  *         mRenderNode = new RenderNode("MyRenderNode");
- *         mRenderNode.setLeftTopRightBottom(0, 0, width, height);
+ *         mRenderNode.setPosition(0, 0, width, height);
  *         RecordingCanvas canvas = mRenderNode.beginRecording();
  *         try {
  *             for (Bitmap b : mBitmaps) {
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 4755cb8..f7c8337 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -74,7 +74,7 @@
 const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
 const char* AssetManager::VENDOR_OVERLAY_DIR = "/vendor/overlay";
 const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay";
-const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay";
+const char* AssetManager::SYSTEM_EXT_OVERLAY_DIR = "/system_ext/overlay";
 const char* AssetManager::ODM_OVERLAY_DIR = "/odm/overlay";
 const char* AssetManager::OEM_OVERLAY_DIR = "/oem/overlay";
 const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme";
@@ -575,7 +575,7 @@
                         mZipSet.setZipResourceTableAsset(ap.path, ass);
                 }
             }
-            
+
             if (nextEntryIdx == 0 && ass != NULL) {
                 // If this is the first resource table in the asset
                 // manager, then we are going to cache it so that we
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index 66fba26b..ce0985b 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -61,7 +61,7 @@
     static const char* IDMAP_BIN;
     static const char* VENDOR_OVERLAY_DIR;
     static const char* PRODUCT_OVERLAY_DIR;
-    static const char* PRODUCT_SERVICES_OVERLAY_DIR;
+    static const char* SYSTEM_EXT_OVERLAY_DIR;
     static const char* ODM_OVERLAY_DIR;
     static const char* OEM_OVERLAY_DIR;
     /*
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index e58fbbe..c8eb1ca 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -274,7 +274,12 @@
     }
     sk_sp<SkDrawable> drawable;
     SkMatrix matrix = SkMatrix::I();
-    void draw(SkCanvas* c, const SkMatrix&) const { c->drawDrawable(drawable.get(), &matrix); }
+    // It is important that we call drawable->draw(c) here instead of c->drawDrawable(drawable).
+    // Drawables are mutable and in cases, like RenderNodeDrawable, are not expected to produce the
+    // same content if retained outside the duration of the frame. Therefore we resolve
+    // them now and do not allow the canvas to take a reference to the drawable and potentially
+    // keep it alive for longer than the frames duration (e.g. SKP serialization).
+    void draw(SkCanvas* c, const SkMatrix&) const { drawable->draw(c, &matrix); }
 };
 struct DrawPicture final : Op {
     static const auto kType = Type::DrawPicture;
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 7269bca..16ec877 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -29,7 +29,6 @@
 #include "SkPaint.h"
 #include "SkPath.h"
 #include "SkRect.h"
-#include "SkTDArray.h"
 #include "SkTemplates.h"
 
 #include <vector>
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 6ea6af8..f01b1bf 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -778,6 +778,13 @@
     mCanvas->drawDrawable(drawable.get());
 }
 
+void SkiaCanvas::drawPicture(const SkPicture& picture) {
+    // TODO: Change to mCanvas->drawPicture()? SkCanvas::drawPicture seems to be
+    // where the logic is for playback vs. ref picture. Using picture.playback here
+    // to stay behavior-identical for now, but should revisit this at some point.
+    picture.playback(mCanvas);
+}
+
 // ----------------------------------------------------------------------------
 // Canvas draw operations: View System
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 05a6d0d..799a891 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -46,8 +46,6 @@
 
     virtual ~SkiaCanvas();
 
-    virtual SkCanvas* asSkCanvas() override { return mCanvas; }
-
     virtual void resetRecording(int width, int height,
                                 uirenderer::RenderNode* renderNode) override {
         LOG_ALWAYS_FATAL("SkiaCanvas cannot be reset as a recording canvas");
@@ -155,9 +153,11 @@
     virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
     virtual void callDrawGLFunction(Functor* functor,
                                     uirenderer::GlFunctorLifecycleListener* listener) override;
+    virtual void drawPicture(const SkPicture& picture) override;
 
 protected:
     SkiaCanvas();
+    SkCanvas* asSkCanvas() { return mCanvas; }
     void reset(SkCanvas* skiaCanvas);
     void drawDrawable(SkDrawable* drawable) { mCanvas->drawDrawable(drawable); }
 
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index ac8db21..ee4fa1d6 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -131,20 +131,6 @@
      */
     static void setCompatibilityVersion(int apiLevel);
 
-    /**
-     *  Provides a Skia SkCanvas interface that acts as a proxy to this Canvas.
-     *  It is useful for testing and clients (e.g. Picture/Movie) that expect to
-     *  draw their contents into an SkCanvas.
-     *
-     *  The SkCanvas returned is *only* valid until another Canvas call is made
-     *  that would change state (e.g. matrix or clip). Clients of asSkCanvas()
-     *  are responsible for *not* persisting this pointer.
-     *
-     *  Further, the returned SkCanvas should NOT be unref'd and is valid until
-     *  this canvas is destroyed or a new bitmap is set.
-     */
-    virtual SkCanvas* asSkCanvas() = 0;
-
     virtual void setBitmap(const SkBitmap& bitmap) = 0;
 
     virtual bool isOpaque() = 0;
@@ -264,6 +250,7 @@
                                const SkPaint* paint) = 0;
 
     virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) = 0;
+    virtual void drawPicture(const SkPicture& picture) = 0;
 
     /**
      * Specifies if the positions passed to ::drawText are absolute or relative
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index eed1942..96b17e1 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -33,21 +33,47 @@
     }
 }
 
-// This is a less-strict matrix.isTranslate() that will still report being translate-only
-// on imperceptibly small scaleX & scaleY values.
-static bool isBasicallyTranslate(const SkMatrix& matrix) {
-    if (!matrix.isScaleTranslate()) return false;
-    return MathUtils::isOne(matrix.getScaleX()) && MathUtils::isOne(matrix.getScaleY());
-}
-
-static bool shouldFilter(const SkMatrix& matrix) {
-    if (!matrix.isScaleTranslate()) return true;
-
-    // We only care about meaningful scale here
-    bool noScale = MathUtils::isOne(matrix.getScaleX()) && MathUtils::isOne(matrix.getScaleY());
-    bool pixelAligned =
-            SkScalarIsInt(matrix.getTranslateX()) && SkScalarIsInt(matrix.getTranslateY());
-    return !(noScale && pixelAligned);
+// 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) {
+    if (!matrix.rectStaysRect()) return true;
+    SkRect dstDevRect = matrix.mapRect(dstRect);
+    float dstW, dstH;
+    bool requiresIntegerTranslate = false;
+    if (MathUtils::isZero(matrix.getScaleX()) && MathUtils::isZero(matrix.getScaleY())) {
+        // Has a 90 or 270 degree rotation, although total matrix may also have scale factors
+        // in m10 and m01. Those scalings are automatically handled by mapRect so comparing
+        // dimensions is sufficient, but swap width and height comparison.
+        dstW = dstDevRect.height();
+        dstH = dstDevRect.width();
+        requiresIntegerTranslate = true;
+    } else {
+        // Handle H/V flips or 180 rotation matrices. Axes may have been mirrored, but
+        // dimensions are still safe to compare directly.
+        dstW = dstDevRect.width();
+        dstH = dstDevRect.height();
+        requiresIntegerTranslate =
+                matrix.getScaleX() < -NON_ZERO_EPSILON || matrix.getScaleY() < -NON_ZERO_EPSILON;
+    }
+    if (!(MathUtils::areEqual(dstW, srcRect.width()) &&
+          MathUtils::areEqual(dstH, srcRect.height()))) {
+        return true;
+    }
+    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())));
+    } else {
+        // As long as src and device rects are translated by the same fractional amount,
+        // filtering won't be needed
+        return !(MathUtils::areEqual(SkScalarFraction(srcRect.x()),
+                                     SkScalarFraction(dstDevRect.x())) &&
+                 MathUtils::areEqual(SkScalarFraction(srcRect.y()),
+                                     SkScalarFraction(dstDevRect.y())));
+    }
 }
 
 bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
@@ -114,24 +140,21 @@
                 skiaDestRect = SkRect::MakeIWH(layerWidth, layerHeight);
             }
             matrixInv.mapRect(&skiaDestRect);
-            // If (matrix is identity or an integer translation) and (src/dst buffers size match),
+            // If (matrix is a rect-to-rect transform)
+            // and (src/dst buffers size match in screen coordinates)
+            // and (src/dst corners align fractionally),
             // then use nearest neighbor, otherwise use bilerp sampling.
-            // Integer translation is defined as when src rect and dst rect align fractionally.
             // Skia TextureOp has the above logic build-in, but not NonAAFillRectOp. TextureOp works
             // only for SrcOver blending and without color filter (readback uses Src blending).
-            bool isIntegerTranslate =
-                    isBasicallyTranslate(totalMatrix) &&
-                    SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX]) ==
-                            SkScalarFraction(skiaSrcRect.fLeft) &&
-                    SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY]) ==
-                            SkScalarFraction(skiaSrcRect.fTop);
-            if (layer->getForceFilter() || !isIntegerTranslate) {
+            if (layer->getForceFilter() ||
+                shouldFilterRect(totalMatrix, skiaSrcRect, skiaDestRect)) {
                 paint.setFilterQuality(kLow_SkFilterQuality);
             }
             canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, &paint,
                                   SkCanvas::kFast_SrcRectConstraint);
         } else {
-            if (layer->getForceFilter() || shouldFilter(totalMatrix)) {
+            SkRect imageRect = SkRect::MakeIWH(layerImage->width(), layerImage->height());
+            if (layer->getForceFilter() || shouldFilterRect(totalMatrix, imageRect, imageRect)) {
                 paint.setFilterQuality(kLow_SkFilterQuality);
             }
             canvas->drawImage(layerImage.get(), 0, 0, &paint);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 84c0d13..530926b 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -313,8 +313,7 @@
         case CaptureMode::CallbackAPI:
         case CaptureMode::SingleFrameSKP:
             mRecorder.reset(new SkPictureRecorder());
-            pictureCanvas = mRecorder->beginRecording(surface->width(), surface->height(),
-                nullptr, SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
+            pictureCanvas = mRecorder->beginRecording(surface->width(), surface->height());
             break;
         case CaptureMode::MultiFrameSKP:
             // If a multi frame recording is active, initialize recording for a single frame of a
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 550c27d..d97c5ed 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -145,7 +145,8 @@
 
     if (surface) {
         mNativeSurface = new ReliableSurface{std::move(surface)};
-        mNativeSurface->setDequeueTimeout(500_ms);
+        // TODO: Fix error handling & re-shorten timeout
+        mNativeSurface->setDequeueTimeout(4000_ms);
     } else {
         mNativeSurface = nullptr;
     }
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index e50428b..40fbdff 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -16,6 +16,8 @@
 
 #include "RenderProxy.h"
 
+#include <gui/Surface.h>
+
 #include "DeferredLayerUpdater.h"
 #include "DisplayList.h"
 #include "Properties.h"
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index a0f08cb..c3eb6ed 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -19,7 +19,6 @@
 
 #include <SkBitmap.h>
 #include <cutils/compiler.h>
-#include <gui/Surface.h>
 #include <utils/Functor.h>
 
 #include "../FrameMetricsObserver.h"
@@ -30,6 +29,7 @@
 
 namespace android {
 class GraphicBuffer;
+class Surface;
 
 namespace uirenderer {
 
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index 5fa860a..5717bb3 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -17,6 +17,7 @@
 
 #include <system/graphics.h>
 #include <system/window.h>
+#include <ui/BufferQueueDefs.h>
 #include <vulkan/vulkan.h>
 
 #include <SkRefCnt.h>
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index c813cd9..e70378b 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -1096,10 +1096,8 @@
         int getDrawCounter() { return mDrawCounter; }
 
         virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
-            // expect to draw 2 RenderNodeDrawable, 1 StartReorderBarrierDrawable,
-            // 1 EndReorderBarrierDrawable
-            mDrawCounter++;
-            SkCanvas::onDrawDrawable(drawable, matrix);
+            // Do not expect this to be called. See RecordingCanvas.cpp DrawDrawable for context.
+            EXPECT_TRUE(false);
         }
 
         virtual void didTranslate(SkScalar dx, SkScalar dy) override {
@@ -1159,8 +1157,8 @@
     // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
     ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
     RenderNodeDrawable drawable(parent.get(), &canvas, false);
-    canvas.drawDrawable(&drawable);
-    EXPECT_EQ(9, canvas.getDrawCounter());
+    drawable.draw(&canvas);
+    EXPECT_EQ(5, canvas.getDrawCounter());
 }
 
 // Draw a vector drawable twice but with different bounds and verify correct bounds are used.
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index f6178af..2ed1b25 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -78,7 +78,7 @@
     sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
 
     // Playback to a software sRGB canvas.  The result should be fully red.
-    canvas.asSkCanvas()->drawPicture(picture);
+    canvas.drawPicture(*picture);
     ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0));
 }
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index f5330b4..1cc246b 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -191,19 +191,6 @@
     public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
 
     /**
-     * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} is
-     * about to be changed through Settings app or Quick Settings.
-     * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.
-     * If you're interacting with {@link #isProviderEnabled(String)}, use
-     * {@link #PROVIDERS_CHANGED_ACTION} instead.
-     *
-     * @deprecated Do not use.
-     * @hide
-     */
-    @Deprecated
-    public static final String MODE_CHANGING_ACTION = "com.android.settings.location.MODE_CHANGING";
-
-    /**
      * Broadcast intent action indicating that a high power location requests
      * has either started or stopped being active.  The current state of
      * active location requests should be read from AppOpsManager using
@@ -216,17 +203,10 @@
 
     /**
      * Broadcast intent action for Settings app to inject a footer at the bottom of location
-     * settings.
+     * settings. This is for use only by apps that are included in the system image.
      *
-     * <p>This broadcast is used for two things:
-     * <ol>
-     *     <li>For receivers to inject a footer with provided text. This is for use only by apps
-     *         that are included in the system image. </li>
-     *     <li>For receivers to know their footer is injected under location settings.</li>
-     * </ol>
-     *
-     * <p>To inject a footer to location settings, you must declare a broadcast receiver of
-     * {@link LocationManager#SETTINGS_FOOTER_DISPLAYED_ACTION} in the manifest as so:
+     * <p>To inject a footer to location settings, you must declare a broadcast receiver for
+     * this action in the manifest:
      * <pre>
      *     &lt;receiver android:name="com.example.android.footer.MyFooterInjector"&gt;
      *         &lt;intent-filter&gt;
@@ -238,10 +218,8 @@
      *     &lt;/receiver&gt;
      * </pre>
      *
-     * <p>On entering location settings, Settings app will send a
-     * {@link #SETTINGS_FOOTER_DISPLAYED_ACTION} broadcast to receivers whose footer is successfully
-     * injected. On leaving location settings, the footer becomes not visible to users. Settings app
-     * will send a {@link #SETTINGS_FOOTER_REMOVED_ACTION} broadcast to those receivers.
+     * <p>This broadcast receiver will never actually be invoked. See also
+     * {#METADATA_SETTINGS_FOOTER_STRING}.
      *
      * @hide
      */
@@ -249,16 +227,6 @@
             "com.android.settings.location.DISPLAYED_FOOTER";
 
     /**
-     * Broadcast intent action when location settings footer is not visible to users.
-     *
-     * <p>See {@link #SETTINGS_FOOTER_DISPLAYED_ACTION} for more detail on how to use.
-     *
-     * @hide
-     */
-    public static final String SETTINGS_FOOTER_REMOVED_ACTION =
-            "com.android.settings.location.REMOVED_FOOTER";
-
-    /**
      * Metadata name for {@link LocationManager#SETTINGS_FOOTER_DISPLAYED_ACTION} broadcast
      * receivers to specify a string resource id as location settings footer text. This is for use
      * only by apps that are included in the system image.
diff --git a/media/Android.bp b/media/Android.bp
index 4f9671f..29064ad 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -33,6 +33,8 @@
         "framework_media_annotation",
         "android_system_stubs_current",
     ],
+
+    plugins: ["java_api_finder"],
 }
 
 filegroup {
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index ce9b07d..0254c97 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -1788,6 +1788,9 @@
      * @hide
      */
     public int getPortId() {
+        if (mNativeRecorderInJavaObj == 0) {
+            return 0;
+        }
         return native_getPortId();
     }
 
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 353e58e..7906fa3 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -246,7 +246,7 @@
  *         via {@link #setOnBufferingUpdateListener(OnBufferingUpdateListener)}.
  *         This callback allows applications to keep track of the buffering status
  *         while streaming audio/video.</li>
- *         <li>Calling {@link #start()} has not effect
+ *         <li>Calling {@link #start()} has no effect
  *         on a MediaPlayer object that is already in the <em>Started</em> state.</li>
  *         </ul>
  *         </li>
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 63b22df..bf7da23 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -720,7 +720,7 @@
 
     /**
      * Sets the width and height of the video to be captured.  Must be called
-     * after setVideoSource(). Call this after setOutFormat() but before
+     * after setVideoSource(). Call this after setOutputFormat() but before
      * prepare().
      *
      * @param width the width of the video to be captured
@@ -733,7 +733,7 @@
 
     /**
      * Sets the frame rate of the video to be captured.  Must be called
-     * after setVideoSource(). Call this after setOutFormat() but before
+     * after setVideoSource(). Call this after setOutputFormat() but before
      * prepare().
      *
      * @param rate the number of frames per second of video to capture
@@ -748,7 +748,7 @@
 
     /**
      * Sets the maximum duration (in ms) of the recording session.
-     * Call this after setOutFormat() but before prepare().
+     * Call this after setOutputFormat() but before prepare().
      * After recording reaches the specified duration, a notification
      * will be sent to the {@link android.media.MediaRecorder.OnInfoListener}
      * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED}
@@ -769,7 +769,7 @@
 
     /**
      * Sets the maximum filesize (in bytes) of the recording session.
-     * Call this after setOutFormat() but before prepare().
+     * Call this after setOutputFormat() but before prepare().
      * After recording reaches the specified filesize, a notification
      * will be sent to the {@link android.media.MediaRecorder.OnInfoListener}
      * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}
@@ -1624,6 +1624,9 @@
      * @hide
      */
     public int getPortId() {
+        if (mNativeContext == 0) {
+            return 0;
+        }
         return native_getPortId();
     }
 
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index f13a64c..5dcbb05 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -23,6 +23,9 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -53,6 +56,8 @@
     final String mDescription;
     @Nullable
     final String mClientPackageName;
+    @NonNull
+    final List<String> mSupportedCategories;
     @Nullable
     final Bundle mExtras;
 
@@ -62,6 +67,7 @@
         mName = builder.mName;
         mDescription = builder.mDescription;
         mClientPackageName = builder.mClientPackageName;
+        mSupportedCategories = builder.mSupportedCategories;
         mExtras = builder.mExtras;
     }
 
@@ -71,6 +77,7 @@
         mName = in.readString();
         mDescription = in.readString();
         mClientPackageName = in.readString();
+        mSupportedCategories = in.createStringArrayList();
         mExtras = in.readBundle();
     }
 
@@ -103,13 +110,14 @@
                 && Objects.equals(mName, other.mName)
                 && Objects.equals(mDescription, other.mDescription)
                 && Objects.equals(mClientPackageName, other.mClientPackageName)
+                && Objects.equals(mSupportedCategories, other.mSupportedCategories)
                 //TODO: This will be evaluated as false in most cases. Try not to.
                 && Objects.equals(mExtras, other.mExtras);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mId, mName, mDescription);
+        return Objects.hash(mId, mName, mDescription, mSupportedCategories);
     }
 
     @NonNull
@@ -146,11 +154,38 @@
         return mClientPackageName;
     }
 
+    /**
+     * Gets the supported categories of the route.
+     */
+    @NonNull
+    public List<String> getSupportedCategories() {
+        return mSupportedCategories;
+    }
+
     @Nullable
     public Bundle getExtras() {
         return mExtras;
     }
 
+    //TODO: Move this if we re-define control category / selector things.
+    /**
+     * Returns true if the route supports at least one of the specified control categories
+     *
+     * @param controlCategories the list of control categories to consider
+     * @return true if the route supports at least one category
+     */
+    public boolean supportsControlCategory(@NonNull Collection<String> controlCategories) {
+        Objects.requireNonNull(controlCategories, "control categories must not be null");
+        for (String controlCategory : controlCategories) {
+            for (String supportedCategory : getSupportedCategories()) {
+                if (TextUtils.equals(controlCategory, supportedCategory)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -163,6 +198,7 @@
         dest.writeString(mName);
         dest.writeString(mDescription);
         dest.writeString(mClientPackageName);
+        dest.writeStringList(mSupportedCategories);
         dest.writeBundle(mExtras);
     }
 
@@ -187,6 +223,7 @@
         String mName;
         String mDescription;
         String mClientPackageName;
+        List<String> mSupportedCategories;
         Bundle mExtras;
 
         public Builder(@NonNull String id, @NonNull String name) {
@@ -198,6 +235,7 @@
             }
             setId(id);
             setName(name);
+            mSupportedCategories = new ArrayList<>();
         }
 
         public Builder(@NonNull MediaRoute2Info routeInfo) {
@@ -212,6 +250,7 @@
             setName(routeInfo.mName);
             mDescription = routeInfo.mDescription;
             setClientPackageName(routeInfo.mClientPackageName);
+            setSupportedCategories(routeInfo.mSupportedCategories);
             if (routeInfo.mExtras != null) {
                 mExtras = new Bundle(routeInfo.mExtras);
             }
@@ -273,6 +312,39 @@
         }
 
         /**
+         * Sets the supported categories of the route.
+         */
+        @NonNull
+        public Builder setSupportedCategories(@NonNull Collection<String> categories) {
+            mSupportedCategories = new ArrayList<>();
+            return addSupportedCategories(categories);
+        }
+
+        /**
+         * Adds supported categories for the route.
+         */
+        @NonNull
+        public Builder addSupportedCategories(@NonNull Collection<String> categories) {
+            Objects.requireNonNull(categories, "categories must not be null");
+            for (String category: categories) {
+                addSupportedCategory(category);
+            }
+            return this;
+        }
+
+        /**
+         * Add a supported category for the route.
+         */
+        @NonNull
+        public Builder addSupportedCategory(@NonNull String category) {
+            if (TextUtils.isEmpty(category)) {
+                throw new IllegalArgumentException("category must not be null or empty");
+            }
+            mSupportedCategories.add(category);
+            return this;
+        }
+
+        /**
          * Sets a bundle of extras for the route.
          */
         @NonNull
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 5fc37a5..85105e0 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -38,6 +38,8 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
 
@@ -66,6 +68,8 @@
     List<MediaRoute2ProviderInfo> mProviders = Collections.emptyList();
     @NonNull
     List<MediaRoute2Info> mRoutes = Collections.emptyList();
+    @NonNull
+    ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();
 
     /**
      * Gets an instance of media router manager that controls media route of other applications.
@@ -160,6 +164,8 @@
         return -1;
     }
 
+    //TODO: Use cache not to create array. For now, it's unclear when to purge the cache.
+    //Do this when we finalize how to set control categories.
     /**
      * Gets available routes for an application.
      *
@@ -167,8 +173,17 @@
      */
     @NonNull
     public List<MediaRoute2Info> getAvailableRoutes(@NonNull String packageName) {
-        //TODO: filter irrelevant routes.
-        return Collections.unmodifiableList(mRoutes);
+        List<String> controlCategories = mControlCategoryMap.get(packageName);
+        if (controlCategories == null) {
+            return Collections.emptyList();
+        }
+        List<MediaRoute2Info> routes = new ArrayList<>();
+        for (MediaRoute2Info route : mRoutes) {
+            if (route.supportsControlCategory(controlCategories)) {
+                routes.add(route);
+            }
+        }
+        return routes;
     }
 
     /**
@@ -310,11 +325,8 @@
         }
     }
 
-    void notifyControlCategoriesChanged(String packageName, List<String> categories) {
-        for (CallbackRecord record : mCallbacks) {
-            record.mExecutor.execute(
-                    () -> record.mCallback.onControlCategoriesChanged(packageName, categories));
-        }
+    void updateControlCategories(String packageName, List<String> categories) {
+        mControlCategoryMap.put(packageName, categories);
     }
 
     /**
@@ -346,15 +358,6 @@
         public void onRouteSelected(@NonNull String packageName, @Nullable MediaRoute2Info route) {}
 
         /**
-         * Called when the control categories of an application is changed.
-         *
-         * @param packageName the package name of the app that changed control categories
-         * @param categories the changed categories
-         */
-        public void onControlCategoriesChanged(@NonNull String packageName,
-                @NonNull List<String> categories) {}
-
-        /**
          * Called when the list of routes are changed.
          * A client may refresh available routes for each application.
          */
@@ -389,7 +392,7 @@
 
         @Override
         public void notifyControlCategoriesChanged(String packageName, List<String> categories) {
-            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyControlCategoriesChanged,
+            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::updateControlCategories,
                     MediaRouter2Manager.this, packageName, categories));
         }
 
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 77878f8..0a02156 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -416,11 +416,13 @@
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
                           "Failed to set buffer consumer default format 0x%x", nativeFormat);
+        return;
     }
     res = bufferConsumer->setDefaultBufferDataSpace(nativeDataspace);
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
                           "Failed to set buffer consumer default dataSpace 0x%x", nativeDataspace);
+        return;
     }
 }
 
@@ -704,7 +706,7 @@
     // and we don't set them here.
 }
 
-static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
+static bool Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
         int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
     ALOGV("%s", __FUNCTION__);
 
@@ -713,7 +715,9 @@
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
                              "Pixel format: 0x%x is unsupported", buffer->flexFormat);
+        return false;
     }
+    return true;
 }
 
 static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
@@ -756,8 +760,10 @@
     }
     // Create all SurfacePlanes
     for (int i = 0; i < numPlanes; i++) {
-        Image_getLockedImageInfo(env, &lockedImg, i, halReaderFormat,
-                &pData, &dataSize, &pixelStride, &rowStride);
+        if (!Image_getLockedImageInfo(env, &lockedImg, i, halReaderFormat,
+                &pData, &dataSize, &pixelStride, &rowStride)) {
+            return NULL;
+        }
         byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
         if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
             jniThrowException(env, "java/lang/IllegalStateException",
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 728c55e..6d8b966 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -777,6 +777,7 @@
         status_t res = buffer->unlock();
         if (res != OK) {
             jniThrowRuntimeException(env, "unlock buffer failed");
+            return;
         }
         ALOGV("Successfully unlocked the image");
     }
@@ -872,7 +873,7 @@
     // and we don't set them here.
 }
 
-static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
+static bool Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
         int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
     ALOGV("%s", __FUNCTION__);
 
@@ -880,8 +881,10 @@
             pixelStride, rowStride);
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
-                             "Pixel format: 0x%x is unsupported", buffer->flexFormat);
+                             "Pixel format: 0x%x is unsupported", writerFormat);
+        return false;
     }
+    return true;
 }
 
 static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
@@ -920,8 +923,10 @@
     PublicFormat publicWriterFormat = static_cast<PublicFormat>(writerFormat);
     writerFormat = mapPublicFormatToHalFormat(publicWriterFormat);
     for (int i = 0; i < numPlanes; i++) {
-        Image_getLockedImageInfo(env, &lockedImg, i, writerFormat,
-                &pData, &dataSize, &pixelStride, &rowStride);
+        if (!Image_getLockedImageInfo(env, &lockedImg, i, writerFormat,
+                &pData, &dataSize, &pixelStride, &rowStride)) {
+            return NULL;
+        }
         byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
         if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
             jniThrowException(env, "java/lang/IllegalStateException",
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index a480784..3809bc4 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -501,15 +501,7 @@
         return NULL;
     }
 
-    int colorFormat = getColorFormat(env, params);
 
-    std::vector<sp<IMemory> > frames;
-    status_t err = retriever->getFrameAtIndex(&frames, frameIndex, numFrames, colorFormat);
-    if (err != OK || frames.size() == 0) {
-        jniThrowException(env,
-                "java/lang/IllegalStateException", "No frames from retriever");
-        return NULL;
-    }
     jobject arrayList = env->NewObject(fields.arrayListClazz, fields.arrayListInit);
     if (arrayList == NULL) {
         jniThrowException(env,
@@ -517,18 +509,29 @@
         return NULL;
     }
 
+    int colorFormat = getColorFormat(env, params);
     SkColorType outColorType = setOutColorType(env, colorFormat, params);
-
-    for (size_t i = 0; i < frames.size(); i++) {
-        if (frames[i] == NULL || frames[i]->pointer() == NULL) {
+    size_t i = 0;
+    for (; i < numFrames; i++) {
+        sp<IMemory> frame = retriever->getFrameAtIndex(frameIndex + i, colorFormat);
+        if (frame == NULL || frame->pointer() == NULL) {
             ALOGE("video frame at index %zu is a NULL pointer", frameIndex + i);
-            continue;
+            break;
         }
-        VideoFrame *videoFrame = static_cast<VideoFrame *>(frames[i]->pointer());
+        VideoFrame *videoFrame = static_cast<VideoFrame *>(frame->pointer());
         jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
         env->CallBooleanMethod(arrayList, fields.arrayListAdd, bitmapObj);
         env->DeleteLocalRef(bitmapObj);
     }
+
+    if (i == 0) {
+        env->DeleteLocalRef(arrayList);
+
+        jniThrowException(env,
+                "java/lang/IllegalStateException", "No frames from retriever");
+        return NULL;
+    }
+
     return arrayList;
 }
 
diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp
index 1e9a194..357bb5e5 100644
--- a/media/native/midi/amidi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -122,7 +122,7 @@
  *  - AMEDIA_ERROR_INVALID_PARAMETER
  *  AMEDIA_ERROR_UNKNOWN
  */
-static media_status_t AMIDI_API AMIDI_getDeviceInfo(const AMidiDevice *device,
+static media_status_t AMIDI_getDeviceInfo(const AMidiDevice *device,
         AMidiDeviceInfo *outDeviceInfoPtr) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
@@ -142,7 +142,7 @@
     return AMEDIA_OK;
 }
 
-media_status_t AMIDI_API AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj,
+media_status_t AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj,
         AMidiDevice** devicePtrPtr)
 {
     if (j_midiDeviceObj == nullptr) {
@@ -188,7 +188,7 @@
     return AMEDIA_OK;
 }
 
-media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *device)
+media_status_t AMidiDevice_release(const AMidiDevice *device)
 {
     if (device == nullptr || device->midiDeviceObj == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
@@ -217,21 +217,21 @@
     return AMEDIA_OK;
 }
 
-int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) {
+int32_t AMidiDevice_getType(const AMidiDevice *device) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     return device->deviceInfo.type;
 }
 
-ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) {
+ssize_t AMidiDevice_getNumInputPorts(const AMidiDevice *device) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
     return device->deviceInfo.inputPortCount;
 }
 
-ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) {
+ssize_t AMidiDevice_getNumOutputPorts(const AMidiDevice *device) {
     if (device == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
@@ -291,7 +291,7 @@
 /*
  * Output (receiving) API
  */
-media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
         AMidiOutputPort **outOutputPortPtr) {
     return AMIDI_openPort(device, portNumber, PORTTYPE_OUTPUT, (AMIDI_Port**)outOutputPortPtr);
 }
@@ -350,7 +350,7 @@
     AMIDI_Port *mPort;
 };
 
-ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
+ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
          uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *timestampPtr) {
 
     if (outputPort == nullptr || buffer == nullptr) {
@@ -361,19 +361,19 @@
            numBytesReceivedPtr, timestampPtr);
 }
 
-void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) {
+void AMidiOutputPort_close(const AMidiOutputPort *outputPort) {
     AMIDI_closePort((AMIDI_Port*)outputPort);
 }
 
 /*
  * Input (sending) API
  */
-media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
         AMidiInputPort **outInputPortPtr) {
     return AMIDI_openPort(device, portNumber, PORTTYPE_INPUT, (AMIDI_Port**)outInputPortPtr);
 }
 
-void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) {
+void AMidiInputPort_close(const AMidiInputPort *inputPort) {
     AMIDI_closePort((AMIDI_Port*)inputPort);
 }
 
@@ -386,12 +386,12 @@
     return numBytes + AMIDI_PACKET_OVERHEAD;
 }
 
-ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
+ssize_t AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
                             size_t numBytes) {
     return AMidiInputPort_sendWithTimestamp(inputPort, buffer, numBytes, 0);
 }
 
-ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
+ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
         const uint8_t *data, size_t numBytes, int64_t timestamp) {
     if (inputPort == nullptr || data == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
@@ -423,7 +423,7 @@
     return numSent;
 }
 
-media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) {
+media_status_t AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) {
     if (inputPort == nullptr) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
diff --git a/media/native/midi/include/amidi/AMidi.h b/media/native/midi/include/amidi/AMidi.h
index cbe410f..76dec0f 100644
--- a/media/native/midi/include/amidi/AMidi.h
+++ b/media/native/midi/include/amidi/AMidi.h
@@ -41,8 +41,6 @@
 typedef struct AMidiInputPort AMidiInputPort;
 typedef struct AMidiOutputPort AMidiOutputPort;
 
-#define AMIDI_API __attribute__((visibility("default")))
-
 /*
  * Message Op Codes. Used to parse MIDI data packets
  */
@@ -61,6 +59,8 @@
     AMIDI_DEVICE_TYPE_BLUETOOTH = 3 /* A MIDI device connected via BlueTooth */
 };
 
+#if __ANDROID_API__ >= 29
+
 /*
  * Device API
  */
@@ -78,7 +78,7 @@
  *    is null or already connected to a native AMidiDevice
   *  @see AMEDIA_ERROR_UNKNOWN - an unknown error occurred.
  */
-media_status_t AMIDI_API AMidiDevice_fromJava(
+media_status_t AMidiDevice_fromJava(
         JNIEnv *env, jobject midiDeviceObj, AMidiDevice **outDevicePtrPtr) __INTRODUCED_IN(29);
 
 /**
@@ -93,7 +93,7 @@
  *  @see AMEDIA_ERROR_INVALID_OBJECT - the JNI interface initialization to the associated java MidiDevice failed.
  *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
-media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29);
+media_status_t AMidiDevice_release(const AMidiDevice *midiDevice) __INTRODUCED_IN(29);
 
 /**
  * Gets the MIDI device type.
@@ -108,7 +108,7 @@
  *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown error.
  */
-int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29);
+int32_t AMidiDevice_getType(const AMidiDevice *device) __INTRODUCED_IN(29);
 
 /**
  * Gets the number of input (sending) ports available on the specified MIDI device.
@@ -120,7 +120,7 @@
  *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
  *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
-ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
+ssize_t AMidiDevice_getNumInputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
 
 /**
  * Gets the number of output (receiving) ports available on the specified MIDI device.
@@ -132,7 +132,7 @@
  *  @see AMEDIA_ERROR_INVALID_PARAMETER - the device parameter is NULL.
  *  @see AMEDIA_ERROR_UNKNOWN - couldn't retrieve the device info.
  */
-ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
+ssize_t AMidiDevice_getNumOutputPorts(const AMidiDevice *device) __INTRODUCED_IN(29);
 
 /*
  * API for receiving data from the Output port of a device.
@@ -150,7 +150,7 @@
  * @return AMEDIA_OK, or a negative error code:
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
-media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
                              AMidiOutputPort **outOutputPortPtr) __INTRODUCED_IN(29);
 
 /**
@@ -158,7 +158,7 @@
  *
  * @param outputPort    The native API port identifier of the port.
  */
-void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29);
+void AMidiOutputPort_close(const AMidiOutputPort *outputPort) __INTRODUCED_IN(29);
 
 /**
  * Receives the next pending MIDI message. To retrieve all pending messages, the client should
@@ -178,7 +178,7 @@
  * @return the number of messages received (either 0 or 1), or a negative error code:
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
-ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
+ssize_t AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
          uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *outTimestampPtr) __INTRODUCED_IN(29);
 
 /*
@@ -197,7 +197,7 @@
  * @return AMEDIA_OK, or a negative error code:
  *  @see AMEDIA_ERROR_UNKNOWN - Unknown Error.
  */
-media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
+media_status_t AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
                             AMidiInputPort **outInputPortPtr) __INTRODUCED_IN(29);
 
 /**
@@ -210,7 +210,7 @@
  * @return The number of bytes sent, which could be less than specified or a negative error code:
  * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
  */
-ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
+ssize_t AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
                    size_t numBytes) __INTRODUCED_IN(29);
 
 /**
@@ -224,7 +224,7 @@
  * @return The number of bytes sent, which could be less than specified or a negative error code:
  * @see AMEDIA_ERROR_INVALID_PARAMETER - The specified port was NULL, the specified buffer was NULL.
  */
-ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
+ssize_t AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
         const uint8_t *buffer, size_t numBytes, int64_t timestamp) __INTRODUCED_IN(29);
 
 /**
@@ -238,14 +238,16 @@
  * @see AMEDIA_ERROR_UNSUPPORTED - The FLUSH command couldn't
  * be sent.
  */
-media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
+media_status_t AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
 
 /**
  * Closes the input port.
  *
  * @param inputPort Identifies the input (sending) port to close.
  */
-void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
+void AMidiInputPort_close(const AMidiInputPort *inputPort) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
 
 #ifdef __cplusplus
 }
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index 2cdc6a8..1267aa8 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -32,19 +32,35 @@
     public static final String ROUTE_NAME1 = "Sample Route 1";
     public static final String ROUTE_ID2 = "route_id2";
     public static final String ROUTE_NAME2 = "Sample Route 2";
+
+    public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category";
+    public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route";
+
     public static final String ACTION_REMOVE_ROUTE =
             "com.android.mediarouteprovider.action_remove_route";
 
+    public static final String CATEGORY_SAMPLE =
+            "com.android.mediarouteprovider.CATEGORY_SAMPLE";
+    public static final String CATEGORY_SPECIAL =
+            "com.android.mediarouteprovider.CATEGORY_SPECIAL";
+
     Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
 
     private void initializeRoutes() {
         MediaRoute2Info route1 = new MediaRoute2Info.Builder(ROUTE_ID1, ROUTE_NAME1)
+                .addSupportedCategory(CATEGORY_SAMPLE)
                 .build();
         MediaRoute2Info route2 = new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2)
+                .addSupportedCategory(CATEGORY_SAMPLE)
                 .build();
-
+        MediaRoute2Info routeSpecial =
+                new MediaRoute2Info.Builder(ROUTE_ID_SPECIAL_CATEGORY, ROUTE_NAME_SPECIAL_CATEGORY)
+                        .addSupportedCategory(CATEGORY_SAMPLE)
+                        .addSupportedCategory(CATEGORY_SPECIAL)
+                        .build();
         mRoutes.put(route1.getId(), route1);
         mRoutes.put(route2.getId(), route2);
+        mRoutes.put(routeSpecial.getId(), routeSpecial);
     }
 
     @Override
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 03b43e2..4282a5bc 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -58,9 +58,18 @@
     public static final String ROUTE_NAME1 = "Sample Route 1";
     public static final String ROUTE_ID2 = "route_id2";
     public static final String ROUTE_NAME2 = "Sample Route 2";
+
+    public static final String ROUTE_ID_SPECIAL_CATEGORY = "route_special_category";
+    public static final String ROUTE_NAME_SPECIAL_CATEGORY = "Special Category Route";
+
     public static final String ACTION_REMOVE_ROUTE =
             "com.android.mediarouteprovider.action_remove_route";
 
+    public static final String CATEGORY_SAMPLE =
+            "com.android.mediarouteprovider.CATEGORY_SAMPLE";
+    public static final String CATEGORY_SPECIAL =
+            "com.android.mediarouteprovider.CATEGORY_SPECIAL";
+
     private static final int TIMEOUT_MS = 5000;
 
     private Context mContext;
@@ -69,12 +78,13 @@
     private Executor mExecutor;
     private String mPackageName;
 
-    private static final List<String> TEST_CONTROL_CATEGORIES = new ArrayList();
-    private static final String CONTROL_CATEGORY_1 = "android.media.mediarouter.MEDIA1";
-    private static final String CONTROL_CATEGORY_2 = "android.media.mediarouter.MEDIA2";
+    private static final List<String> CONTROL_CATEGORIES_ALL = new ArrayList();
+    private static final List<String> CONTROL_CATEGORIES_SPECIAL = new ArrayList();
     static {
-        TEST_CONTROL_CATEGORIES.add(CONTROL_CATEGORY_1);
-        TEST_CONTROL_CATEGORIES.add(CONTROL_CATEGORY_2);
+        CONTROL_CATEGORIES_ALL.add(CATEGORY_SAMPLE);
+        CONTROL_CATEGORIES_ALL.add(CATEGORY_SPECIAL);
+
+        CONTROL_CATEGORIES_SPECIAL.add(CATEGORY_SPECIAL);
     }
 
     @Before
@@ -125,7 +135,7 @@
         // (Control requests shouldn't be used in this way.)
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
                 (Runnable) () -> {
-                    mRouter.addCallback(TEST_CONTROL_CATEGORIES, mExecutor, mockRouterCallback);
+                    mRouter.addCallback(CONTROL_CATEGORIES_ALL, mExecutor, mockRouterCallback);
                     mRouter.sendControlRequest(
                             new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2).build(),
                             new Intent(ACTION_REMOVE_ROUTE));
@@ -138,8 +148,11 @@
         mManager.removeCallback(mockCallback);
     }
 
+    /**
+     * Tests if we get proper routes for application that has special control category.
+     */
     @Test
-    public void controlCategoryTest() throws Exception {
+    public void testControlCategory() throws Exception {
         MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
         mManager.addCallback(mExecutor, mockCallback);
 
@@ -147,12 +160,19 @@
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
                 () -> {
-                    mRouter.addCallback(TEST_CONTROL_CATEGORIES, mExecutor, mockRouterCallback);
+                    mRouter.addCallback(CONTROL_CATEGORIES_SPECIAL,
+                            mExecutor, mockRouterCallback);
                     mRouter.removeCallback(mockRouterCallback);
                 }
         );
-        verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
-                .onControlCategoriesChanged(mPackageName, TEST_CONTROL_CATEGORIES);
+        verify(mockCallback, timeout(TIMEOUT_MS))
+                .onRouteListChanged(argThat(routes -> routes.size() > 0));
+
+        Map<String, MediaRoute2Info> routes =
+                createRouteMap(mManager.getAvailableRoutes(mPackageName));
+
+        Assert.assertEquals(1, routes.size());
+        Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
 
         mManager.removeCallback(mockCallback);
     }
@@ -164,7 +184,7 @@
         MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class);
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
                 () -> {
-                    mRouter.addCallback(TEST_CONTROL_CATEGORIES, mExecutor, mockRouterCallback);
+                    mRouter.addCallback(CONTROL_CATEGORIES_ALL, mExecutor, mockRouterCallback);
                 }
         );
 
@@ -197,10 +217,10 @@
         mManager.removeCallback(managerCallback);
     }
 
-    @Test
     /**
      * Tests selecting and unselecting routes of a single provider.
      */
+    @Test
     public void testSingleProviderSelect() {
         MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
         MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class);
@@ -208,7 +228,7 @@
         mManager.addCallback(mExecutor, managerCallback);
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
                 () -> {
-                    mRouter.addCallback(TEST_CONTROL_CATEGORIES, mExecutor, routerCallback);
+                    mRouter.addCallback(CONTROL_CATEGORIES_ALL, mExecutor, routerCallback);
                 }
         );
         verify(managerCallback, timeout(TIMEOUT_MS))
@@ -218,7 +238,8 @@
                 createRouteMap(mManager.getAvailableRoutes(mPackageName));
 
         mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1));
-        verify(managerCallback, timeout(TIMEOUT_MS))
+        verify(managerCallback, timeout(TIMEOUT_MS)
+        )
                 .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID1, routeInfo.getId())
                         && TextUtils.equals(routeInfo.getClientPackageName(), mPackageName)));
 
diff --git a/packages/CarSystemUI/res/values-night/colors.xml b/packages/CarSystemUI/res/values-night/colors.xml
index dad94a8..a2edd7dc 100644
--- a/packages/CarSystemUI/res/values-night/colors.xml
+++ b/packages/CarSystemUI/res/values-night/colors.xml
@@ -19,6 +19,9 @@
     <color name="status_bar_background_color">#ff000000</color>
     <color name="system_bar_background_opaque">#ff0c1013</color>
 
+    <!-- The background color of the notification shade -->
+    <color name="notification_shade_background_color">#E0000000</color>
+    
     <!-- The color of the ripples on the untinted notifications -->
     <color name="notification_ripple_untinted_color">@color/ripple_material_dark</color>
 </resources>
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index e13c940..e0ae4566 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -35,7 +35,7 @@
     <drawable name="system_bar_background">@android:color/transparent</drawable>
 
     <!-- The background color of the notification shade -->
-    <color name="notification_shade_background_color">#DD000000</color>
+    <color name="notification_shade_background_color">#D6000000</color>
 
     <!-- The background color of the car volume dialog -->
     <color name="car_volume_dialog_background_color">@color/system_bar_background_opaque</color>
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 7592bd2..fb422af 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -114,10 +114,10 @@
     <!-- Car notification shade-->
     <dimen name="notification_shade_handle_bar_height">10dp</dimen>
     <dimen name="notification_shade_handle_bar_radius">20dp</dimen>
-    <dimen name="notification_shade_handle_bar_margin_start">500dp</dimen>
-    <dimen name="notification_shade_handle_bar_margin_end">500dp</dimen>
+    <dimen name="notification_shade_handle_bar_margin_start">200dp</dimen>
+    <dimen name="notification_shade_handle_bar_margin_end">200dp</dimen>
     <dimen name="notification_shade_handle_bar_margin_top">20dp</dimen>
     <dimen name="notification_shade_handle_bar_margin_bottom">10dp</dimen>
-    <dimen name="notification_shade_list_padding_bottom">0dp</dimen>
+    <dimen name="notification_shade_list_padding_bottom">50dp</dimen>
 
 </resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
index 0f4cf21..0421c3b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.view.Display;
@@ -122,7 +123,7 @@
                         new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), UserHandle.CURRENT);
             });
 
-            if (longPressIntentString != null) {
+            if (longPressIntentString != null && (Build.IS_ENG || Build.IS_USERDEBUG)) {
                 final Intent longPressIntent = Intent.parseUri(longPressIntentString,
                         Intent.URI_INTENT_SCHEME);
                 setOnLongClickListener(v -> {
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
index 095e2e9..05a41e6 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.car;
 
 import android.content.Context;
-import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -75,40 +74,13 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (mStatusBarWindowTouchListener != null) {
-            boolean shouldConsumeEvent = shouldConsumeNotificationButtonEvent(ev);
             // Forward touch events to the status bar window so it can drag
             // windows if required (Notification shade)
             mStatusBarWindowTouchListener.onTouch(this, ev);
-            // return true if child views should not receive this event.
-            if (shouldConsumeEvent) {
-                return true;
-            }
         }
         return super.onInterceptTouchEvent(ev);
     }
 
-    /**
-     * If the motion event is over top of the notification button while the notification
-     * panel is open, we need the statusbar touch listeners handle the event instead of the button.
-     * Since the statusbar listener will trigger a close of the notification panel before the
-     * any button click events are fired this will prevent reopening the panel.
-     *
-     * Note: we can't use requestDisallowInterceptTouchEvent because the gesture detector will
-     * always receive the ACTION_DOWN and thus think a longpress happened if no other events are
-     * received
-     *
-     * @return true if the notification button should not receive the event
-     */
-    private boolean shouldConsumeNotificationButtonEvent(MotionEvent ev) {
-        if (mNotificationsButton == null || !mCarStatusBar.isNotificationPanelOpen()) {
-            return false;
-        }
-        Rect notificationButtonLocation = new Rect();
-        mNotificationsButton.getHitRect(notificationButtonLocation);
-        return notificationButtonLocation.contains((int) ev.getX(), (int) ev.getY());
-    }
-
-
     void setStatusBar(CarStatusBar carStatusBar) {
         mCarStatusBar = carStatusBar;
     }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 9de4ef5..c0dcbbc 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -69,13 +70,9 @@
                 R.styleable.CarNavigationButton_unselectedAlpha, mUnselectedAlpha);
         mSelectedIconResourceId = typedArray.getResourceId(
                 R.styleable.CarNavigationButton_selectedIcon, mIconResourceId);
+        mIconResourceId = typedArray.getResourceId(
+                R.styleable.CarNavigationButton_icon, 0);
         typedArray.recycle();
-
-        // ImageView attrs
-        TypedArray a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.ImageView);
-        mIconResourceId = a.getResourceId(com.android.internal.R.styleable.ImageView_src, 0);
-        a.recycle();
     }
 
 
@@ -114,7 +111,7 @@
         }
 
         try {
-            if (mLongIntent != null) {
+            if (mLongIntent != null && (Build.IS_ENG || Build.IS_USERDEBUG)) {
                 final Intent intent = Intent.parseUri(mLongIntent, Intent.URI_INTENT_SCHEME);
                 setOnLongClickListener(v -> {
                     try {
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 812adf9..b1f9797 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -27,6 +27,7 @@
 import android.car.drivingstate.CarUxRestrictionsManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -1072,9 +1073,25 @@
             // shade is visible to the user. When the notification shade is completely open then
             // alpha value will be 1.
             float alpha = (float) height / mNotificationView.getHeight();
-            Drawable background = mNotificationView.getBackground();
+            Drawable background = mNotificationView.getBackground().mutate();
 
             background.setAlpha((int) (alpha * 255));
+            mNotificationView.setBackground(background);
+        }
+    }
+
+    @Override
+    public void onConfigChanged(Configuration newConfig) {
+        super.onConfigChanged(newConfig);
+
+        int uiModeNightMask = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+
+        boolean dayNightModeChanged = uiModeNightMask == Configuration.UI_MODE_NIGHT_YES
+                || uiModeNightMask == Configuration.UI_MODE_NIGHT_NO;
+
+        if (dayNightModeChanged) {
+            mNotificationView.setBackgroundColor(
+                    mContext.getColor(R.color.notification_shade_background_color));
         }
     }
 
@@ -1232,13 +1249,6 @@
             setNotificationViewClipBounds((int) event2.getRawY());
             return true;
         }
-
-        @Override
-        public void onLongPress(MotionEvent e) {
-            mClosingVelocity = DEFAULT_FLING_VELOCITY;
-            close();
-            super.onLongPress(e);
-        }
     }
 
     /**
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index 03eb0d9..0ef4654 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -65,6 +65,9 @@
 
 LOCAL_MULTILIB := both
 LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
+# Explicitly uncompress native libs rather than letting the build system doing it and destroy the
+# v2/v3 signature.
+LOCAL_USE_EMBEDDED_NATIVE_LIBS := true
 
 LOCAL_USE_AAPT2 := true
 
diff --git a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
index 96046ad..35de8ef 100644
--- a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
@@ -19,5 +19,5 @@
     <string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
     <string name="storage_description" msgid="8541974407321172792">"Armazenamento local"</string>
     <string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
-    <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
+    <string name="root_documents" msgid="4051252304075469250">"Docs"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 5ad9b01..3d9a78e 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -76,7 +76,7 @@
     <item msgid="3422726142222090896">"avrcp16"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="7065842274271279580">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+    <item msgid="7065842274271279580">"सिस्टम से चुने जाने का उपयोग करें (डिफ़ॉल्ट)"</item>
     <item msgid="7539690996561263909">"SBC"</item>
     <item msgid="686685526567131661">"AAC"</item>
     <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ऑडियो"</item>
@@ -86,7 +86,7 @@
     <item msgid="3304843301758635896">"वैकल्पिक कोडेक अक्षम करें"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="5062108632402595000">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+    <item msgid="5062108632402595000">"सिस्टम से चुने जाने का उपयोग करें (डिफ़ॉल्ट)"</item>
     <item msgid="6898329690939802290">"SBC"</item>
     <item msgid="6839647709301342559">"AAC"</item>
     <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ऑडियो"</item>
@@ -96,38 +96,38 @@
     <item msgid="741805482892725657">"वैकल्पिक कोडेक अक्षम करें"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="3093023430402746802">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+    <item msgid="3093023430402746802">"सिस्टम से चुने जाने का उपयोग करें (डिफ़ॉल्ट)"</item>
     <item msgid="8895532488906185219">"44.1 kHz"</item>
     <item msgid="2909915718994807056">"48.0 kHz"</item>
     <item msgid="3347287377354164611">"88.2 kHz"</item>
     <item msgid="1234212100239985373">"96.0 kHz"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="3214516120190965356">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+    <item msgid="3214516120190965356">"सिस्टम से चुने जाने का उपयोग करें (डिफ़ॉल्ट)"</item>
     <item msgid="4482862757811638365">"44.1 kHz"</item>
     <item msgid="354495328188724404">"48.0 kHz"</item>
     <item msgid="7329816882213695083">"88.2 kHz"</item>
     <item msgid="6967397666254430476">"96.0 kHz"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="2684127272582591429">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+    <item msgid="2684127272582591429">"सिस्टम से चुने जाने का उपयोग करें (डिफ़ॉल्ट)"</item>
     <item msgid="5618929009984956469">"16 बिट/नमूना"</item>
     <item msgid="3412640499234627248">"24 बिट/नमूना"</item>
     <item msgid="121583001492929387">"32 बिट/नमूना"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="1081159789834584363">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+    <item msgid="1081159789834584363">"सिस्टम से चुने जाने का उपयोग करें (डिफ़ॉल्ट)"</item>
     <item msgid="4726688794884191540">"16 बिट/नमूना"</item>
     <item msgid="305344756485516870">"24 बिट/नमूना"</item>
     <item msgid="244568657919675099">"32 बिट/नमूना"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="5226878858503393706">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+    <item msgid="5226878858503393706">"सिस्टम से चुने जाने का उपयोग करें (डिफ़ॉल्ट)"</item>
     <item msgid="4106832974775067314">"मोनो"</item>
     <item msgid="5571632958424639155">"स्टीरियो"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="4118561796005528173">"सिस्टम चयन का उपयोग करें (डिफ़ॉल्ट)"</item>
+    <item msgid="4118561796005528173">"सिस्टम चुनाव का उपयोग करें (डिफ़ॉल्ट)"</item>
     <item msgid="8900559293912978337">"मोनो"</item>
     <item msgid="8883739882299884241">"स्टीरियो"</item>
   </string-array>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 5d512a8..238eba5 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -361,7 +361,7 @@
     <string name="runningservices_settings_summary" msgid="854608995821032748">"इस समय चल रही सेवाओं को देखें और नियंत्रित करें"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"वेबव्यू लागू करें"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"वेबव्यू सेट करें"</string>
-    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"यह चयन अब मान्य नहीं है. पुनः प्रयास करें."</string>
+    <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"यह चुनाव अब मान्य नहीं है. दोबारा कोशिश करें."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"फ़ाइल आधारित सुरक्षित करने के तरीके में बदलें"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रूपांतरित करें..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"फ़ाइल पहले से एन्क्रिप्ट की हुई है"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index fd45cb0..f1934c3 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -248,7 +248,7 @@
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string>
     <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"ब्याट्रीको खपत कम गरी नेटवर्कको कार्यसम्पादनमा सुधार गर्दछ"</string>
-    <string name="wifi_metered_label" msgid="4514924227256839725">"मिटर गरिएको जडान भनी चिन्ह लगाइएको"</string>
+    <string name="wifi_metered_label" msgid="4514924227256839725">"सशुल्क वाइफाइ"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"मिटर नगरिएको"</string>
     <string name="select_logd_size_title" msgid="7433137108348553508">"लगर बफर आकारहरू"</string>
     <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"लग बफर प्रति लगर आकार चयन गर्नुहोस्"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 9a41f1d..9672fea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -663,7 +663,8 @@
         final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
         removeExistingRestrictedSpans(sb);
         if (disabled) {
-            final int disabledColor = context.getColor(R.color.disabled_text_color);
+            final int disabledColor = Utils.getDisabled(context,
+                    textView.getCurrentTextColor());
             sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
             textView.setCompoundDrawables(null, null, getRestrictedPadlock(context), null);
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index d32e85f..14f233d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -35,8 +35,6 @@
 
 public class Utils {
 
-    private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
-    private static final String NEW_MODE_KEY = "NEW_MODE";
     @VisibleForTesting
     static final String STORAGE_MANAGER_ENABLED_PROPERTY =
             "ro.storage_manager.enabled";
@@ -56,24 +54,11 @@
 
     public static void updateLocationEnabled(Context context, boolean enabled, int userId,
             int source) {
-        LocationManager locationManager = context.getSystemService(LocationManager.class);
-
         Settings.Secure.putIntForUser(
                 context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source,
                 userId);
 
-        Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION);
-        final int oldMode = locationManager.isLocationEnabled()
-                ? Settings.Secure.LOCATION_MODE_ON
-                : Settings.Secure.LOCATION_MODE_OFF;
-        final int newMode = enabled
-                ? Settings.Secure.LOCATION_MODE_ON
-                : Settings.Secure.LOCATION_MODE_OFF;
-        intent.putExtra(CURRENT_MODE_KEY, oldMode);
-        intent.putExtra(NEW_MODE_KEY, newMode);
-        context.sendBroadcastAsUser(
-                intent, UserHandle.of(userId), android.Manifest.permission.WRITE_SECURE_SETTINGS);
-
+        LocationManager locationManager = context.getSystemService(LocationManager.class);
         locationManager.setLocationEnabledForUser(enabled, UserHandle.of(userId));
     }
 
@@ -218,6 +203,13 @@
         return list.getDefaultColor();
     }
 
+    /**
+     * This method computes disabled color from normal color
+     *
+     * @param context
+     * @param inputColor normal color.
+     * @return disabled color.
+     */
     @ColorInt
     public static int getDisabled(Context context, int inputColor) {
         return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor);
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
index b15ea98..23e29493 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
@@ -18,11 +18,11 @@
 
 import android.content.Context;
 import android.net.NetworkTemplate;
-import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
 /**
  * Utils class for data usage
  */
@@ -34,19 +34,25 @@
      */
     public static NetworkTemplate getMobileTemplate(Context context, int subId) {
         final TelephonyManager telephonyManager = context.getSystemService(
-                TelephonyManager.class).createForSubscriptionId(subId);
+                TelephonyManager.class);
         final SubscriptionManager subscriptionManager = context.getSystemService(
                 SubscriptionManager.class);
-        final SubscriptionInfo info = subscriptionManager.getActiveSubscriptionInfo(subId);
         final NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll(
                 telephonyManager.getSubscriberId(subId));
 
-        if (info == null) {
+        if (!subscriptionManager.isActiveSubId(subId)) {
             Log.i(TAG, "Subscription is not active: " + subId);
             return mobileAll;
         }
 
-        // Use old API to build networkTemplate
-        return NetworkTemplate.normalize(mobileAll, telephonyManager.getMergedSubscriberIds());
+        final String[] mergedSubscriberIds = telephonyManager.createForSubscriptionId(subId)
+                .getMergedSubscriberIdsFromGroup();
+
+        if (ArrayUtils.isEmpty(mergedSubscriberIds)) {
+            Log.i(TAG, "mergedSubscriberIds is null.");
+            return mobileAll;
+        }
+
+        return NetworkTemplate.normalize(mobileAll, mergedSubscriberIds);
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ColorUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/ColorUtil.java
new file mode 100644
index 0000000..c54b471
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ColorUtil.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 com.android.settingslib.utils;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+
+/** Utility class for getting color attribute **/
+public class ColorUtil {
+
+    /**
+     * Returns android:disabledAlpha value in context
+     */
+    public static float getDisabledAlpha(Context context) {
+        final TypedArray ta = context.obtainStyledAttributes(
+                new int[]{android.R.attr.disabledAlpha});
+        final float alpha = ta.getFloat(0, 0);
+        ta.recycle();
+        return alpha;
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 4d76e44..fc69b1a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -15,17 +15,13 @@
  */
 package com.android.settingslib;
 
-import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
-
 import static com.android.settingslib.Utils.STORAGE_MANAGER_ENABLED_PROPERTY;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
@@ -45,7 +41,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatcher;
-import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -85,15 +80,11 @@
     }
 
     @Test
-    public void testUpdateLocationEnabled_sendBroadcast() {
+    public void testUpdateLocationEnabled() {
         int currentUserId = ActivityManager.getCurrentUser();
         Utils.updateLocationEnabled(mContext, true, currentUserId,
                 Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
 
-        verify(mContext).sendBroadcastAsUser(
-            argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)),
-            ArgumentMatchers.eq(UserHandle.of(currentUserId)),
-            ArgumentMatchers.eq(WRITE_SECURE_SETTINGS));
         assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN))
                 .isEqualTo(Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
index 821c0b3..5cae611 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -37,13 +38,13 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
 public class DataUsageUtilsTest {
 
     private static final int SUB_ID = 1;
+    private static final int SUB_ID_2 = 2;
     private static final String SUBSCRIBER_ID = "Test Subscriber";
     private static final String SUBSCRIBER_ID_2 = "Test Subscriber 2";
 
@@ -66,21 +67,16 @@
 
         mContext = spy(RuntimeEnvironment.application);
         when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
-        when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
         when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
         when(mTelephonyManager.getSubscriberId(SUB_ID)).thenReturn(SUBSCRIBER_ID);
-        when(mTelephonyManager.getMergedSubscriberIds()).thenReturn(
-                new String[]{SUBSCRIBER_ID, SUBSCRIBER_ID_2});
-
-        mInfos = new ArrayList<>();
-        mInfos.add(mInfo1);
-        mInfos.add(mInfo2);
-        when(mSubscriptionManager.getSubscriptionsInGroup(mParcelUuid)).thenReturn(mInfos);
+        when(mTelephonyManager.getSubscriberId(SUB_ID_2)).thenReturn(SUBSCRIBER_ID_2);
+        when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+        when(mSubscriptionManager.isActiveSubId(anyInt())).thenReturn(true);
     }
 
     @Test
     public void getMobileTemplate_infoNull_returnMobileAll() {
-        when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(null);
+        when(mSubscriptionManager.isActiveSubId(SUB_ID)).thenReturn(false);
 
         final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
         assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
@@ -88,9 +84,23 @@
     }
 
     @Test
-    public void getMobileTemplate_infoExisted_returnMobileMerged() {
+    public void getMobileTemplate_groupUuidNull_returnMobileAll() {
+        when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(mInfo1);
+        when(mInfo1.getGroupUuid()).thenReturn(null);
+        when(mTelephonyManager.getMergedSubscriberIdsFromGroup())
+                .thenReturn(new String[] {SUBSCRIBER_ID});
+
+        final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
+        assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
+        assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isFalse();
+    }
+
+    @Test
+    public void getMobileTemplate_groupUuidExist_returnMobileMerged() {
         when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(mInfo1);
         when(mInfo1.getGroupUuid()).thenReturn(mParcelUuid);
+        when(mTelephonyManager.getMergedSubscriberIdsFromGroup())
+                .thenReturn(new String[] {SUBSCRIBER_ID, SUBSCRIBER_ID_2});
 
         final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
         assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
index 044ec86..5617331 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/GenerationRegistry.java
@@ -22,14 +22,16 @@
 import android.util.MemoryIntArray;
 import android.util.Slog;
 import android.util.SparseIntArray;
+
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.IOException;
 
 /**
- * This class tracks changes for global/secure/system tables on a
- * per user basis and updates a shared memory region which client
- * processes can read to determine if their local caches are stale,
+ * This class tracks changes for config/global/secure/system tables
+ * on a per user basis and updates a shared memory region which
+ * client processes can read to determine if their local caches are
+ * stale.
  */
 final class GenerationRegistry {
     private static final String LOG_TAG = "GenerationRegistry";
@@ -114,11 +116,12 @@
     @GuardedBy("mLock")
     private MemoryIntArray getBackingStoreLocked() {
         if (mBackingStore == null) {
-            // One for the global table, two for system and secure tables for a
-            // managed profile (managed profile is not included in the max user
-            // count), ten for partially deleted users if users are quickly removed,
-            // and twice max user count for system and secure.
-            final int size = 1 + 2 + 10 + 2 * UserManager.getMaxSupportedUsers();
+            // One for the config table, one for the global table, two for system
+            // and secure tables for a managed profile (managed profile is not
+            // included in the max user count), ten for partially deleted users if
+            // users are quickly removed, and twice max user count for system and
+            // secure.
+            final int size = 1 + 1 + 2 + 10 + 2 * UserManager.getMaxSupportedUsers();
             try {
                 mBackingStore = new MemoryIntArray(size);
                 if (DEBUG) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 9d398b5..7d56868 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -16,7 +16,6 @@
 
 package com.android.providers.settings;
 
-import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.backup.BackupAgentHelper;
 import android.app.backup.BackupDataInput;
@@ -41,6 +40,7 @@
 import android.util.BackupUtils;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.BufferedOutputStream;
@@ -56,6 +56,7 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.zip.CRC32;
 
 /**
@@ -241,6 +242,8 @@
         HashSet<String> movedToGlobal = new HashSet<String>();
         Settings.System.getMovedToGlobalSettings(movedToGlobal);
         Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
+        Set<String> movedToSecure = getMovedToSecureSettings();
+
         byte[] restoredWifiSupplicantData = null;
         byte[] restoredWifiIpConfigData = null;
 
@@ -259,16 +262,17 @@
 
             switch (key) {
                 case KEY_SYSTEM :
-                    restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
+                    restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal,
+                            movedToSecure);
                     mSettingsHelper.applyAudioSettings();
                     break;
 
                 case KEY_SECURE :
-                    restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
+                    restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal, null);
                     break;
 
                 case KEY_GLOBAL :
-                    restoreSettings(data, Settings.Global.CONTENT_URI, null);
+                    restoreSettings(data, Settings.Global.CONTENT_URI, null, movedToSecure);
                     break;
 
                 case KEY_WIFI_SUPPLICANT :
@@ -347,20 +351,22 @@
             HashSet<String> movedToGlobal = new HashSet<String>();
             Settings.System.getMovedToGlobalSettings(movedToGlobal);
             Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
+            Set<String> movedToSecure = getMovedToSecureSettings();
 
             // system settings data first
             int nBytes = in.readInt();
             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
             byte[] buffer = new byte[nBytes];
             in.readFully(buffer, 0, nBytes);
-            restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal);
+            restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal,
+                    movedToSecure);
 
             // secure settings
             nBytes = in.readInt();
             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
             if (nBytes > buffer.length) buffer = new byte[nBytes];
             in.readFully(buffer, 0, nBytes);
-            restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal);
+            restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal, null);
 
             // Global only if sufficiently new
             if (version >= FULL_BACKUP_ADDED_GLOBAL) {
@@ -369,7 +375,8 @@
                 if (nBytes > buffer.length) buffer = new byte[nBytes];
                 in.readFully(buffer, 0, nBytes);
                 movedToGlobal.clear();  // no redirection; this *is* the global namespace
-                restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal);
+                restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal,
+                        movedToSecure);
             }
 
             // locale
@@ -440,6 +447,13 @@
         }
     }
 
+    private Set<String> getMovedToSecureSettings() {
+        Set<String> movedToSecureSettings = new HashSet<>();
+        Settings.Global.getMovedToSecureSettings(movedToSecureSettings);
+        Settings.System.getMovedToSecureSettings(movedToSecureSettings);
+        return movedToSecureSettings;
+    }
+
     private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
         long[] stateChecksums = new long[STATE_SIZE];
 
@@ -564,7 +578,7 @@
     }
 
     private void restoreSettings(BackupDataInput data, Uri contentUri,
-            HashSet<String> movedToGlobal) {
+            HashSet<String> movedToGlobal, Set<String> movedToSecure) {
         byte[] settings = new byte[data.getDataSize()];
         try {
             data.readEntityData(settings, 0, settings.length);
@@ -572,11 +586,11 @@
             Log.e(TAG, "Couldn't read entity data");
             return;
         }
-        restoreSettings(settings, settings.length, contentUri, movedToGlobal);
+        restoreSettings(settings, settings.length, contentUri, movedToGlobal, movedToSecure);
     }
 
     private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
-            HashSet<String> movedToGlobal) {
+            HashSet<String> movedToGlobal, Set<String> movedToSecure) {
         if (DEBUG) {
             Log.i(TAG, "restoreSettings: " + contentUri);
         }
@@ -586,15 +600,15 @@
         final String[] whitelist;
         Map<String, Validator> validators = null;
         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
-            whitelist = concat(Settings.Secure.SETTINGS_TO_BACKUP,
+            whitelist = ArrayUtils.concatElements(String.class, Settings.Secure.SETTINGS_TO_BACKUP,
                     Settings.Secure.LEGACY_RESTORE_SETTINGS);
             validators = Settings.Secure.VALIDATORS;
         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
-            whitelist = concat(Settings.System.SETTINGS_TO_BACKUP,
+            whitelist = ArrayUtils.concatElements(String.class, Settings.System.SETTINGS_TO_BACKUP,
                     Settings.System.LEGACY_RESTORE_SETTINGS);
             validators = Settings.System.VALIDATORS;
         } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
-            whitelist = concat(Settings.Global.SETTINGS_TO_BACKUP,
+            whitelist = ArrayUtils.concatElements(String.class, Settings.Global.SETTINGS_TO_BACKUP,
                     Settings.Global.LEGACY_RESTORE_SETTINGS);
             validators = Settings.Global.VALIDATORS;
         } else {
@@ -651,9 +665,14 @@
                 continue;
             }
 
-            final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
-                    ? Settings.Global.CONTENT_URI
-                    : contentUri;
+            final Uri destination;
+            if (movedToGlobal != null && movedToGlobal.contains(key)) {
+                destination = Settings.Global.CONTENT_URI;
+            } else if (movedToSecure != null && movedToSecure.contains(key)) {
+                destination = Settings.Secure.CONTENT_URI;
+            } else {
+                destination = contentUri;
+            }
             settingsHelper.restoreValue(this, cr, contentValues, destination, key, value,
                     mRestoredFromSdkInt);
 
@@ -672,18 +691,6 @@
         return (validator != null) && validator.validate(value);
     }
 
-    private final String[] concat(String[] first, @Nullable String[] second) {
-        if (second == null || second.length == 0) {
-            return first;
-        }
-        final int firstLen = first.length;
-        final int secondLen = second.length;
-        String[] both = new String[firstLen + secondLen];
-        System.arraycopy(first, 0, both, 0, firstLen);
-        System.arraycopy(second, 0, both, firstLen, secondLen);
-        return both;
-    }
-
     /**
      * Restores the owner info enabled and other settings in LockSettings.
      *
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index ea87870..c9bb83c 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -50,7 +50,6 @@
 import android.os.BugreportManager.BugreportCallback;
 import android.os.BugreportManager.BugreportCallback.BugreportErrorCode;
 import android.os.BugreportParams;
-import android.os.BugreportParams.BugreportMode;
 import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -354,7 +353,7 @@
         private final int mId;
         private final BugreportInfo mInfo;
 
-        BugreportCallbackImpl(String name, int id, @BugreportMode int bugreportType) {
+        BugreportCallbackImpl(String name, int id) {
             mId = id;
             // pid not used in this workflow, so setting default = 0
             mInfo = new BugreportInfo(mContext, mId, 0 /* pid */, name,
@@ -363,8 +362,6 @@
 
         @Override
         public void onProgress(float progress) {
-            // TODO: Make dumpstate call onProgress at 0% progress to trigger the
-            // progress notification instantly.
             checkProgressUpdated(mInfo, (int) progress);
         }
 
@@ -544,21 +541,21 @@
 
     private void startBugreportAPI(Intent intent) {
         mUsingBugreportApi = true;
-        String currentTimeStamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm").format(
+        String bugreportName = "bugreport-" + new SimpleDateFormat("yyyy-MM-dd-HH-mm").format(
                 new Date());
 
         // TODO(b/126862297): Make file naming same as dumpstate triggered bugreports
         ParcelFileDescriptor bugreportFd = createReadWriteFile(BUGREPORT_DIR,
-                "bugreport-" + currentTimeStamp + ".zip");
+                bugreportName + ".zip");
         if (bugreportFd == null) {
             Log.e(TAG, "Bugreport parcel file descriptor is null.");
             return;
         }
+        int bugreportType = intent.getIntExtra(EXTRA_BUGREPORT_TYPE,
+                BugreportParams.BUGREPORT_MODE_INTERACTIVE);
 
-        // TODO(b/126862297): Screenshot file is not needed for INTERACTIVE_BUGREPORTS
-        // Add logic to pass screenshot file only for specific bugreports.
         ParcelFileDescriptor screenshotFd = createReadWriteFile(BUGREPORT_DIR,
-                "screenshot-" + currentTimeStamp + ".png");
+                bugreportName + ".png");
         if (screenshotFd == null) {
             Log.e(TAG, "Screenshot parcel file descriptor is null.");
             // TODO(b/123617758): Delete bugreport file created above
@@ -572,16 +569,13 @@
         // Dumpstate increments PROPERTY_LAST_ID, may be racy if multiple calls
         // to dumpstate are made simultaneously.
         final int id = SystemProperties.getInt(PROPERTY_LAST_ID, 0) + 1;
-        int bugreportType = intent.getIntExtra(EXTRA_BUGREPORT_TYPE,
-                BugreportParams.BUGREPORT_MODE_INTERACTIVE);
         Log.i(TAG, "bugreport type = " + bugreportType
                 + " bugreport file fd: " + bugreportFd
                 + " screenshot file fd: " + screenshotFd);
 
-        BugreportCallbackImpl bugreportCallback = new BugreportCallbackImpl("bugreport-"
-                + currentTimeStamp, id, bugreportType);
+        BugreportCallbackImpl bugreportCallback = new BugreportCallbackImpl(bugreportName, id);
         try {
-            mBugreportManager.startBugreport(bugreportFd, null,
+            mBugreportManager.startBugreport(bugreportFd, screenshotFd,
                     new BugreportParams(bugreportType), executor, bugreportCallback);
             mBugreportInfos.put(bugreportCallback.mInfo.id, bugreportCallback.mInfo);
         } catch (RuntimeException e) {
@@ -963,14 +957,20 @@
             return;
         }
         final int max = -1; // this is to log metrics for dumpstate duration.
-        final File screenshotFile = new File(BUGREPORT_DIR, info.name + ".png");
-        // TODO(b/126862297): Screenshot file is not needed for INTERACTIVE_BUGREPORTS
-        // Add logic to null check screenshot file only for specific bugreports.
+        File screenshotFile = new File(BUGREPORT_DIR, info.name + ".png");
         if (screenshotFile == null) {
             // Should never happen, an id always has a file linked to it.
             Log.wtf(TAG, "Missing file " + screenshotFile.getPath() + " does not exist.");
             return;
         }
+        // If the screenshot file did not get populated implies this type of bugreport does not
+        // need the screenshot file; setting the file to null so that empty file doesnt get shared
+        if (screenshotFile.length() == 0) {
+            if (screenshotFile.delete()) {
+                Log.d(TAG, "screenshot file deleted successfully.");
+            }
+            screenshotFile = null;
+        }
         onBugreportFinished(id, bugreportFile, screenshotFile, info.title, info.description, max);
     }
 
@@ -2195,7 +2195,7 @@
             max = CAPPED_MAX;
         }
 
-        if (newPercentage > oldPercentage) {
+        if (progress == 0 || newPercentage > oldPercentage) {
             updateProgressInfo(info, progress, max);
         }
     }
diff --git a/packages/SystemUI/plugin/ExamplePlugin/Android.bp b/packages/SystemUI/plugin/ExamplePlugin/Android.bp
index a0eaf14..c6c80f3 100644
--- a/packages/SystemUI/plugin/ExamplePlugin/Android.bp
+++ b/packages/SystemUI/plugin/ExamplePlugin/Android.bp
@@ -11,4 +11,5 @@
 
     srcs: ["src/**/*.java"],
 
+    platform_apis: true,
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 28d5402..52ec1f0 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -30,7 +30,7 @@
  */
 @ProvidesInterface(version = FalsingManager.VERSION)
 public interface FalsingManager {
-    int VERSION = 1;
+    int VERSION = 2;
 
     void onSucccessfulUnlock();
 
@@ -103,4 +103,6 @@
     void onTouchEvent(MotionEvent ev, int width, int height);
 
     void dump(PrintWriter pw);
+
+    void cleanup();
 }
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index b23824e..8547bc8 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -22,7 +22,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="3171996292755059205">"Zaključavanje tastature"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3420548423949593123">"Upišite PIN"</string>
-    <string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"Upišite PUK kôd za SIM karticu i novi PIN"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"Upišite PUK za SIM i novi PIN kôd"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"PUK kôd za SIM karticu"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="8188243197504453830">"Novi PIN za SIM karticu"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="5790410752696806482"><font size="17">"Dodirnite da upišete lozinku"</font></string>
@@ -54,7 +54,7 @@
     <string name="keyguard_accessibility_pin_area" msgid="703175752097279029">"Prostor za PIN"</string>
     <string name="keyguard_accessibility_password" msgid="7695303207740941101">"Lozinka uređaja"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="912702510825058921">"Prostor za PIN za SIM karticu"</string>
-    <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"Prostor za PUK kôd za SIM karticu"</string>
+    <string name="keyguard_accessibility_sim_puk_area" msgid="136979425761438705">"Prostor za PUK za SIM"</string>
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Naredni alarm je podešen za <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Izbriši"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Onemogući eSIM karticu"</string>
@@ -116,7 +116,7 @@
       <item quantity="other">PUK kôd za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva.</item>
     </plurals>
     <string name="kg_password_pin_failed" msgid="8769990811451236223">"Korištenje PIN-a za SIM karticu nije uspjelo!"</string>
-    <string name="kg_password_puk_failed" msgid="1331621440873439974">"Korištenje PUK koda za SIM karticu nije uspjelo!"</string>
+    <string name="kg_password_puk_failed" msgid="1331621440873439974">"Korištenje PUK-a za SIM nije uspjelo!"</string>
     <string name="kg_pin_accepted" msgid="7637293533973802143">"Kôd je prihvaćen"</string>
     <string name="keyguard_carrier_default" msgid="4274828292998453695">"Nema mreže."</string>
     <string name="accessibility_ime_switch_button" msgid="2695096475319405612">"Promjena načina unosa"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 1d42f1f..e4b37d0 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -38,7 +38,7 @@
     <string name="keyguard_plugged_in" msgid="3161102098900158923">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="3684592786276709342">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me shpejtësi"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="509533586841478405">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet ngadalë"</string>
-    <string name="keyguard_low_battery" msgid="9218432555787624490">"Lidh ngarkuesin."</string>
+    <string name="keyguard_low_battery" msgid="9218432555787624490">"Lidh karikuesin."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"Shtyp \"Meny\" për të shkyçur."</string>
     <string name="keyguard_network_locked_message" msgid="6743537524631420759">"Rrjeti është i kyçur"</string>
     <string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"Nuk ka kartë SIM"</string>
diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
index c560d7e..e687cdf 100644
--- a/packages/SystemUI/res/layout/biometric_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -55,7 +55,8 @@
                     android:id="@+id/left_space"
                     android:layout_weight="1"
                     android:layout_width="0dp"
-                    android:layout_height="match_parent"/>
+                    android:layout_height="match_parent"
+                    android:contentDescription="@string/biometric_dialog_empty_space_description"/>
 
                     <LinearLayout
                         android:id="@+id/dialog"
@@ -177,7 +178,8 @@
                     android:id="@+id/right_space"
                     android:layout_weight="1"
                     android:layout_width="0dp"
-                    android:layout_height="match_parent" />
+                    android:layout_height="match_parent"
+                    android:contentDescription="@string/biometric_dialog_empty_space_description"/>
 
             </LinearLayout>
 
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 7fc2066..21c2c6b 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -46,6 +46,8 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:gravity="center"
+                android:paddingStart="@dimen/keyguard_indication_text_padding"
+                android:paddingEnd="@dimen/keyguard_indication_text_padding"
                 android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
                 android:visibility="gone" />
 
@@ -54,6 +56,8 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:gravity="center"
+                android:paddingStart="@dimen/keyguard_indication_text_padding"
+                android:paddingEnd="@dimen/keyguard_indication_text_padding"
                 android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
                 android:accessibilityLiveRegion="polite" />
 
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 7f85ec0..3d297ae 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -464,7 +464,7 @@
     <string name="battery_saver_notification_title" msgid="8614079794522291840">"تم تفعيل ميزة توفير شحن البطارية"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"لخفض مستوى الأداء وبيانات الخلفية"</string>
     <string name="battery_saver_notification_action_text" msgid="132118784269455533">"إيقاف ميزة توفير شحن البطارية"</string>
-    <string name="media_projection_dialog_text" msgid="8585357687598538511">"أثناء التسجيل أو الإرسال، يمكن لتطبيق <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> تسجيل أي معلومات حساسة يتم عرضها على الشاشة أو تشغيلها من جهازك، بما فيها المعلومات الحساسة مثل الصوت الذي تشغّله وكلمات المرور ومعلومات الدفع والصور والرسائل."</string>
+    <string name="media_projection_dialog_text" msgid="8585357687598538511">"أثناء التسجيل أو البث، يمكن لتطبيق <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> تسجيل أي معلومات حسّاسة يتم عرضها على الشاشة أو تشغيلها من جهازك، بما فيها المعلومات الحسّاسة مثل المقاطع الصوتية وكلمات المرور ومعلومات الدفع والصور والرسائل."</string>
     <string name="media_projection_dialog_service_text" msgid="3075544489835858258">"أثناء التسجيل أو الإرسال، يمكن للخدمة التي تقدّم هذه الوظيفة تسجيل أي معلومات حساسة يتم عرضها على الشاشة أو تشغيلها من جهازك، بما فيها المعلومات الحساسة مثل الصوت الذي تشغّله وكلمات المرور ومعلومات الدفع والصور والرسائل."</string>
     <string name="media_projection_dialog_title" msgid="8124184308671641248">"عرض معلومات حسّاسة أثناء الإرسال/التسجيل"</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"عدم الإظهار مرة أخرى"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 82252ba..dc661dd 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -401,7 +401,7 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
     <string name="keyguard_unlock" msgid="6035822649218712063">"Swipe up to open"</string>
-    <string name="do_disclosure_generic" msgid="5615898451805157556">"This device is managed by your organization"</string>
+    <string name="do_disclosure_generic" msgid="5615898451805157556">"This device is managed by your organisation"</string>
     <string name="do_disclosure_with_name" msgid="5640615509915445501">"This device is managed by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Swipe from icon for voice assist"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index ca9e29a..9903cc0 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -401,7 +401,7 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
     <string name="keyguard_unlock" msgid="6035822649218712063">"Swipe up to open"</string>
-    <string name="do_disclosure_generic" msgid="5615898451805157556">"This device is managed by your organization"</string>
+    <string name="do_disclosure_generic" msgid="5615898451805157556">"This device is managed by your organisation"</string>
     <string name="do_disclosure_with_name" msgid="5640615509915445501">"This device is managed by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Swipe from icon for voice assist"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 82252ba..dc661dd 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -401,7 +401,7 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
     <string name="keyguard_unlock" msgid="6035822649218712063">"Swipe up to open"</string>
-    <string name="do_disclosure_generic" msgid="5615898451805157556">"This device is managed by your organization"</string>
+    <string name="do_disclosure_generic" msgid="5615898451805157556">"This device is managed by your organisation"</string>
     <string name="do_disclosure_with_name" msgid="5640615509915445501">"This device is managed by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Swipe from icon for voice assist"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 82252ba..dc661dd 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -401,7 +401,7 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
     <string name="keyguard_unlock" msgid="6035822649218712063">"Swipe up to open"</string>
-    <string name="do_disclosure_generic" msgid="5615898451805157556">"This device is managed by your organization"</string>
+    <string name="do_disclosure_generic" msgid="5615898451805157556">"This device is managed by your organisation"</string>
     <string name="do_disclosure_with_name" msgid="5640615509915445501">"This device is managed by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Swipe from icon for phone"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Swipe from icon for voice assist"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index a5f9989..7b2d793 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -871,7 +871,7 @@
     <string name="notification_channel_storage" msgid="3077205683020695313">"Memoria"</string>
     <string name="notification_channel_hints" msgid="7323870212489152689">"Aholkuak"</string>
     <string name="instant_apps" msgid="6647570248119804907">"Zuzeneko aplikazioak"</string>
-    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> exekutatzen ari da"</string>
+    <string name="instant_apps_title" msgid="8738419517367449783">"<xliff:g id="APP">%1$s</xliff:g> abian da"</string>
     <string name="instant_apps_message" msgid="1183313016396018086">"Ezer instalatu gabe ireki da aplikazioa."</string>
     <string name="instant_apps_message_with_help" msgid="6179830437630729747">"Ezer instalatu gabe ireki da aplikazioa. Sakatu informazio gehiago lortzeko."</string>
     <string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string>
@@ -888,7 +888,7 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> arte"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Utzi bere horretan"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Ordeztu"</string>
-    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikazioak exekutatzen ari dira atzeko planoan"</string>
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikazioak abian dira atzeko planoan"</string>
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"Sakatu bateria eta datuen erabilerari buruzko xehetasunak ikusteko"</string>
     <string name="mobile_data_disable_title" msgid="1068272097382942231">"Datu-konexioa desaktibatu nahi duzu?"</string>
     <string name="mobile_data_disable_message" msgid="4756541658791493506">"<xliff:g id="CARRIER">%s</xliff:g> erabilita ezingo dituzu erabili datuak edo Internet. Wifi-sare baten bidez soilik konektatu ahal izango zara Internetera."</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b25f2fc..75a76ae 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -376,7 +376,7 @@
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Jusqu\'à l\'aube"</string>
     <string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"À partir de <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_secondary_label_until" msgid="2749196569462600150">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
-    <string name="quick_settings_ui_mode_night_label" msgid="3419947801072692538">"Thème foncé"</string>
+    <string name="quick_settings_ui_mode_night_label" msgid="3419947801072692538">"Thème sombre"</string>
     <string name="quick_settings_ui_mode_night_label_battery_saver" msgid="7438725724589758362">"Thème foncé\nÉconomiseur de batterie"</string>
     <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="6883274004315134333">"La technologie NFC est désactivée"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 1a914e0..3268ed0 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -894,10 +894,10 @@
     <string name="mobile_data_disable_message" msgid="4756541658791493506">"Non terás acceso aos datos nin a Internet a través de <xliff:g id="CARRIER">%s</xliff:g>. Internet só estará dispoñible mediante a wifi."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"o teu operador"</string>
     <string name="touch_filtered_warning" msgid="8671693809204767551">"Dado que unha aplicación se superpón sobre unha solicitude de permiso, a configuración non pode verificar a túa resposta."</string>
-    <string name="slice_permission_title" msgid="7465009437851044444">"Queres permitir que a aplicación <xliff:g id="APP_0">%1$s</xliff:g> mostre partes de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+    <string name="slice_permission_title" msgid="7465009437851044444">"Queres permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre fragmentos de aplicación de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
     <string name="slice_permission_text_1" msgid="3514586565609596523">"- Pode ler información da aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="slice_permission_text_2" msgid="3146758297471143723">"- Pode levar a cabo accións dentro da aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="slice_permission_checkbox" msgid="7986504458640562900">"Permitir que a aplicación <xliff:g id="APP">%1$s</xliff:g> mostre partes de calquera aplicación"</string>
+    <string name="slice_permission_checkbox" msgid="7986504458640562900">"Permitir que <xliff:g id="APP">%1$s</xliff:g> mostre fragmentos de calquera aplicación"</string>
     <string name="slice_permission_allow" msgid="2340244901366722709">"Permitir"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"Denegar"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Tocar para programar a función Aforro de batería"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ef29f9b..263fe8a 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -484,7 +484,7 @@
     <string name="monitoring_title_device_owned" msgid="1652495295941959815">"डिवाइस प्रबंधन"</string>
     <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफ़ाइल को मॉनीटर करना"</string>
     <string name="monitoring_title" msgid="169206259253048106">"नेटवर्क को मॉनीटर करना"</string>
-    <string name="monitoring_subtitle_vpn" msgid="876537538087857300">"VPN"</string>
+    <string name="monitoring_subtitle_vpn" msgid="876537538087857300">"वीपीएन"</string>
     <string name="monitoring_subtitle_network_logging" msgid="3341264304793193386">"नेटवर्क लॉगिंग"</string>
     <string name="monitoring_subtitle_ca_certificate" msgid="3874151893894355988">"CA प्रमाणपत्र"</string>
     <string name="disable_vpn" msgid="4435534311510272506">"VPN अक्षम करें"</string>
@@ -513,7 +513,7 @@
     <string name="monitoring_description_network_logging" msgid="7223505523384076027">"आपके एडमिन ने नेटवर्क लॉग करना चालू कर दिया है, जो आपके डिवाइस पर ट्रैफ़िक की निगरानी करता है.\n\nज़्यादा जानकारी के लिए अपने एडमिन से संपर्क करें."</string>
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"आपने किसी ऐप को VPN कनेक्‍शन सेट करने की अनुमति दी है.\n\nयह ऐप ईमेल, ऐप्‍स और सुरक्षित वेबसाइटों सहित आपके डिवाइस और नेटवर्क की गतिविधि की निगरानी कर सकता है."</string>
     <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> आपकी वर्क प्रोफ़ाइल को प्रबंधित करता है.\n\n आपका एडमिन ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nऔर जानकारी के लिए अपने एडमिन से संपर्क करें.\n\nआप ऐसे VPN से भी कनेक्‍ट हैं, जो आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
-    <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
+    <string name="legacy_vpn_name" msgid="6604123105765737830">"वीपीएन"</string>
     <string name="monitoring_description_app" msgid="1828472472674709532">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि को मॉनिटर कर सकता है."</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 6d614b1..3156a6f 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -130,7 +130,7 @@
     <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"Դեմքի ճանաչում…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Դեմքի պատկերակ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
-    <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
+    <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Մասշտաբը մեծացնել փոքրից ավելի մեծ էկրան:"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-ը միացված է:"</string>
     <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth-ն անջատված է:"</string>
     <string name="accessibility_no_battery" msgid="358343022352820946">"Մարտկոց չկա:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 59b6eb3..19b2b99 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -89,7 +89,7 @@
     <string name="screenrecord_share_label" msgid="4197867360204019389">"Bagikan"</string>
     <string name="screenrecord_delete_label" msgid="7893716870917824013">"Hapus"</string>
     <string name="screenrecord_cancel_success" msgid="7768976011702614782">"Rekaman layar dibatalkan"</string>
-    <string name="screenrecord_save_message" msgid="4733982661301846778">"Rekaman layar disimpan, tap untuk melihat"</string>
+    <string name="screenrecord_save_message" msgid="4733982661301846778">"Rekaman layar disimpan, ketuk untuk melihat"</string>
     <string name="screenrecord_delete_description" msgid="5743190456090354585">"Rekaman layar dihapus"</string>
     <string name="screenrecord_delete_error" msgid="8154904464563560282">"Error saat menghapus rekaman layar"</string>
     <string name="screenrecord_permission_error" msgid="1526755299469001000">"Gagal mendapatkan izin"</string>
@@ -836,7 +836,7 @@
     <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Tarik ke bawah untuk menutup"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Menu"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> adalah picture-in-picture"</string>
-    <string name="pip_notification_message" msgid="5619512781514343311">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, tap untuk membuka setelan dan menonaktifkannya."</string>
+    <string name="pip_notification_message" msgid="5619512781514343311">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, ketuk untuk membuka setelan dan menonaktifkannya."</string>
     <string name="pip_play" msgid="1417176722760265888">"Putar"</string>
     <string name="pip_pause" msgid="8881063404466476571">"Jeda"</string>
     <string name="pip_skip_to_next" msgid="1948440006726306284">"Lewati ke berikutnya"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 1058d74..83a7aaa 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -29,9 +29,9 @@
     <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> të mbetura, rreth <xliff:g id="TIME">%2$s</xliff:g> të mbetura bazuar në përdorimin tënd"</string>
     <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> të mbetura, rreth <xliff:g id="TIME">%2$s</xliff:g> të mbetura"</string>
     <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Ka mbetur edhe <xliff:g id="PERCENTAGE">%s</xliff:g>. \"Kursyesi i baterisë\" është i aktivizuar."</string>
-    <string name="invalid_charger" msgid="2741987096648693172">"Nuk mund të ngarkohet përmes USB-së. Përdor ngarkuesin që ke marrë me pajisjen."</string>
+    <string name="invalid_charger" msgid="2741987096648693172">"Nuk mund të karikohet përmes USB-së. Përdor karikuesin që ke marrë me pajisjen."</string>
     <string name="invalid_charger_title" msgid="2836102177577255404">"Nuk mund të ngarkohet përmes USB-së"</string>
-    <string name="invalid_charger_text" msgid="6480624964117840005">"Përdor ngarkuesin që ke marrë me pajisjen"</string>
+    <string name="invalid_charger_text" msgid="6480624964117840005">"Përdor karikuesin që ke marrë me pajisjen"</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Cilësimet"</string>
     <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Të aktivizohet \"Kursyesi i baterisë\"?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2090922638411744540">"Rreth \"Kursyesit të baterisë\""</string>
@@ -614,7 +614,7 @@
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Të hiqet Sintonizuesi i Sistemit të Ndërfaqes së Përdoruesit nga Cilësimet dhe të ndërpritet përdorimi i të gjitha funksioneve të tij?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Aplikacioni nuk është instaluar në pajisjen tënde."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Trego sekondat e orës"</string>
-    <string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te kohëzgjatja e baterisë."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 0e74993..56521f6 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -33,7 +33,7 @@
     <string name="invalid_charger_title" msgid="2836102177577255404">"Не вдається зарядити через USB"</string>
     <string name="invalid_charger_text" msgid="6480624964117840005">"Використовуйте зарядний пристрій, який входить у комплект пристрою"</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Налаштування"</string>
-    <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Увімкнути режим економії заряду акумулятора?"</string>
+    <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Увімкнути режим енергозбереження?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2090922638411744540">"Про режим енергозбереження"</string>
     <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Увімкнути"</string>
     <string name="battery_saver_start_action" msgid="8187820911065797519">"Увімкнути режим економії заряду акумулятора"</string>
@@ -455,7 +455,7 @@
     <string name="user_remove_user_title" msgid="4681256956076895559">"Видалити користувача?"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"Усі додатки й дані цього користувача буде видалено."</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"Видалити"</string>
-    <string name="battery_saver_notification_title" msgid="8614079794522291840">"Режим економії заряду акумулятора ввімкнено"</string>
+    <string name="battery_saver_notification_title" msgid="8614079794522291840">"Режим енергозбереження ввімкнено"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Знижується продуктивність і обмежуються фонові дані"</string>
     <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Вимкнути режим економії заряду акумулятора"</string>
     <string name="media_projection_dialog_text" msgid="8585357687598538511">"Під час запису або трансляції додаток <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> може фіксувати будь-яку конфіденційну інформацію (зокрема, аудіо, паролі, платіжну інформацію, фотографії та повідомлення), яка з\'являється на екрані або відтворюється на пристрої."</string>
@@ -913,7 +913,7 @@
     <string name="auto_saver_title" msgid="1217959994732964228">"Торкніться, щоб увімкнути автоматичний режим економії заряду акумулятора"</string>
     <string name="auto_saver_text" msgid="2563289953551438248">"Вмикати, коли заряд акумулятора закінчується"</string>
     <string name="no_auto_saver_action" msgid="8086002101711328500">"Ні, дякую"</string>
-    <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Автоматичний режим економії заряду акумулятора ввімкнено"</string>
+    <string name="auto_saver_enabled_title" msgid="6726474226058316862">"Автоматичний перехід у режим енергозбереження ввімкнено"</string>
     <string name="auto_saver_enabled_text" msgid="874711029884777579">"Режим економії заряду акумулятора вмикається автоматично, коли рівень заряду нижчий за <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Налаштування"</string>
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"OK"</string>
diff --git a/packages/SystemUI/res/values/attrs_car.xml b/packages/SystemUI/res/values/attrs_car.xml
index ced26c9..49b87f3 100644
--- a/packages/SystemUI/res/values/attrs_car.xml
+++ b/packages/SystemUI/res/values/attrs_car.xml
@@ -62,6 +62,8 @@
         <attr name="unselectedAlpha" />
         <!-- icon to be rendered when in selected state -->
         <attr name="selectedIcon" />
+        <!-- icon to be rendered (drawable) -->
+        <attr name="icon"/>
     </declare-styleable>
 
     <!-- Custom attributes to configure hvac values -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 7c24130..861187f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -154,12 +154,8 @@
     <!-- The number of milliseconds before the heads up notification accepts touches. -->
     <integer name="touch_acceptance_delay">700</integer>
 
-    <!-- The number of milliseconds before the ambient notification auto-dismisses. This will
-         override the default pulse length. -->
-    <integer name="heads_up_notification_decay_dozing">10000</integer>
-
     <!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
-    <integer name="ambient_notification_extension_time">6000</integer>
+    <integer name="ambient_notification_extension_time">10000</integer>
 
     <!-- In multi-window, determines whether the stack where recents lives should grow from
          the smallest position when being launched. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f4970d0..be815e1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -112,7 +112,7 @@
     <dimen name="status_bar_connected_device_bt_indicator_size">17dp</dimen>
 
     <!-- Height of a small notification in the status bar-->
-    <dimen name="notification_min_height">106dp</dimen>
+    <dimen name="notification_min_height">@*android:dimen/notification_min_height</dimen>
 
     <!-- Increased height of a small notification in the status bar -->
     <dimen name="notification_min_height_increased">146dp</dimen>
@@ -183,6 +183,9 @@
     <!-- The padding on the bottom of the notifications on the keyguard -->
     <dimen name="keyguard_indication_bottom_padding">12sp</dimen>
 
+    <!-- The padding at start and end of indication text shown on AOD -->
+    <dimen name="keyguard_indication_text_padding">16dp</dimen>
+
     <!-- Shadows under the clock, date and other keyguard text fields -->
     <dimen name="keyguard_shadow_radius">5</dimen>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index 53403aa..a7e3c59 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -171,15 +171,21 @@
         PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
                 allowMultiple, mLooper, cls, this);
         p.loadAll();
-        mPluginMap.put(listener, p);
+        synchronized (this) {
+            mPluginMap.put(listener, p);
+        }
         startListening();
     }
 
     public void removePluginListener(PluginListener<?> listener) {
-        if (!mPluginMap.containsKey(listener)) return;
-        mPluginMap.remove(listener).destroy();
-        if (mPluginMap.size() == 0) {
-            stopListening();
+        synchronized (this) {
+            if (!mPluginMap.containsKey(listener)) {
+                return;
+            }
+            mPluginMap.remove(listener).destroy();
+            if (mPluginMap.size() == 0) {
+                stopListening();
+            }
         }
     }
 
@@ -208,8 +214,10 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
-            for (PluginInstanceManager manager : mPluginMap.values()) {
-                manager.loadAll();
+            synchronized (this) {
+                for (PluginInstanceManager manager : mPluginMap.values()) {
+                    manager.loadAll();
+                }
             }
         } else if (DISABLE_PLUGIN.equals(intent.getAction())) {
             Uri uri = intent.getData();
@@ -274,13 +282,15 @@
                     getPluginEnabler().setEnabled(componentName);
                 }
             }
-            if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
-                for (PluginInstanceManager manager : mPluginMap.values()) {
-                    manager.onPackageChange(pkg);
-                }
-            } else {
-                for (PluginInstanceManager manager : mPluginMap.values()) {
-                    manager.onPackageRemoved(pkg);
+            synchronized (this) {
+                if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+                    for (PluginInstanceManager manager : mPluginMap.values()) {
+                        manager.onPackageChange(pkg);
+                    }
+                } else {
+                    for (PluginInstanceManager manager : mPluginMap.values()) {
+                        manager.onPackageRemoved(pkg);
+                    }
                 }
             }
         }
@@ -322,9 +332,11 @@
     }
 
     public <T> boolean dependsOn(Plugin p, Class<T> cls) {
-        for (int i = 0; i < mPluginMap.size(); i++) {
-            if (mPluginMap.valueAt(i).dependsOn(p, cls)) {
-                return true;
+        synchronized (this) {
+            for (int i = 0; i < mPluginMap.size(); i++) {
+                if (mPluginMap.valueAt(i).dependsOn(p, cls)) {
+                    return true;
+                }
             }
         }
         return false;
@@ -335,10 +347,12 @@
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println(String.format("  plugin map (%d):", mPluginMap.size()));
-        for (PluginListener listener: mPluginMap.keySet()) {
-            pw.println(String.format("    %s -> %s",
-                    listener, mPluginMap.get(listener)));
+        synchronized (this) {
+            pw.println(String.format("  plugin map (%d):", mPluginMap.size()));
+            for (PluginListener listener : mPluginMap.keySet()) {
+                pw.println(String.format("    %s -> %s",
+                        listener, mPluginMap.get(listener)));
+            }
         }
     }
 
@@ -418,8 +432,10 @@
                 // We couldn't find any plugins involved in this crash, just to be safe
                 // disable all the plugins, so we can be sure that SysUI is running as
                 // best as possible.
-                for (PluginInstanceManager manager : mPluginMap.values()) {
-                    disabledAny |= manager.disableAll();
+                synchronized (this) {
+                    for (PluginInstanceManager manager : mPluginMap.values()) {
+                        disabledAny |= manager.disableAll();
+                    }
                 }
             }
             if (disabledAny) {
@@ -433,9 +449,11 @@
         private boolean checkStack(Throwable throwable) {
             if (throwable == null) return false;
             boolean disabledAny = false;
-            for (StackTraceElement element : throwable.getStackTrace()) {
-                for (PluginInstanceManager manager : mPluginMap.values()) {
-                    disabledAny |= manager.checkAndDisable(element.getClassName());
+            synchronized (this) {
+                for (StackTraceElement element : throwable.getStackTrace()) {
+                    for (PluginInstanceManager manager : mPluginMap.values()) {
+                        disabledAny |= manager.checkAndDisable(element.getClassName());
+                    }
                 }
             }
             return disabledAny | checkStack(throwable.getCause());
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index 5b9ee1c..dcb134e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -20,6 +20,7 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskDescription;
+import android.app.TaskInfo;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -75,7 +76,7 @@
 
         private int mHashCode;
 
-        public TaskKey(ActivityManager.RecentTaskInfo t) {
+        public TaskKey(TaskInfo t) {
             ComponentName sourceComponent = t.origActivity != null
                     // Activity alias if there is one
                     ? t.origActivity
@@ -226,6 +227,17 @@
         // Do nothing
     }
 
+    /**
+     * Creates a task object from the provided task info
+     */
+    public static Task from(TaskKey taskKey, TaskInfo taskInfo, boolean isLocked) {
+        ActivityManager.TaskDescription td = taskInfo.taskDescription;
+        return new Task(taskKey,
+                td != null ? td.getPrimaryColor() : 0,
+                td != null ? td.getBackgroundColor() : 0,
+                taskInfo.supportsSplitScreenMultiWindow, isLocked, td, taskInfo.topActivity);
+    }
+
     public Task(TaskKey key) {
         this.key = key;
         this.taskDescription = new TaskDescription();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 98a8110..98b7e24 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -38,6 +38,7 @@
     public int windowingMode;
     public int systemUiVisibility;
     public float scale;
+    public long snapshotId;
 
     public ThumbnailData() {
         thumbnail = null;
@@ -49,6 +50,7 @@
         isTranslucent = false;
         windowingMode = WINDOWING_MODE_UNDEFINED;
         systemUiVisibility = 0;
+        snapshotId = 0;
     }
 
     public ThumbnailData(TaskSnapshot snapshot) {
@@ -61,5 +63,6 @@
         isTranslucent = snapshot.isTranslucent();
         windowingMode = snapshot.getWindowingMode();
         systemUiVisibility = snapshot.getSystemUiVisibility();
+        snapshotId = snapshot.getId();
     }
 }
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 506813b..328116d 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
@@ -30,10 +30,12 @@
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
 import android.app.IAssistDataReceiver;
+import android.app.WindowConfiguration;
 import android.app.WindowConfiguration.ActivityType;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -500,4 +502,12 @@
                 PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
                 || freeformDevOption);
     }
+
+    /**
+     * Returns true if the running task represents the home task
+     */
+    public static boolean isHomeTask(RunningTaskInfo info) {
+        return info.configuration.windowConfiguration.getActivityType()
+                == WindowConfiguration.ACTIVITY_TYPE_HOME;
+    }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 7fbe5db..2a890fe 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -49,6 +49,15 @@
     public static final String NAV_BAR_MODE_GESTURAL_OVERLAY =
             WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
+    // Action sent by a system app to switch to gesture nav
+    public static final String ACTION_ENABLE_GESTURE_NAV =
+            "com.android.systemui.ENABLE_GESTURE_NAV";
+    // Action for the intent to receive the result
+    public static final String ACTION_ENABLE_GESTURE_NAV_RESULT =
+            "com.android.systemui.action.ENABLE_GESTURE_NAV_RESULT";
+    // Extra containing the pending intent to receive the result
+    public static final String EXTRA_RESULT_INTENT = "com.android.systemui.EXTRA_RESULT_INTENT";
+
     // Overview is disabled, either because the device is in lock task mode, or because the device
     // policy has disabled the feature
     public static final int SYSUI_STATE_SCREEN_PINNING = 1 << 0;
@@ -71,6 +80,8 @@
     public static final int SYSUI_STATE_HOME_DISABLED = 1 << 8;
     // The keyguard is showing, but occluded
     public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED = 1 << 9;
+    // The search feature is disabled (either by SUW/SysUI/device policy)
+    public static final int SYSUI_STATE_SEARCH_DISABLED = 1 << 10;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -82,7 +93,8 @@
             SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
             SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
             SYSUI_STATE_OVERVIEW_DISABLED,
-            SYSUI_STATE_HOME_DISABLED
+            SYSUI_STATE_HOME_DISABLED,
+            SYSUI_STATE_SEARCH_DISABLED
     })
     public @interface SystemUiStateFlags {}
 
@@ -91,6 +103,7 @@
         str.add((flags & SYSUI_STATE_SCREEN_PINNING) != 0 ? "screen_pinned" : "");
         str.add((flags & SYSUI_STATE_OVERVIEW_DISABLED) != 0 ? "overview_disabled" : "");
         str.add((flags & SYSUI_STATE_HOME_DISABLED) != 0 ? "home_disabled" : "");
+        str.add((flags & SYSUI_STATE_SEARCH_DISABLED) != 0 ? "search_disabled" : "");
         str.add((flags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0 ? "navbar_hidden" : "");
         str.add((flags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0 ? "notif_visible" : "");
         str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) != 0 ? "keygrd_visible" : "");
@@ -141,10 +154,11 @@
      * disabled.
      */
     public static boolean isAssistantGestureDisabled(int sysuiStateFlags) {
-        // Disable when in screen pinning, immersive, the bouncer is showing
+        // Disable when in screen pinning, immersive, the bouncer is showing, or search is disabled
         int disableFlags = SYSUI_STATE_SCREEN_PINNING
                 | SYSUI_STATE_NAV_BAR_HIDDEN
-                | SYSUI_STATE_BOUNCER_SHOWING;
+                | SYSUI_STATE_BOUNCER_SHOWING
+                | SYSUI_STATE_SEARCH_DISABLED;
         if ((sysuiStateFlags & disableFlags) != 0) {
             return true;
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java
deleted file mode 100644
index a529903..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentTaskInfoCompat.java
+++ /dev/null
@@ -1,45 +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
- */
-
-package com.android.systemui.shared.system;
-
-import android.app.ActivityManager;
-import android.content.ComponentName;
-
-public class RecentTaskInfoCompat {
-
-    private ActivityManager.RecentTaskInfo mInfo;
-
-    public RecentTaskInfoCompat(ActivityManager.RecentTaskInfo info) {
-        mInfo = info;
-    }
-
-    public int getUserId() {
-        return mInfo.userId;
-    }
-
-    public boolean supportsSplitScreenMultiWindow() {
-        return mInfo.supportsSplitScreenMultiWindow;
-    }
-
-    public ComponentName getTopActivity() {
-        return mInfo.topActivity;
-    }
-
-    public ActivityManager.TaskDescription getTaskDescription() {
-        return mInfo.taskDescription;
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index d2fe5cd..2ef0422 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -91,6 +91,7 @@
         }
     }
 
+    @Deprecated
     public void setCancelWithDeferredScreenshot(boolean screenshot) {
         try {
             mAnimationController.setCancelWithDeferredScreenshot(screenshot);
@@ -99,6 +100,14 @@
         }
     }
 
+    public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+        try {
+            mAnimationController.setDeferCancelUntilNextTransition(defer, screenshot);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to set deferred cancel with screenshot", e);
+        }
+    }
+
     public void cleanupScreenshot() {
         try {
             mAnimationController.cleanupScreenshot();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
new file mode 100644
index 0000000..326c2aa
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.system;
+
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+
+public class TaskInfoCompat {
+
+    public static int getUserId(TaskInfo info) {
+        return info.userId;
+    }
+
+    public static int getActivityType(TaskInfo info) {
+        return info.configuration.windowConfiguration.getActivityType();
+    }
+
+    public static int getWindowingMode(TaskInfo info) {
+        return info.configuration.windowConfiguration.getWindowingMode();
+    }
+
+    public static boolean supportsSplitScreenMultiWindow(TaskInfo info) {
+        return info.supportsSplitScreenMultiWindow;
+    }
+
+    public static ComponentName getTopActivity(TaskInfo info) {
+        return info.topActivity;
+    }
+
+    public static ActivityManager.TaskDescription getTaskDescription(TaskInfo info) {
+        return info.taskDescription;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 2483192..5097216 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -584,6 +584,9 @@
         @Override
         public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
                 TransitionValues endValues) {
+            if (!sceneRoot.isShown()) {
+                return null;
+            }
             final float cutoff = mCutoff;
             final int startVisibility = View.INVISIBLE;
             final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
@@ -596,6 +599,9 @@
         @Override
         public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
                 TransitionValues endValues) {
+            if (!sceneRoot.isShown()) {
+                return null;
+            }
             final float cutoff = 1f - mCutoff;
             final int startVisibility = View.VISIBLE;
             final int endVisibility = (int) endValues.values.get(PROPNAME_VISIBILITY);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 69630c4..8059dcf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -237,6 +237,7 @@
                     MIN_DRAG_SIZE, getResources().getDisplayMetrics())
                     && !mUpdateMonitor.isFaceDetectionRunning()) {
                 mUpdateMonitor.requestFaceAuth();
+                mCallback.userActivity();
                 showMessage(null, null);
             }
         }
@@ -268,7 +269,7 @@
      */
     private void updateBiometricRetry() {
         SecurityMode securityMode = getSecurityMode();
-        mSwipeUpToRetry = mUnlockMethodCache.isUnlockingWithFacePossible()
+        mSwipeUpToRetry = mUnlockMethodCache.isFaceAuthEnabled()
                 && securityMode != SecurityMode.SimPin
                 && securityMode != SecurityMode.SimPuk
                 && securityMode != SecurityMode.None;
@@ -512,7 +513,7 @@
                 case SimPuk:
                     // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
                     SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
-                    if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
+                    if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
                             KeyguardUpdateMonitor.getCurrentUser())) {
                         finish = true;
                         eventSubtype = BOUNCER_DISMISS_SIM;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index e219e24..af4e61b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -89,6 +89,7 @@
     private final HashMap<View, PendingIntent> mClickActions;
     private final ActivityStarter mActivityStarter;
     private final ConfigurationController mConfigurationController;
+    private final LayoutTransition mLayoutTransition;
     private Uri mKeyguardSliceUri;
     @VisibleForTesting
     TextView mTitle;
@@ -126,16 +127,16 @@
         mActivityStarter = activityStarter;
         mConfigurationController = configurationController;
 
-        LayoutTransition transition = new LayoutTransition();
-        transition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2);
-        transition.setDuration(LayoutTransition.APPEARING, DEFAULT_ANIM_DURATION);
-        transition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 2);
-        transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
-        transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
-        transition.setInterpolator(LayoutTransition.APPEARING, Interpolators.FAST_OUT_SLOW_IN);
-        transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT);
-        transition.setAnimateParentHierarchy(false);
-        setLayoutTransition(transition);
+        mLayoutTransition = new LayoutTransition();
+        mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2);
+        mLayoutTransition.setDuration(LayoutTransition.APPEARING, DEFAULT_ANIM_DURATION);
+        mLayoutTransition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 2);
+        mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
+        mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+        mLayoutTransition.setInterpolator(LayoutTransition.APPEARING,
+                Interpolators.FAST_OUT_SLOW_IN);
+        mLayoutTransition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT);
+        mLayoutTransition.setAnimateParentHierarchy(false);
     }
 
     @Override
@@ -174,6 +175,12 @@
         mConfigurationController.removeCallback(this);
     }
 
+    @Override
+    public void onVisibilityAggregated(boolean isVisible) {
+        super.onVisibilityAggregated(isVisible);
+        setLayoutTransition(isVisible ? mLayoutTransition : null);
+    }
+
     /**
      * Returns whether the current visible slice has a title/header.
      */
@@ -419,6 +426,7 @@
          * their desired positions.
          */
         private final Animation.AnimationListener mKeepAwakeListener;
+        private LayoutTransition mLayoutTransition;
         private float mDarkAmount;
 
         public Row(Context context) {
@@ -440,33 +448,41 @@
 
         @Override
         protected void onFinishInflate() {
-            LayoutTransition transition = new LayoutTransition();
-            transition.setDuration(DEFAULT_ANIM_DURATION);
+            mLayoutTransition = new LayoutTransition();
+            mLayoutTransition.setDuration(DEFAULT_ANIM_DURATION);
 
             PropertyValuesHolder left = PropertyValuesHolder.ofInt("left", 0, 1);
             PropertyValuesHolder right = PropertyValuesHolder.ofInt("right", 0, 1);
             ObjectAnimator changeAnimator = ObjectAnimator.ofPropertyValuesHolder((Object) null,
                     left, right);
-            transition.setAnimator(LayoutTransition.CHANGE_APPEARING, changeAnimator);
-            transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeAnimator);
-            transition.setInterpolator(LayoutTransition.CHANGE_APPEARING,
+            mLayoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, changeAnimator);
+            mLayoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeAnimator);
+            mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_APPEARING,
                     Interpolators.ACCELERATE_DECELERATE);
-            transition.setInterpolator(LayoutTransition.CHANGE_DISAPPEARING,
+            mLayoutTransition.setInterpolator(LayoutTransition.CHANGE_DISAPPEARING,
                     Interpolators.ACCELERATE_DECELERATE);
-            transition.setStartDelay(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION);
-            transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, DEFAULT_ANIM_DURATION);
+            mLayoutTransition.setStartDelay(LayoutTransition.CHANGE_APPEARING,
+                    DEFAULT_ANIM_DURATION);
+            mLayoutTransition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING,
+                    DEFAULT_ANIM_DURATION);
 
             ObjectAnimator appearAnimator = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
-            transition.setAnimator(LayoutTransition.APPEARING, appearAnimator);
-            transition.setInterpolator(LayoutTransition.APPEARING, Interpolators.ALPHA_IN);
+            mLayoutTransition.setAnimator(LayoutTransition.APPEARING, appearAnimator);
+            mLayoutTransition.setInterpolator(LayoutTransition.APPEARING, Interpolators.ALPHA_IN);
 
             ObjectAnimator disappearAnimator = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
-            transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT);
-            transition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 4);
-            transition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnimator);
+            mLayoutTransition.setInterpolator(LayoutTransition.DISAPPEARING,
+                    Interpolators.ALPHA_OUT);
+            mLayoutTransition.setDuration(LayoutTransition.DISAPPEARING, DEFAULT_ANIM_DURATION / 4);
+            mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnimator);
 
-            transition.setAnimateParentHierarchy(false);
-            setLayoutTransition(transition);
+            mLayoutTransition.setAnimateParentHierarchy(false);
+        }
+
+        @Override
+        public void onVisibilityAggregated(boolean isVisible) {
+            super.onVisibilityAggregated(isVisible);
+            setLayoutTransition(isVisible ? mLayoutTransition : null);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 05e14a7..4e7b157 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -377,14 +377,15 @@
         }
     };
 
-    private boolean mFaceSettingEnabledForUser;
+    private SparseBooleanArray mFaceSettingEnabledForUser = new SparseBooleanArray();
     private BiometricManager mBiometricManager;
     private IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback =
             new IBiometricEnabledOnKeyguardCallback.Stub() {
         @Override
-        public void onChanged(BiometricSourceType type, boolean enabled) throws RemoteException {
+        public void onChanged(BiometricSourceType type, boolean enabled, int userId)
+                throws RemoteException {
             if (type == BiometricSourceType.FACE) {
-                mFaceSettingEnabledForUser = enabled;
+                mFaceSettingEnabledForUser.put(userId, enabled);
                 updateFaceListeningState();
             }
         }
@@ -1711,7 +1712,7 @@
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
         return (mBouncer || mAuthInterruptActive || awakeKeyguard || shouldListenForFaceAssistant())
                 && !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
-                && !mKeyguardGoingAway && mFaceSettingEnabledForUser && !mLockIconPressed
+                && !mKeyguardGoingAway && mFaceSettingEnabledForUser.get(user) && !mLockIconPressed
                 && strongAuthAllowsScanning && mIsPrimaryUser
                 && !mSecureCameraLaunched;
     }
@@ -1782,14 +1783,17 @@
                 && mFpm.getEnrolledFingerprints(userId).size() > 0;
     }
 
+    private boolean isUnlockWithFacePossible(int userId) {
+        return isFaceAuthEnabledForUser(userId) && !isFaceDisabled(userId);
+    }
+
     /**
-     * If face hardware is available and user has enrolled. Not considering encryption or
-     * lockdown state.
+     * If face hardware is available, user has enrolled and enabled auth via setting.
      */
-    public boolean isUnlockWithFacePossible(int userId) {
+    public boolean isFaceAuthEnabledForUser(int userId) {
         return mFaceManager != null && mFaceManager.isHardwareDetected()
-                && !isFaceDisabled(userId)
-                && mFaceManager.hasEnrolledTemplates(userId);
+                && mFaceManager.hasEnrolledTemplates(userId)
+                && mFaceSettingEnabledForUser.get(userId);
     }
 
     private void stopListeningForFingerprint() {
@@ -2203,6 +2207,15 @@
         if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncer + ")");
         boolean isBouncer = (bouncer == 1);
         mBouncer = isBouncer;
+
+        if (isBouncer) {
+            // If the bouncer is shown, always clear this flag. This can happen in the following
+            // situations: 1) Default camera with SHOW_WHEN_LOCKED is not chosen yet. 2) Secure
+            // camera requests dismiss keyguard (tapping on photos for example). When these happen,
+            // face auth should resume.
+            mSecureCameraLaunched = false;
+        }
+
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -2648,7 +2661,8 @@
             pw.println("    possible=" + isUnlockWithFacePossible(userId));
             pw.println("    strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
             pw.println("    trustManaged=" + getUserTrustIsManaged(userId));
-            pw.println("    enabledByUser=" + mFaceSettingEnabledForUser);
+            pw.println("    enabledByUser=" + mFaceSettingEnabledForUser.get(userId));
+            pw.println("    mSecureCameraLaunched=" + mSecureCameraLaunched);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemBars.java b/packages/SystemUI/src/com/android/systemui/SystemBars.java
index 4285af0..c4c0fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemBars.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemBars.java
@@ -46,6 +46,13 @@
         }
     }
 
+    @Override
+    public void onBootCompleted() {
+        if (mStatusBar != null) {
+            mStatusBar.onBootCompleted();
+        }
+    }
+
     private void createStatusBarFromConfig() {
         if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
         final String clsName = mContext.getString(R.string.config_statusBarComponent);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index a5857df..ce67577 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -111,6 +111,9 @@
     protected boolean mRequireConfirmation;
     private int mUserId; // used to determine if we should show work background
 
+    private boolean mCompletedAnimatingIn;
+    private boolean mPendingDismissDialog;
+
     protected abstract int getHintStringResourceId();
     protected abstract int getAuthenticatedAccessibilityResourceId();
     protected abstract int getIconDescriptionResourceId();
@@ -332,6 +335,7 @@
             mDialog.setAlpha(1.0f);
             mDialog.setTranslationY(0);
             mLayout.setAlpha(1.0f);
+            mCompletedAnimatingIn = true;
         } else {
             // Dim the background and slide the dialog up
             mDialog.setTranslationY(mAnimationTranslationOffset);
@@ -352,6 +356,12 @@
     }
 
     public void startDismiss() {
+        if (!mCompletedAnimatingIn) {
+            Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn");
+            mPendingDismissDialog = true;
+            return;
+        }
+
         mAnimatingAway = true;
 
         // This is where final cleanup should occur.
@@ -499,6 +509,13 @@
     }
 
     public void onDialogAnimatedIn() {
+        mCompletedAnimatingIn = true;
+
+        if (mPendingDismissDialog) {
+            Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now");
+            startDismiss();
+            mPendingDismissDialog = false;
+        }
     }
 
     public void restoreState(Bundle bundle) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index 729242e..ae6cb5c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -460,6 +460,7 @@
 
     @Override
     public void onDialogAnimatedIn() {
+        super.onDialogAnimatedIn();
         mDialogAnimatedIn = true;
         mIconController.startPulsing();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index 0041b0c..ea175ed 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -239,4 +239,8 @@
     public void dump(PrintWriter pw) {
 
     }
+
+    @Override
+    public void cleanup() {
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
index 6fb6467..fba0d50 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
@@ -67,8 +67,8 @@
             Sensor.TYPE_LIGHT,
             Sensor.TYPE_ROTATION_VECTOR,
     };
-    private static final String FALSING_REMAIN_LOCKED = "falsing_failure_after_attempts";
-    private static final String FALSING_SUCCESS = "falsing_success_after_attempts";
+    public static final String FALSING_REMAIN_LOCKED = "falsing_failure_after_attempts";
+    public static final String FALSING_SUCCESS = "falsing_success_after_attempts";
 
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final Context mContext;
@@ -168,6 +168,7 @@
                     .append("enabled=").append(isEnabled() ? 1 : 0)
                     .append(" mScreenOn=").append(mScreenOn ? 1 : 0)
                     .append(" mState=").append(StatusBarState.toShortString(mState))
+                    .append(" mShowingAod=").append(mShowingAod ? 1 : 0)
                     .toString()
             );
         }
@@ -550,6 +551,14 @@
         pw.println();
     }
 
+    @Override
+    public void cleanup() {
+        mSensorManager.unregisterListener(mSensorEventListener);
+        mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
+        Dependency.get(StatusBarStateController.class).removeCallback(mStatusBarStateListener);
+        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mKeyguardUpdateCallback);
+    }
+
     public Uri reportRejectedTouch() {
         if (mDataCollector.isEnabled()) {
             return mDataCollector.reportRejectedTouch();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 3cc8ec9a..128cc61 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -65,6 +65,7 @@
             public void onPluginConnected(FalsingPlugin plugin, Context context) {
                 FalsingManager pluginFalsingManager = plugin.getFalsingManager(context);
                 if (pluginFalsingManager != null) {
+                    mInternalFalsingManager.cleanup();
                     mInternalFalsingManager = pluginFalsingManager;
                 }
             }
@@ -91,7 +92,11 @@
     @VisibleForTesting
     public void setupFalsingManager(Context context) {
         boolean brightlineEnabled = DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, false);
+                DeviceConfig.NAMESPACE_SYSTEMUI, BRIGHTLINE_FALSING_MANAGER_ENABLED, true);
+
+        if (mInternalFalsingManager != null) {
+            mInternalFalsingManager.cleanup();
+        }
         if (!brightlineEnabled) {
             mInternalFalsingManager = new FalsingManagerImpl(context);
         } else {
@@ -290,4 +295,9 @@
     public void dump(PrintWriter pw) {
         mInternalFalsingManager.dump(pw);
     }
+
+    @Override
+    public void cleanup() {
+        mInternalFalsingManager.cleanup();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index 19c46e4..41f20ec 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.classifier.brightline;
 
+import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_REMAIN_LOCKED;
+import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_SUCCESS;
+
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
@@ -24,6 +27,7 @@
 import android.util.Log;
 import android.view.MotionEvent;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.plugins.FalsingManager;
 
@@ -44,6 +48,8 @@
     private final SensorManager mSensorManager;
     private final FalsingDataProvider mDataProvider;
     private boolean mSessionStarted;
+    private MetricsLogger mMetricsLogger;
+    private int mIsFalseTouchCalls;
 
     private final ExecutorService mBackgroundExecutor = Executors.newSingleThreadExecutor();
 
@@ -64,6 +70,7 @@
             SensorManager sensorManager) {
         mDataProvider = falsingDataProvider;
         mSensorManager = sensorManager;
+        mMetricsLogger = new MetricsLogger();
         mClassifiers = new ArrayList<>();
         DistanceClassifier distanceClassifier = new DistanceClassifier(mDataProvider);
         ProximityClassifier proximityClassifier = new ProximityClassifier(distanceClassifier,
@@ -98,10 +105,12 @@
     }
 
     private void sessionStart() {
-        logDebug("Starting Session");
-        mSessionStarted = true;
-        registerSensors();
-        mClassifiers.forEach(FalsingClassifier::onSessionStarted);
+        if (!mSessionStarted) {
+            logDebug("Starting Session");
+            mSessionStarted = true;
+            registerSensors();
+            mClassifiers.forEach(FalsingClassifier::onSessionStarted);
+        }
     }
 
     private void sessionEnd() {
@@ -111,6 +120,10 @@
             unregisterSensors();
             mDataProvider.onSessionEnd();
             mClassifiers.forEach(FalsingClassifier::onSessionEnded);
+            if (mIsFalseTouchCalls != 0) {
+                mMetricsLogger.histogram(FALSING_REMAIN_LOCKED, mIsFalseTouchCalls);
+                mIsFalseTouchCalls = 0;
+            }
         }
     }
 
@@ -157,6 +170,10 @@
 
     @Override
     public void onSucccessfulUnlock() {
+        if (mIsFalseTouchCalls != 0) {
+            mMetricsLogger.histogram(FALSING_SUCCESS, mIsFalseTouchCalls);
+            mIsFalseTouchCalls = 0;
+        }
     }
 
     @Override
@@ -309,6 +326,11 @@
     public void dump(PrintWriter printWriter) {
     }
 
+    @Override
+    public void cleanup() {
+        unregisterSensors();
+    }
+
     static void logDebug(String msg) {
         logDebug(msg, null);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
index 730907e..cc66454 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
@@ -16,9 +16,13 @@
 
 package com.android.systemui.classifier.brightline;
 
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE;
 import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
 import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
 
+import android.provider.DeviceConfig;
+
 /**
  * False on swipes that are too close to 45 degrees.
  *
@@ -35,8 +39,20 @@
     private static final float ONE_HUNDRED_EIGHTY_DEG = (float) (Math.PI);
     private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI);
 
+    private final float mHorizontalAngleRange;
+    private final float mVerticalAngleRange;
+
     DiagonalClassifier(FalsingDataProvider dataProvider) {
         super(dataProvider);
+
+        mHorizontalAngleRange = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE,
+                HORIZONTAL_ANGLE_RANGE);
+        mVerticalAngleRange = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE,
+                VERTICAL_ANGLE_RANGE);
     }
 
     @Override
@@ -52,11 +68,11 @@
             return false;
         }
 
-        float minAngle = DIAGONAL - HORIZONTAL_ANGLE_RANGE;
-        float maxAngle = DIAGONAL + HORIZONTAL_ANGLE_RANGE;
+        float minAngle = DIAGONAL - mHorizontalAngleRange;
+        float maxAngle = DIAGONAL + mHorizontalAngleRange;
         if (isVertical()) {
-            minAngle = DIAGONAL - VERTICAL_ANGLE_RANGE;
-            maxAngle = DIAGONAL + VERTICAL_ANGLE_RANGE;
+            minAngle = DIAGONAL - mVerticalAngleRange;
+            maxAngle = DIAGONAL + mVerticalAngleRange;
         }
 
         return angleBetween(angle, minAngle, maxAngle)
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
index 005ee12..a6a617d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
@@ -16,6 +16,14 @@
 
 package com.android.systemui.classifier.brightline;
 
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_SCREEN_FRACTION_MAX_DISTANCE;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VELOCITY_TO_DISTANCE;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN;
+
+import android.provider.DeviceConfig;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 
@@ -31,12 +39,13 @@
     private static final float HORIZONTAL_SWIPE_THRESHOLD_DISTANCE_IN = 3;
     private static final float VERTICAL_SWIPE_THRESHOLD_DISTANCE_IN = 3;
     private static final float VELOCITY_TO_DISTANCE = 80f;
-    private static final float SCREEN_FRACTION_MIN_DISTANCE = 0.8f;
+    private static final float SCREEN_FRACTION_MAX_DISTANCE = 0.8f;
 
     private final float mVerticalFlingThresholdPx;
     private final float mHorizontalFlingThresholdPx;
     private final float mVerticalSwipeThresholdPx;
     private final float mHorizontalSwipeThresholdPx;
+    private final float mVelocityToDistanceMultiplier;
 
     private boolean mDistanceDirty;
     private DistanceVectors mCachedDistance;
@@ -44,18 +53,48 @@
     DistanceClassifier(FalsingDataProvider dataProvider) {
         super(dataProvider);
 
+        mVelocityToDistanceMultiplier = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_DISTANCE_VELOCITY_TO_DISTANCE,
+                VELOCITY_TO_DISTANCE);
+
+        float horizontalFlingThresholdIn = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN,
+                HORIZONTAL_FLING_THRESHOLD_DISTANCE_IN);
+
+        float verticalFlingThresholdIn = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN,
+                VERTICAL_FLING_THRESHOLD_DISTANCE_IN);
+
+        float horizontalSwipeThresholdIn = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN,
+                HORIZONTAL_SWIPE_THRESHOLD_DISTANCE_IN);
+
+        float verticalSwipeThresholdIn = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN,
+                VERTICAL_SWIPE_THRESHOLD_DISTANCE_IN);
+
+        float screenFractionMaxDistance = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_DISTANCE_SCREEN_FRACTION_MAX_DISTANCE,
+                SCREEN_FRACTION_MAX_DISTANCE);
+
         mHorizontalFlingThresholdPx = Math
-                .min(getWidthPixels() * SCREEN_FRACTION_MIN_DISTANCE,
-                        HORIZONTAL_FLING_THRESHOLD_DISTANCE_IN * getXdpi());
+                .min(getWidthPixels() * screenFractionMaxDistance,
+                        horizontalFlingThresholdIn * getXdpi());
         mVerticalFlingThresholdPx = Math
-                .min(getHeightPixels() * SCREEN_FRACTION_MIN_DISTANCE,
-                        VERTICAL_FLING_THRESHOLD_DISTANCE_IN * getYdpi());
+                .min(getHeightPixels() * screenFractionMaxDistance,
+                        verticalFlingThresholdIn * getYdpi());
         mHorizontalSwipeThresholdPx = Math
-                .min(getWidthPixels() * SCREEN_FRACTION_MIN_DISTANCE,
-                        HORIZONTAL_SWIPE_THRESHOLD_DISTANCE_IN * getXdpi());
+                .min(getWidthPixels() * screenFractionMaxDistance,
+                        horizontalSwipeThresholdIn * getXdpi());
         mVerticalSwipeThresholdPx = Math
-                .min(getHeightPixels() * SCREEN_FRACTION_MIN_DISTANCE,
-                        VERTICAL_SWIPE_THRESHOLD_DISTANCE_IN * getYdpi());
+                .min(getHeightPixels() * screenFractionMaxDistance,
+                        verticalSwipeThresholdIn * getYdpi());
         mDistanceDirty = true;
     }
 
@@ -139,18 +178,18 @@
         }
 
         boolean getPassedFlingThreshold() {
-            float dX = this.mDx + this.mVx * VELOCITY_TO_DISTANCE;
-            float dY = this.mDy + this.mVy * VELOCITY_TO_DISTANCE;
+            float dX = this.mDx + this.mVx * mVelocityToDistanceMultiplier;
+            float dY = this.mDy + this.mVy * mVelocityToDistanceMultiplier;
 
             if (isHorizontal()) {
                 logDebug("Horizontal swipe and fling distance: " + this.mDx + ", "
-                        + this.mVx * VELOCITY_TO_DISTANCE);
+                        + this.mVx * mVelocityToDistanceMultiplier);
                 logDebug("Threshold: " + mHorizontalFlingThresholdPx);
                 return Math.abs(dX) >= mHorizontalFlingThresholdPx;
             }
 
             logDebug("Vertical swipe and fling distance: " + this.mDy + ", "
-                    + this.mVy * VELOCITY_TO_DISTANCE);
+                    + this.mVy * mVelocityToDistanceMultiplier);
             logDebug("Threshold: " + mVerticalFlingThresholdPx);
             return Math.abs(dY) >= mVerticalFlingThresholdPx;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
index 94a8ac85..2644bf9 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
@@ -16,10 +16,12 @@
 
 package com.android.systemui.classifier.brightline;
 
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
 
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
+import android.provider.DeviceConfig;
 import android.view.MotionEvent;
 
 
@@ -31,8 +33,9 @@
  */
 class ProximityClassifier extends FalsingClassifier {
 
-    private static final double PERCENT_COVERED_THRESHOLD = 0.1;
+    private static final float PERCENT_COVERED_THRESHOLD = 0.1f;
     private final DistanceClassifier mDistanceClassifier;
+    private final float mPercentCoveredThreshold;
 
     private boolean mNear;
     private long mGestureStartTimeNs;
@@ -44,6 +47,11 @@
             FalsingDataProvider dataProvider) {
         super(dataProvider);
         this.mDistanceClassifier = distanceClassifier;
+
+        mPercentCoveredThreshold = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD,
+                PERCENT_COVERED_THRESHOLD);
     }
 
     @Override
@@ -107,7 +115,7 @@
 
         logInfo("Percent of gesture in proximity: " + mPercentNear);
 
-        if (mPercentNear > PERCENT_COVERED_THRESHOLD) {
+        if (mPercentNear > mPercentCoveredThreshold) {
             return !mDistanceClassifier.isLongSwipe();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
index a62574f..c58b7db 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
@@ -16,7 +16,13 @@
 
 package com.android.systemui.classifier.brightline;
 
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE;
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE;
+
 import android.graphics.Point;
+import android.provider.DeviceConfig;
 import android.view.MotionEvent;
 
 import java.util.ArrayList;
@@ -37,8 +43,34 @@
     private static final float MAX_X_SECONDARY_DEVIANCE = .3f;
     private static final float MAX_Y_SECONDARY_DEVIANCE = .3f;
 
+    private final float mMaxXPrimaryDeviance;
+    private final float mMaxYPrimaryDeviance;
+    private final float mMaxXSecondaryDeviance;
+    private final float mMaxYSecondaryDeviance;
+
     ZigZagClassifier(FalsingDataProvider dataProvider) {
         super(dataProvider);
+
+        mMaxXPrimaryDeviance = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE,
+                MAX_X_PRIMARY_DEVIANCE);
+
+        mMaxYPrimaryDeviance = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE,
+                MAX_Y_PRIMARY_DEVIANCE);
+
+        mMaxXSecondaryDeviance = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE,
+                MAX_X_SECONDARY_DEVIANCE);
+
+        mMaxYSecondaryDeviance = DeviceConfig.getFloat(
+                DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE,
+                MAX_Y_SECONDARY_DEVIANCE);
+
     }
 
     @Override
@@ -98,11 +130,11 @@
         float maxXDeviance;
         float maxYDeviance;
         if (actualDx > actualDy) {
-            maxXDeviance = MAX_X_PRIMARY_DEVIANCE * totalDistanceIn * getXdpi();
-            maxYDeviance = MAX_Y_SECONDARY_DEVIANCE * totalDistanceIn * getYdpi();
+            maxXDeviance = mMaxXPrimaryDeviance * totalDistanceIn * getXdpi();
+            maxYDeviance = mMaxYSecondaryDeviance * totalDistanceIn * getYdpi();
         } else {
-            maxXDeviance = MAX_X_SECONDARY_DEVIANCE * totalDistanceIn * getXdpi();
-            maxYDeviance = MAX_Y_PRIMARY_DEVIANCE * totalDistanceIn * getYdpi();
+            maxXDeviance = mMaxXSecondaryDeviance * totalDistanceIn * getXdpi();
+            maxYDeviance = mMaxYPrimaryDeviance * totalDistanceIn * getYdpi();
         }
 
         logDebug("Straightness Deviance: (" + devianceX + "," + devianceY + ") vs "
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index 0e93f42..d3e8b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -77,7 +77,7 @@
     protected void extractWallpaperColors() {
         super.extractWallpaperColors();
         // mTonal is final but this method will be invoked by the base class during its ctor.
-        if (mTonal == null) {
+        if (mTonal == null || mNeutralColorsLock == null) {
             return;
         }
         mTonal.applyFallback(mLockColors == null ? mSystemColors : mLockColors, mNeutralColorsLock);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 537c09e..1bc7e63 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -30,6 +30,7 @@
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.AsyncSensorManager;
 import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -70,7 +71,7 @@
                 new DozeScreenState(wrappedService, handler, params, wakeLock),
                 createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
                         handler),
-                new DozeWallpaperState(context),
+                new DozeWallpaperState(context, getBiometricUnlockController(dozeService)),
                 new DozeDockHandler(context, machine, host, config, handler, dockManager),
                 new DozeAuthRemover(dozeService)
         });
@@ -108,4 +109,10 @@
         final SystemUIApplication app = (SystemUIApplication) appCandidate;
         return app.getComponent(DozeHost.class);
     }
+
+    public static BiometricUnlockController getBiometricUnlockController(DozeService service) {
+        Application appCandidate = service.getApplication();
+        final SystemUIApplication app = (SystemUIApplication) appCandidate;
+        return app.getComponent(BiometricUnlockController.class);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 3c9d4a9..ae6dac5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -50,9 +50,23 @@
      */
     void onSlpiTap(float x, float y);
 
+    /**
+     * Artificially dim down the the display by changing scrim opacities.
+     * @param scrimOpacity opacity from 0 to 1.
+     */
     default void setAodDimmingScrim(float scrimOpacity) {}
+
+    /**
+     * Sets the actual display brightness.
+     * @param value from 0 to 255.
+     */
     void setDozeScreenBrightness(int value);
 
+    /**
+     * Makes scrims black and changes animation durations.
+     */
+    default void prepareForGentleWakeUp() {}
+
     void onIgnoreTouchWhilePulsing(boolean ignore);
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 5be097c..38ee2fe 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -82,7 +82,10 @@
         boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
         boolean pulseEnding = oldState  == DozeMachine.State.DOZE_PULSE_DONE
                 && newState == DozeMachine.State.DOZE_AOD;
-        if (messagePending || oldState == DozeMachine.State.INITIALIZED || pulseEnding) {
+        boolean turningOn = (oldState == DozeMachine.State.DOZE_AOD_PAUSED
+                || oldState  == DozeMachine.State.DOZE) && newState == DozeMachine.State.DOZE_AOD;
+        boolean justInitialized = oldState == DozeMachine.State.INITIALIZED;
+        if (messagePending || justInitialized || pulseEnding || turningOn) {
             // During initialization, we hide the navigation bar. That is however only applied after
             // a traversal; setting the screen state here is immediate however, so it can happen
             // that the screen turns on again before the navigation bar is hidden. To work around
@@ -91,7 +94,7 @@
 
             // Delay screen state transitions even longer while animations are running.
             boolean shouldDelayTransition = newState == DozeMachine.State.DOZE_AOD
-                    && mParameters.shouldControlScreenOff();
+                    && mParameters.shouldControlScreenOff() && !turningOn;
 
             if (shouldDelayTransition) {
                 mWakeLock.setAcquired(true);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index cf04b7f..f6a921d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -43,6 +43,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.R;
 import com.android.systemui.plugins.SensorManagerPlugin;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.AlarmTimeout;
@@ -198,7 +199,10 @@
         updateListening();
     }
 
-    private void updateListening() {
+    /**
+     * Registers/unregisters sensors based on internal state.
+     */
+    public void updateListening() {
         boolean anyListening = false;
         for (TriggerSensor s : mSensors) {
             // We don't want to be listening while we're PAUSED (prox sensor is covered)
@@ -231,7 +235,7 @@
 
     public void onUserSwitched() {
         for (TriggerSensor s : mSensors) {
-            s.updateListener();
+            s.updateListening();
         }
     }
 
@@ -246,7 +250,7 @@
                 return;
             }
             for (TriggerSensor s : mSensors) {
-                s.updateListener();
+                s.updateListening();
             }
         }
     };
@@ -287,12 +291,21 @@
         long mLastNear;
         final AlarmTimeout mCooldownTimer;
         final AlwaysOnDisplayPolicy mPolicy;
-
+        final Sensor mSensor;
 
         public ProxSensor(AlwaysOnDisplayPolicy policy) {
             mPolicy = policy;
             mCooldownTimer = new AlarmTimeout(mAlarmManager, this::updateRegistered,
                     "prox_cooldown", mHandler);
+
+            // The default prox sensor can be noisy, so let's use a prox gated brightness sensor
+            // if available.
+            Sensor sensor = DozeSensors.findSensorWithType(mSensorManager,
+                    mContext.getString(R.string.doze_brightness_sensor_type));
+            if (sensor == null) {
+                sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+            }
+            mSensor = sensor;
         }
 
         void setRequested(boolean requested) {
@@ -356,8 +369,9 @@
 
         @Override
         public String toString() {
-            return String.format("{registered=%s, requested=%s, coolingDown=%s, currentlyFar=%s}",
-                    mRegistered, mRequested, mCooldownTimer.isScheduled(), mCurrentlyFar);
+            return String.format("{registered=%s, requested=%s, coolingDown=%s, currentlyFar=%s,"
+                    + " sensor=%s}", mRegistered, mRequested, mCooldownTimer.isScheduled(),
+                    mCurrentlyFar, mSensor);
         }
     }
 
@@ -409,22 +423,22 @@
         public void setListening(boolean listen) {
             if (mRequested == listen) return;
             mRequested = listen;
-            updateListener();
+            updateListening();
         }
 
         public void setDisabled(boolean disabled) {
             if (mDisabled == disabled) return;
             mDisabled = disabled;
-            updateListener();
+            updateListening();
         }
 
         public void ignoreSetting(boolean ignored) {
             if (mIgnoresSetting == ignored) return;
             mIgnoresSetting = ignored;
-            updateListener();
+            updateListening();
         }
 
-        public void updateListener() {
+        public void updateListening() {
             if (!mConfigured || mSensor == null) return;
             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
                     && !mRegistered) {
@@ -480,7 +494,7 @@
                 mCallback.onSensorPulse(mPulseReason, mSensorPerformsProxCheck, screenX, screenY,
                         event.values);
                 if (!mRegistered) {
-                    updateListener();  // reregister, this sensor only fires once
+                    updateListening();  // reregister, this sensor only fires once
                 }
             }));
         }
@@ -541,7 +555,7 @@
         }
 
         @Override
-        public void updateListener() {
+        public void updateListening() {
             if (!mConfigured) return;
             AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
             if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 97b08d5..8ef01e8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -201,7 +201,7 @@
             // Let's prepare the display to wake-up by drawing black.
             // This will cover the hardware wake-up sequence, where the display
             // becomes black for a few frames.
-            mDozeHost.setAodDimmingScrim(255f);
+            mDozeHost.setAodDimmingScrim(1f);
         }
         mMachine.wakeUp();
     }
@@ -314,6 +314,9 @@
                 break;
             case DOZE_PULSE_DONE:
                 mDozeSensors.requestTemporaryDisable();
+                // A pulse will temporarily disable sensors that require a touch screen.
+                // Let's make sure that they are re-enabled when the pulse is over.
+                mDozeSensors.updateListening();
                 break;
             case FINISH:
                 mBroadcastReceiver.unregister(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 51e96d2..1f33af8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.doze;
 
+import static com.android.systemui.doze.DozeMachine.State.DOZE;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
 
 import android.app.AlarmManager;
@@ -116,7 +117,7 @@
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
         switch (newState) {
             case DOZE_AOD:
-                if (oldState == DOZE_AOD_PAUSED) {
+                if (oldState == DOZE_AOD_PAUSED || oldState == DOZE) {
                     // Whenever turning on the display, it's necessary to push a new frame.
                     // The display buffers will be empty and need to be filled.
                     mHost.dozeTimeTick();
@@ -130,6 +131,7 @@
                 break;
             case DOZE:
             case DOZE_AOD_PAUSED:
+                mHost.prepareForGentleWakeUp();
                 unscheduleTimeTick();
                 break;
             case DOZE_REQUEST_PULSE:
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index 1b3cd88..35c8b74 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -24,6 +24,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.DozeParameters;
 
 import java.io.PrintWriter;
@@ -38,18 +39,22 @@
 
     private final IWallpaperManager mWallpaperManagerService;
     private final DozeParameters mDozeParameters;
+    private final BiometricUnlockController mBiometricUnlockController;
     private boolean mIsAmbientMode;
 
-    public DozeWallpaperState(Context context) {
+    public DozeWallpaperState(Context context,
+            BiometricUnlockController biometricUnlockController) {
         this(IWallpaperManager.Stub.asInterface(
                 ServiceManager.getService(Context.WALLPAPER_SERVICE)),
+                biometricUnlockController,
                 DozeParameters.getInstance(context));
     }
 
     @VisibleForTesting
     DozeWallpaperState(IWallpaperManager wallpaperManagerService,
-            DozeParameters parameters) {
+            BiometricUnlockController biometricUnlockController, DozeParameters parameters) {
         mWallpaperManagerService = wallpaperManagerService;
+        mBiometricUnlockController = biometricUnlockController;
         mDozeParameters = parameters;
     }
 
@@ -76,7 +81,9 @@
         } else {
             boolean wakingUpFromPulse = oldState == DozeMachine.State.DOZE_PULSING
                     && newState == DozeMachine.State.FINISH;
-            animated = !mDozeParameters.getDisplayNeedsBlanking() || wakingUpFromPulse;
+            boolean fastDisplay = !mDozeParameters.getDisplayNeedsBlanking();
+            animated = (fastDisplay && !mBiometricUnlockController.unlockedByWakeAndUnlock())
+                    || wakingUpFromPulse;
         }
 
         if (isAmbientMode != mIsAmbientMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 5136682..48f32cf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -52,6 +52,7 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
@@ -62,7 +63,6 @@
 import com.android.systemui.util.wakelock.WakeLock;
 
 import java.util.Date;
-import java.util.HashSet;
 import java.util.Locale;
 import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
@@ -128,6 +128,7 @@
     private CharSequence mMediaTitle;
     private CharSequence mMediaArtist;
     protected boolean mDozing;
+    private int mStatusBarState;
     private boolean mMediaIsVisible;
 
     /**
@@ -231,7 +232,11 @@
     protected boolean needsMediaLocked() {
         boolean keepWhenAwake = mKeyguardBypassController != null
                 && mKeyguardBypassController.getBypassEnabled() && mDozeParameters.getAlwaysOn();
-        return !TextUtils.isEmpty(mMediaTitle) && mMediaIsVisible && (mDozing || keepWhenAwake);
+        // Show header if music is playing and the status bar is in the shade state. This way, an
+        // animation isn't necessary when pressing power and transitioning to AOD.
+        boolean keepWhenShade = mStatusBarState == StatusBarState.SHADE && mMediaIsVisible;
+        return !TextUtils.isEmpty(mMediaTitle) && mMediaIsVisible && (mDozing || keepWhenAwake
+                || keepWhenShade);
     }
 
     protected void addMediaLocked(ListBuilder listBuilder) {
@@ -458,7 +463,7 @@
         synchronized (this) {
             boolean nextVisible = NotificationMediaManager.isPlayingState(state);
             mHandler.removeCallbacksAndMessages(mMediaToken);
-            if (mMediaIsVisible && !nextVisible) {
+            if (mMediaIsVisible && !nextVisible && mStatusBarState != StatusBarState.SHADE) {
                 // We need to delay this event for a few millis when stopping to avoid jank in the
                 // animation. The media app might not send its update when buffering, and the slice
                 // would end up without a header for 0.5 second.
@@ -515,5 +520,14 @@
 
     @Override
     public void onStateChanged(int newState) {
+        final boolean notify;
+        synchronized (this) {
+            boolean needsMedia = needsMediaLocked();
+            mStatusBarState = newState;
+            notify = needsMedia != needsMediaLocked();
+        }
+        if (notify) {
+            notifyChange();
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 819ce5f..6b2721a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -210,6 +210,7 @@
     private boolean mBootCompleted;
     private boolean mBootSendUserPresent;
     private boolean mShuttingDown;
+    private boolean mDozing;
 
     /** High level access to the power manager for WakeLocks */
     private PowerManager mPM;
@@ -713,11 +714,10 @@
                 com.android.keyguard.R.bool.config_enableKeyguardService)) {
             setShowingLocked(!shouldWaitForProvisioning()
                     && !mLockPatternUtils.isLockScreenDisabled(
-                            KeyguardUpdateMonitor.getCurrentUser()),
-                    mAodShowing, true /* forceCallbacks */);
+                            KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
         } else {
             // The system's keyguard is disabled or missing.
-            setShowingLocked(false, mAodShowing, true);
+            setShowingLocked(false /* showing */, true /* forceCallbacks */);
         }
 
         mStatusBarKeyguardViewManager =
@@ -1326,7 +1326,7 @@
             if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
                 if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
                 // Without this, settings is not enabled until the lock screen first appears
-                setShowingLocked(false, mAodShowing);
+                setShowingLocked(false);
                 hideLocked();
                 return;
             }
@@ -1742,6 +1742,9 @@
 
     private void updateActivityLockScreenState(boolean showing, boolean aodShowing) {
         mUiOffloadThread.submit(() -> {
+            if (DEBUG) {
+                Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ")");
+            }
             try {
                 ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing);
             } catch (RemoteException e) {
@@ -1767,10 +1770,10 @@
                 if (DEBUG) Log.d(TAG, "handleShow");
             }
 
-            setShowingLocked(true, mAodShowing);
-            mStatusBarKeyguardViewManager.show(options);
             mHiding = false;
             mWakeAndUnlocking = false;
+            setShowingLocked(true);
+            mStatusBarKeyguardViewManager.show(options);
             resetKeyguardDonePendingLocked();
             mHideAnimationRun = false;
             adjustStatusBarLocked();
@@ -1877,7 +1880,7 @@
 
             if (!mHiding) {
                 // Tell ActivityManager that we canceled the keyguardExitAnimation.
-                setShowingLocked(mShowing, mAodShowing, true /* force */);
+                setShowingLocked(mShowing, true /* force */);
                 return;
             }
             mHiding = false;
@@ -1898,8 +1901,8 @@
                 playSounds(false);
             }
 
+            setShowingLocked(false);
             mWakeAndUnlocking = false;
-            setShowingLocked(false, mAodShowing);
             mDismissCallbackRegistry.notifyDismissSucceeded();
             mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
             resetKeyguardDonePendingLocked();
@@ -1959,7 +1962,7 @@
         Trace.beginSection("KeyguardViewMediator#handleVerifyUnlock");
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
-            setShowingLocked(true, mAodShowing);
+            setShowingLocked(true);
             mStatusBarKeyguardViewManager.dismissAndCollapse();
         }
         Trace.endSection();
@@ -2107,6 +2110,8 @@
         pw.print("  mDeviceInteractive: "); pw.println(mDeviceInteractive);
         pw.print("  mGoingToSleep: "); pw.println(mGoingToSleep);
         pw.print("  mHiding: "); pw.println(mHiding);
+        pw.print("  mDozing: "); pw.println(mDozing);
+        pw.print("  mAodShowing: "); pw.println(mAodShowing);
         pw.print("  mWaitingUntilKeyguardVisible: "); pw.println(mWaitingUntilKeyguardVisible);
         pw.print("  mKeyguardDonePending: "); pw.println(mKeyguardDonePending);
         pw.print("  mHideAnimationRun: "); pw.println(mHideAnimationRun);
@@ -2117,10 +2122,14 @@
     }
 
     /**
-     * @param aodShowing true when AOD - or ambient mode - is showing.
+     * @param dozing true when AOD - or ambient mode - is showing.
      */
-    public void setAodShowing(boolean aodShowing) {
-        setShowingLocked(mShowing, aodShowing);
+    public void setDozing(boolean dozing) {
+        if (dozing == mDozing) {
+            return;
+        }
+        mDozing = dozing;
+        setShowingLocked(mShowing);
     }
 
     /**
@@ -2141,19 +2150,18 @@
         }
     }
 
-    private void setShowingLocked(boolean showing, boolean aodShowing) {
-        setShowingLocked(showing, aodShowing, false /* forceCallbacks */);
+    private void setShowingLocked(boolean showing) {
+        setShowingLocked(showing, false /* forceCallbacks */);
     }
 
-    private void setShowingLocked(boolean showing, boolean aodShowing, boolean forceCallbacks) {
+    private void setShowingLocked(boolean showing, boolean forceCallbacks) {
+        final boolean aodShowing = mDozing && !mWakeAndUnlocking;
         final boolean notifyDefaultDisplayCallbacks = showing != mShowing
                 || aodShowing != mAodShowing || forceCallbacks;
+        mShowing = showing;
+        mAodShowing = aodShowing;
         if (notifyDefaultDisplayCallbacks) {
-            mShowing = showing;
-            mAodShowing = aodShowing;
-            if (notifyDefaultDisplayCallbacks) {
-                notifyDefaultDisplayCallbacks(showing);
-            }
+            notifyDefaultDisplayCallbacks(showing);
             updateActivityLockScreenState(showing, aodShowing);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 46d53e4..14459d6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -414,6 +414,7 @@
             if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
                     pinnedStackInfo.taskIds.length > 0) {
                 Intent intent = new Intent(mContext, PipMenuActivity.class);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
                 intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
                 if (stackBounds != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index a9896f5..822a666 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -22,6 +22,8 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
+import android.content.ContentResolver;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -48,6 +50,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.text.SimpleDateFormat;
@@ -158,19 +161,34 @@
             case ACTION_STOP:
                 stopRecording();
 
-                // Move temp file to user directory
-                File recordDir = new File(
-                        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),
-                        RECORD_DIR);
-                recordDir.mkdirs();
-
                 String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
                         .format(new Date());
-                Path path = new File(recordDir, fileName).toPath();
 
+                ContentValues values = new ContentValues();
+                values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
+                values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
+                values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis());
+                values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
+
+                ContentResolver resolver = getContentResolver();
+                Uri collectionUri = MediaStore.Video.Media.getContentUri(
+                        MediaStore.VOLUME_EXTERNAL_PRIMARY);
+                Uri itemUri = resolver.insert(collectionUri, values);
+
+                File recordDir = new File(getExternalFilesDir(Environment.DIRECTORY_MOVIES),
+                        RECORD_DIR);
+                recordDir.mkdirs();
+                Path path = new File(recordDir, fileName).toPath();
                 try {
+                    // Move file out of temp directory
                     Files.move(mTempFile.toPath(), path);
-                    Notification notification = createSaveNotification(path);
+
+                    // Add to the mediastore
+                    OutputStream os = resolver.openOutputStream(itemUri, "w");
+                    Files.copy(path, os);
+                    os.close();
+
+                    Notification notification = createSaveNotification(itemUri, path);
                     notificationManager.notify(NOTIFICATION_ID, notification);
                 } catch (IOException e) {
                     e.printStackTrace();
@@ -352,13 +370,12 @@
         notificationManager.notify(NOTIFICATION_ID, mRecordingNotificationBuilder.build());
     }
 
-    private Notification createSaveNotification(Path path) {
-        Uri saveUri = FileProvider.getUriForFile(this, FILE_PROVIDER, path.toFile());
-        Log.d(TAG, "Screen recording saved to " + path.toString());
+    private Notification createSaveNotification(Uri uri, Path path) {
+        Log.d(TAG, "Screen recording saved to " + uri.toString() + ", " + path.toString());
 
         Intent viewIntent = new Intent(Intent.ACTION_VIEW)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION)
-                .setDataAndType(saveUri, "video/mp4");
+                .setDataAndType(uri, "video/mp4");
 
         Notification.Action shareAction = new Notification.Action.Builder(
                 Icon.createWithResource(this, R.drawable.ic_android),
@@ -366,7 +383,7 @@
                 PendingIntent.getService(
                         this,
                         REQUEST_CODE,
-                        getShareIntent(this, path.toString()),
+                        getShareIntent(this, uri.toString()),
                         PendingIntent.FLAG_UPDATE_CURRENT))
                 .build();
 
@@ -376,7 +393,7 @@
                 PendingIntent.getService(
                         this,
                         REQUEST_CODE,
-                        getDeleteIntent(this, path.toString()),
+                        getDeleteIntent(this, uri.toString()),
                         PendingIntent.FLAG_UPDATE_CURRENT))
                 .build();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 0fe5f8a..4cc5b21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -15,7 +15,6 @@
 package com.android.systemui.statusbar;
 
 import android.content.pm.UserInfo;
-import android.service.notification.StatusBarNotification;
 import android.util.SparseArray;
 
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -58,7 +57,7 @@
 
     boolean shouldHideNotifications(int userId);
     boolean shouldHideNotifications(String key);
-    boolean shouldShowOnKeyguard(StatusBarNotification sbn);
+    boolean shouldShowOnKeyguard(NotificationEntry entry);
 
     boolean isAnyProfilePublicMode();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 4ea1ed5..e08a5ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -33,7 +33,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -302,7 +301,7 @@
                         Notification.VISIBILITY_SECRET;
     }
 
-    public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
+    public boolean shouldShowOnKeyguard(NotificationEntry entry) {
         if (getEntryManager() == null) {
             Log.wtf(TAG, "mEntryManager was null!", new Throwable());
             return false;
@@ -310,10 +309,10 @@
         boolean exceedsPriorityThreshold;
         if (NotificationUtils.useNewInterruptionModel(mContext)
                 && hideSilentNotificationsOnLockscreen()) {
-            exceedsPriorityThreshold = getEntryManager().getNotificationData().isHighPriority(sbn);
+            exceedsPriorityThreshold = entry.isTopBucket();
         } else {
             exceedsPriorityThreshold =
-                    !getEntryManager().getNotificationData().isAmbient(sbn.getKey());
+                    !getEntryManager().getNotificationData().isAmbient(entry.key);
         }
         return mShowLockscreenNotifications && exceedsPriorityThreshold;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index f001561..00a12a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -17,6 +17,10 @@
 
 import static com.android.systemui.Dependency.MAIN_HANDLER;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController
+        .MODE_WAKE_AND_UNLOCK_PULSING;
 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_MEDIA_FAKE_ARTWORK;
 import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_LOCKSCREEN_WALLPAPER;
 import static com.android.systemui.statusbar.phone.StatusBar.SHOW_LOCKSCREEN_MEDIA_ARTWORK;
@@ -595,9 +599,11 @@
                 boolean cannotAnimateDoze = shadeController != null
                         && shadeController.isDozing()
                         && !ScrimState.AOD.getAnimateChange();
-                if (mBiometricUnlockController != null && mBiometricUnlockController.getMode()
+                boolean needsBypassFading = mKeyguardMonitor.isBypassFadingAnimation();
+                if (((mBiometricUnlockController != null && mBiometricUnlockController.getMode()
                         == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
-                        || hideBecauseOccluded || cannotAnimateDoze) {
+                                || cannotAnimateDoze) && !needsBypassFading)
+                        || hideBecauseOccluded) {
 
                     // We are unlocking directly - no animation!
                     mBackdrop.setVisibility(View.GONE);
@@ -622,9 +628,7 @@
                             });
                     if (mKeyguardMonitor.isKeyguardFadingAway()) {
                         mBackdrop.animate()
-                                // Make it disappear faster, as the focus should be on the activity
-                                // behind.
-                                .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+                                .setDuration(mKeyguardMonitor.getShortenedFadingAwayDuration())
                                 .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
                                 .setInterpolator(Interpolators.LINEAR)
                                 .start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 70ee752..c9050d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -398,7 +398,7 @@
             }
         }
 
-        if (!riv.isAttachedToWindow()) {
+        if (riv != null && !riv.isAttachedToWindow()) {
             // the remoteInput isn't attached to the window anymore :/ Let's focus on the expanded
             // one instead if it's available
             riv = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 22c9164..6e75c03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -397,15 +397,13 @@
             int userId = entry.notification.getUserId();
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
                     entry.notification) && !entry.isRowRemoved();
-            boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry
-                    .notification);
+            boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry);
             if (!showOnKeyguard) {
                 // min priority notifications should show if their summary is showing
                 if (mGroupManager.isChildInGroupWithSummary(entry.notification)) {
                     NotificationEntry summary = mGroupManager.getLogicalGroupSummary(
                             entry.notification);
-                    if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(
-                            summary.notification))         {
+                    if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(summary)) {
                         showOnKeyguard = true;
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
index ea474ce..314dc04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -21,6 +21,7 @@
 import android.provider.Settings
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -40,6 +41,7 @@
         private val bypassController: KeyguardBypassController,
         private val statusBarStateController: StatusBarStateController,
         private val headsUpManager: HeadsUpManagerPhone,
+        private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
         private val mediaManager: NotificationMediaManager,
         tunerService: TunerService) : StatusBarStateController.StateListener,
         NotificationMediaManager.MediaListener {
@@ -63,7 +65,7 @@
                     enabled = Settings.Secure.getIntForUser(
                             context.contentResolver,
                             Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING,
-                            1 /* default */,
+                            0 /* default */,
                             KeyguardUpdateMonitor.getCurrentUser()) != 0
                 }, Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING)
     }
@@ -79,9 +81,6 @@
         if (!NotificationMediaManager.isPlayingState(state)) {
             newEntry = null
         }
-        if (newEntry?.isSensitive == true) {
-            newEntry = null
-        }
         currentMediaEntry = newEntry
         updateAutoHeadsUp(previous)
         updateAutoHeadsUp(currentMediaEntry)
@@ -89,7 +88,7 @@
 
     private fun updateAutoHeadsUp(entry: NotificationEntry?) {
         entry?.let {
-            val autoHeadsUp = it == currentMediaEntry && canAutoHeadsUp()
+            val autoHeadsUp = it == currentMediaEntry && canAutoHeadsUp(it)
             it.isAutoHeadsUp = autoHeadsUp
             if (autoHeadsUp) {
                 headsUpManager.showNotification(it)
@@ -97,11 +96,36 @@
         }
     }
 
+    /**
+     * @return {@code true} if this entry be autoHeadsUpped right now.
+     */
+    private fun canAutoHeadsUp(entry: NotificationEntry): Boolean {
+        if (!isAutoHeadsUpAllowed()) {
+            return false;
+        }
+        if (entry.isSensitive) {
+            // filter sensitive notifications
+            return false
+        }
+        if (!notificationLockscreenUserManager.shouldShowOnKeyguard(entry)) {
+            // filter notifications invisible on Keyguard
+            return false
+        }
+        if (!entryManager.notificationData.activeNotifications.contains(entry)) {
+            // filter notifications not the active list currently
+            return false
+        }
+        return true
+    }
+
     override fun onStatePostChange() {
         updateAutoHeadsUp(currentMediaEntry)
     }
 
-    private fun canAutoHeadsUp() : Boolean {
+    /**
+     * @return {@code true} if autoHeadsUp is possible right now.
+     */
+    private fun isAutoHeadsUpAllowed() : Boolean {
         if (!enabled) {
             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 6a3816c..6af1f5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.statusbar.phone.PanelExpansionListener
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 
 import javax.inject.Inject
@@ -40,7 +41,8 @@
         private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
         private val statusBarStateController: StatusBarStateController,
         private val bypassController: KeyguardBypassController)
-    : OnHeadsUpChangedListener, StatusBarStateController.StateListener {
+    : OnHeadsUpChangedListener, StatusBarStateController.StateListener,
+        PanelExpansionListener {
 
     private val mNotificationVisibility
             = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
@@ -64,7 +66,6 @@
     private var mVisibilityAnimator: ObjectAnimator? = null
     private var mVisibilityAmount = 0.0f
     private var mLinearVisibilityAmount = 0.0f
-    private var mWakingUp = false
     private val mEntrySetToClearWhenFinished = mutableSetOf<NotificationEntry>()
     private val mDozeParameters: DozeParameters
     private var pulseExpanding: Boolean = false
@@ -73,6 +74,25 @@
 
     var fullyAwake: Boolean = false
 
+    var wakingUp = false
+        set(value) {
+            field = value
+            willWakeUp = false
+            if (value) {
+                if (mNotificationsVisible && !mNotificationsVisibleForExpansion
+                        && !bypassController.bypassEnabled) {
+                    // We're waking up while pulsing, let's make sure the animation looks nice
+                    mStackScroller.wakeUpFromPulse();
+                }
+                if (bypassController.bypassEnabled && !mNotificationsVisible) {
+                    // Let's make sure our huns become visible once we are waking up in case
+                    // they were blocked by the proximity sensor
+                    updateNotificationVisibility(animate = shouldAnimateVisibility(),
+                            increaseSpeed = false)
+                }
+            }
+        }
+
     var willWakeUp = false
         set(value) {
             if (!value || mDozeAmount != 0.0f) {
@@ -80,7 +100,9 @@
             }
         }
 
+    private var collapsedEnoughToHide: Boolean = false
     lateinit var iconAreaController : NotificationIconAreaController
+
     var pulsing: Boolean = false
         set(value) {
             field = value
@@ -102,7 +124,6 @@
                 }
             }
         }
-
     /**
      * True if we can show pulsing heads up notifications
      */
@@ -112,8 +133,12 @@
             var canShow = pulsing
             if (bypassController.bypassEnabled) {
                 // We also allow pulsing on the lock screen!
-                canShow = canShow || (mWakingUp || willWakeUp || fullyAwake)
+                canShow = canShow || (wakingUp || willWakeUp || fullyAwake)
                         && statusBarStateController.state == StatusBarState.KEYGUARD
+                // We want to hide the notifications when collapsed too much
+                if (collapsedEnoughToHide) {
+                    canShow = false
+                }
             }
             return canShow
         }
@@ -160,7 +185,7 @@
         wakeUpListeners.add(listener);
     }
 
-    fun removeFullyHiddenChangedListener(listener: WakeUpListener) {
+    fun removeListener(listener: WakeUpListener) {
         wakeUpListeners.remove(listener);
     }
 
@@ -169,7 +194,7 @@
         var visible = mNotificationsVisibleForExpansion || mHeadsUpManagerPhone.hasNotifications()
         visible = visible && canShowPulsingHuns
 
-        if (!visible && mNotificationsVisible && (mWakingUp || willWakeUp) && mDozeAmount != 0.0f) {
+        if (!visible && mNotificationsVisible && (wakingUp || willWakeUp) && mDozeAmount != 0.0f) {
             // let's not make notifications invisible while waking up, otherwise the animation
             // is strange
             return;
@@ -229,6 +254,18 @@
         this.state = newState
     }
 
+    override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
+        val collapsedEnough = expansion <= 0.9f
+        if (collapsedEnough != this.collapsedEnoughToHide) {
+            val couldShowPulsingHuns = canShowPulsingHuns;
+            this.collapsedEnoughToHide = collapsedEnough
+            if (couldShowPulsingHuns && !canShowPulsingHuns) {
+                updateNotificationVisibility(animate = true, increaseSpeed = true)
+                mHeadsUpManagerPhone.releaseAllImmediately()
+            }
+        }
+    }
+
     private fun updateDozeAmountIfBypass(): Boolean {
         if (bypassController.bypassEnabled) {
             var amount = 1.0f;
@@ -307,16 +344,6 @@
         return if (bypassController.bypassEnabled) 0.0f else overflow
     }
 
-    fun setWakingUp(wakingUp: Boolean) {
-        willWakeUp = false
-        mWakingUp = wakingUp
-        if (wakingUp && mNotificationsVisible && !mNotificationsVisibleForExpansion
-                && !bypassController.bypassEnabled) {
-            // We're waking up while pulsing, let's make sure the animation looks nice
-            mStackScroller.wakeUpFromPulse();
-        }
-    }
-
     override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
         var animate = shouldAnimateVisibility()
         if (!isHeadsUp) {
@@ -325,7 +352,7 @@
                     // if we animate, we see the shelf briefly visible. Instead we fully animate
                     // the notification and its background out
                     animate = false
-                } else if (!mWakingUp && !willWakeUp){
+                } else if (!wakingUp && !willWakeUp){
                     // TODO: look that this is done properly and not by anyone else
                     entry.setHeadsUpAnimatingAway(true)
                     mEntrySetToClearWhenFinished.add(entry)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index fca520f..1ce4934 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -25,7 +25,6 @@
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
-import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
@@ -108,10 +107,19 @@
             boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH
                     && isSystemNotification(nb);
 
-            boolean isHeadsUp = a.getRow().isHeadsUp();
-            if (isHeadsUp != b.getRow().isHeadsUp()) {
-                return isHeadsUp ? -1 : 1;
-            } else if (isHeadsUp) {
+
+            boolean aHeadsUp = a.getRow().isHeadsUp();
+            boolean bHeadsUp = b.getRow().isHeadsUp();
+
+            // HACK: This should really go elsewhere, but it's currently not straightforward to
+            // extract the comparison code and we're guaranteed to touch every element, so this is
+            // the best place to set the buckets for the moment.
+            a.setIsTopBucket(aHeadsUp || aMedia || aSystemMax || a.isHighPriority());
+            b.setIsTopBucket(bHeadsUp || bMedia || bSystemMax || b.isHighPriority());
+
+            if (aHeadsUp != bHeadsUp) {
+                return aHeadsUp ? -1 : 1;
+            } else if (aHeadsUp) {
                 // Provide consistent ranking with headsUpManager
                 return mHeadsUpManager.compare(a, b);
             } else if (aMedia != bMedia) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index b19d2ca..d718570 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -173,6 +173,9 @@
      * the lock screen/status bar and in the top section in the shade.
      */
     private boolean mHighPriority;
+
+    private boolean mIsTopBucket;
+
     private boolean mSensitive = true;
     private Runnable mOnSensitiveChangedListener;
     private boolean mAutoHeadsUp;
@@ -224,6 +227,18 @@
         this.mHighPriority = highPriority;
     }
 
+    /**
+     * @return True if the notif should appear in the "top" or "important" section of notifications
+     * (as opposed to the "bottom" or "silent" section). This is usually the same as
+     * {@link #isHighPriority()}, but there are certain exceptions, such as media notifs.
+     */
+    public boolean isTopBucket() {
+        return mIsTopBucket;
+    }
+    public void setIsTopBucket(boolean isTopBucket) {
+        mIsTopBucket = isTopBucket;
+    }
+
     public boolean isBubble() {
         return (notification.getNotification().flags & FLAG_BUBBLE) != 0;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index d057a1d..48a8295 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -349,7 +349,7 @@
         }
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
-            result.newPublicView = builder.makePublicContentView();
+            result.newPublicView = builder.makePublicContentView(isLowPriority);
         }
 
         result.packageContext = packageContext;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 212808d..15cc72c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -184,4 +184,6 @@
     default boolean containsView(View v) {
         return true;
     }
+
+    default void setWillExpand(boolean willExpand) {};
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 170a4d5..d119fb79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -133,7 +133,7 @@
             if (child instanceof ExpandableNotificationRow
                     && child.getVisibility() != View.GONE) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                if (!row.getEntry().isHighPriority()) {
+                if (!row.getEntry().isTopBucket()) {
                     firstGentleNotifIndex = i;
                     mFirstGentleNotif = row;
                     break;
@@ -248,7 +248,7 @@
             View child = mParent.getChildAt(i);
             if (child.getVisibility() != View.GONE && child instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                if (!row.getEntry().isHighPriority()) {
+                if (!row.getEntry().isTopBucket()) {
                     break;
                 } else {
                     lastChildBeforeGap = row;
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 bec9520..18a51b9 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
@@ -499,6 +499,7 @@
     private boolean mAnimateBottomOnLayout;
     private float mLastSentAppear;
     private float mLastSentExpandedHeight;
+    private boolean mWillExpand;
 
     @Inject
     public NotificationStackScrollLayout(
@@ -2549,13 +2550,21 @@
             }
             return;
         }
-        int minTopPosition = 0;
+        int minTopPosition;
         NotificationSection lastSection = getLastVisibleSection();
         boolean onKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
         if (!onKeyguard) {
             minTopPosition = (int) (mTopPadding + mStackTranslation);
         } else if (lastSection == null) {
             minTopPosition = mTopPadding;
+        } else {
+            // The first sections could be empty while there could still be elements in later
+            // sections. The position of these first few sections is determined by the position of
+            // the first visible section.
+            NotificationSection firstVisibleSection = getFirstVisibleSection();
+            firstVisibleSection.updateBounds(0 /* minTopPosition*/, 0 /* minBottomPosition */,
+                    false /* shiftPulsingWithFirst */);
+            minTopPosition = firstVisibleSection.getBounds().top;
         }
         boolean shiftPulsingWithFirst = mHeadsUpManager.getAllEntries().count() <= 1
                 && (mAmbientState.isDozing()
@@ -4398,6 +4407,7 @@
         mStateAnimator.setShadeExpanded(isExpanded);
         mSwipeHelper.setIsExpanded(isExpanded);
         if (changed) {
+            mWillExpand = false;
             if (!mIsExpanded) {
                 mGroupManager.collapseAllGroups();
                 mExpandHelper.cancelImmediately();
@@ -5046,7 +5056,7 @@
         if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) {
             mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
             mNeedsAnimation = true;
-            if (!mIsExpanded && !isHeadsUp) {
+            if (!mIsExpanded && !mWillExpand && !isHeadsUp) {
                 row.setHeadsUpAnimatingAway(true);
             }
             requestChildrenUpdate();
@@ -5067,6 +5077,11 @@
         requestChildrenUpdate();
     }
 
+    @Override
+    public void setWillExpand(boolean willExpand) {
+        mWillExpand = willExpand;
+    }
+
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setTrackingHeadsUp(ExpandableNotificationRow row) {
         mTrackingHeadsUp = row != null;
@@ -5667,6 +5682,8 @@
             // The bottom might change because we're using the final actual height of the view
             mAnimateBottomOnLayout = true;
         }
+        // Let's update the footer once the notifications have been updated (in the next frame)
+        post(this::updateFooter);
     }
 
     public void setOnPulseHeightChangedListener(Runnable listener) {
@@ -5737,7 +5754,7 @@
             currentIndex++;
             boolean beforeSpeedBump;
             if (mHighPriorityBeforeSpeedBump) {
-                beforeSpeedBump = row.getEntry().isHighPriority();
+                beforeSpeedBump = row.getEntry().isTopBucket();
             } else {
                 beforeSpeedBump = !row.getEntry().ambient;
             }
@@ -5795,9 +5812,9 @@
             case ROWS_ALL:
                 return true;
             case ROWS_HIGH_PRIORITY:
-                return row.getEntry().isHighPriority();
+                return row.getEntry().isTopBucket();
             case ROWS_GENTLE:
-                return !row.getEntry().isHighPriority();
+                return !row.getEntry().isTopBucket();
             default:
                 throw new IllegalArgumentException("Unknown selection: " + selection);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index cc1170f..b444fa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -83,6 +83,11 @@
         bindContents();
     }
 
+    @Override
+    public boolean isTransparent() {
+        return true;
+    }
+
     /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */
     void onUiModeChanged() {
         updateBackgroundColors();
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 35ba801..7655056 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
@@ -159,15 +159,13 @@
         float drawStart = !ambientState.isOnKeyguard() ? ambientState.getTopPadding()
                 + ambientState.getStackTranslation() + ambientState.getExpandAnimationTopChange()
                 : 0;
-        float previousNotificationEnd = 0;
-        float previousNotificationStart = 0;
+        float clipStart = 0;
         int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
             ExpandableViewState state = child.getViewState();
             if (!child.mustStayOnScreen() || state.headsUpIsVisible) {
-                previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
-                previousNotificationStart = Math.max(drawStart, previousNotificationStart);
+                clipStart = Math.max(drawStart, clipStart);
             }
             float newYTranslation = state.yTranslation;
             float newHeight = state.height;
@@ -175,10 +173,10 @@
             boolean isHeadsUp = (child instanceof ExpandableNotificationRow)
                     && ((ExpandableNotificationRow) child).isPinned();
             if (mClipNotificationScrollToTop
-                    && !state.inShelf && newYTranslation < previousNotificationEnd
-                    && (!isHeadsUp || ambientState.isShadeExpanded())) {
+                    && (!state.inShelf || isHeadsUp)
+                    && newYTranslation < clipStart) {
                 // The previous view is overlapping on top, clip!
-                float overlapAmount = previousNotificationEnd - newYTranslation;
+                float overlapAmount = clipStart - newYTranslation;
                 state.clipTopAmount = (int) overlapAmount;
             } else {
                 state.clipTopAmount = 0;
@@ -187,8 +185,7 @@
             if (!child.isTransparent()) {
                 // Only update the previous values if we are not transparent,
                 // otherwise we would clip to a transparent view.
-                previousNotificationEnd = newNotificationEnd;
-                previousNotificationStart = newYTranslation;
+                clipStart = Math.max(clipStart, isHeadsUp ? newYTranslation : newNotificationEnd);
             }
         }
     }
@@ -514,11 +511,11 @@
         for (int i = 0; i < childCount; i++) {
             View child = algorithmState.visibleChildren.get(i);
             if (!(child instanceof ExpandableNotificationRow)) {
-                break;
+                continue;
             }
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
             if (!row.isHeadsUp()) {
-                break;
+                continue;
             }
             ExpandableViewState childState = row.getViewState();
             if (topHeadsUpEntry == null && row.mustStayOnScreen() && !childState.headsUpIsVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 05d26b0..94cd2cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -141,6 +141,7 @@
     private BiometricSourceType mPendingAuthenticatedBioSourceType = null;
     private boolean mPendingShowBouncer;
     private boolean mHasScreenTurnedOnSinceAuthenticating;
+    private boolean mFadedAwayAfterWakeAndUnlock;
 
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
@@ -260,7 +261,10 @@
         boolean unlockAllowed = mKeyguardBypassController.onBiometricAuthenticated(
                 biometricSourceType);
         if (unlockAllowed) {
+            mKeyguardViewMediator.userActivity();
             startWakeAndUnlock(biometricSourceType);
+        } else {
+            Log.d(TAG, "onBiometricAuthenticated aborted by bypass controller");
         }
     }
 
@@ -365,6 +369,7 @@
     @Override
     public void onStartedGoingToSleep(int why) {
         resetMode();
+        mFadedAwayAfterWakeAndUnlock = false;
         mPendingAuthenticatedUserId = -1;
         mPendingAuthenticatedBioSourceType = null;
     }
@@ -464,8 +469,11 @@
         }
         if (mStatusBarKeyguardViewManager.isShowing()) {
             if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) {
-                return bypass && !mKeyguardBypassController.canPlaySubtleWindowAnimations()
-                        ? MODE_UNLOCK_COLLAPSING : MODE_UNLOCK_FADING;
+                if (bypass && mKeyguardBypassController.canPlaySubtleWindowAnimations()) {
+                    return MODE_UNLOCK_FADING;
+                } else {
+                    return MODE_DISMISS_BOUNCER;
+                }
             } else if (unlockingAllowed) {
                 return bypass ? MODE_UNLOCK_FADING : MODE_NONE;
             } else {
@@ -507,6 +515,9 @@
     }
 
     public void finishKeyguardFadingAway() {
+        if (isWakeAndUnlock()) {
+            mFadedAwayAfterWakeAndUnlock = true;
+        }
         resetMode();
     }
 
@@ -557,6 +568,14 @@
     }
 
     /**
+     * Successful authentication with fingerprint, face, or iris that wakes up the device.
+     * This will return {@code true} even after the keyguard fades away.
+     */
+    public boolean unlockedByWakeAndUnlock() {
+        return  isWakeAndUnlock() || mFadedAwayAfterWakeAndUnlock;
+    }
+
+    /**
      * Successful authentication with fingerprint, face, or iris when the screen was either
      * on or off.
      */
@@ -565,6 +584,13 @@
     }
 
     /**
+     * Successful authentication with fingerprint, face, or iris when the lockscreen fades away
+     */
+    public boolean isUnlockFading() {
+        return mMode == MODE_UNLOCK_FADING;
+    }
+
+    /**
      * Translates biometric source type for logging purpose.
      */
     private int toSubtype(BiometricSourceType biometricSourceType) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 46dd5e6..f53c4e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -35,6 +35,7 @@
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -48,7 +49,7 @@
  * Controls the appearance of heads up notifications in the icon area and the header itself.
  */
 public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
-        DarkIconDispatcher.DarkReceiver {
+        DarkIconDispatcher.DarkReceiver, NotificationWakeUpCoordinator.WakeUpListener {
     public static final int CONTENT_FADE_DURATION = 110;
     public static final int CONTENT_FADE_DELAY = 100;
     private final NotificationIconAreaController mNotificationIconAreaController;
@@ -67,6 +68,7 @@
     private final KeyguardBypassController mBypassController;
     private final StatusBarStateController mStatusBarStateController;
     private final CommandQueue mCommandQueue;
+    private final NotificationWakeUpCoordinator mWakeUpCoordinator;
     @VisibleForTesting
     float mExpandedHeight;
     @VisibleForTesting
@@ -95,9 +97,10 @@
             HeadsUpManagerPhone headsUpManager,
             View statusbarView,
             SysuiStatusBarStateController statusBarStateController,
-            KeyguardBypassController keyguardBypassController) {
+            KeyguardBypassController keyguardBypassController,
+            NotificationWakeUpCoordinator wakeUpCoordinator) {
         this(notificationIconAreaController, headsUpManager, statusBarStateController,
-                keyguardBypassController,
+                keyguardBypassController, wakeUpCoordinator,
                 statusbarView.findViewById(R.id.heads_up_status_bar_view),
                 statusbarView.findViewById(R.id.notification_stack_scroller),
                 statusbarView.findViewById(R.id.notification_panel),
@@ -112,6 +115,7 @@
             HeadsUpManagerPhone headsUpManager,
             StatusBarStateController stateController,
             KeyguardBypassController bypassController,
+            NotificationWakeUpCoordinator wakeUpCoordinator,
             HeadsUpStatusBarView headsUpStatusBarView,
             NotificationStackScrollLayout stackScroller,
             NotificationPanelView panelView,
@@ -153,6 +157,8 @@
         });
         mBypassController = bypassController;
         mStatusBarStateController = stateController;
+        mWakeUpCoordinator = wakeUpCoordinator;
+        wakeUpCoordinator.addListener(this);
         mCommandQueue = getComponent(headsUpStatusBarView.getContext(), CommandQueue.class);
         mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
     }
@@ -161,6 +167,7 @@
     public void destroy() {
         mHeadsUpManager.removeListener(this);
         mHeadsUpStatusBarView.setOnDrawingRectChangedListener(null);
+        mWakeUpCoordinator.removeListener(this);
         mPanelView.removeTrackingHeadsUpListener(mSetTrackingHeadsUp);
         mPanelView.removeVerticalTranslationListener(mUpdatePanelTranslation);
         mPanelView.setHeadsUpAppearanceController(null);
@@ -289,6 +296,11 @@
                     updateParentClipping(true /* shouldClip */);
                 });
             }
+            // Show the status bar icons when the view gets shown / hidden
+            if (mStatusBarStateController.getState() != StatusBarState.SHADE) {
+                mCommandQueue.recomputeDisableFlags(
+                        mHeadsUpStatusBarView.getContext().getDisplayId(), false);
+            }
         }
     }
 
@@ -362,10 +374,12 @@
      * @return if the heads up status bar view should be shown
      */
     public boolean shouldBeVisible() {
-        boolean canShow = !mIsExpanded;
+        boolean notificationsShown = !mWakeUpCoordinator.getNotificationsFullyHidden();
+        boolean canShow = !mIsExpanded && notificationsShown;
         if (mBypassController.getBypassEnabled() &&
                 (mStatusBarStateController.getState() == StatusBarState.KEYGUARD
-                        || mKeyguardMonitor.isKeyguardGoingAway())) {
+                        || mKeyguardMonitor.isKeyguardGoingAway())
+                && notificationsShown) {
             canShow = true;
         }
         return canShow && mHeadsUpManager.hasPinnedHeadsUp();
@@ -377,15 +391,6 @@
         updateHeader(entry);
     }
 
-    @Override
-    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
-        if (mStatusBarStateController.getState() != StatusBarState.SHADE) {
-            // Show the status bar icons when the pinned mode changes
-            mCommandQueue.recomputeDisableFlags(
-                    mHeadsUpStatusBarView.getContext().getDisplayId(), false);
-        }
-    }
-
     public void setAppearFraction(float expandedHeight, float appearFraction) {
         boolean changed = expandedHeight != mExpandedHeight;
         mExpandedHeight = expandedHeight;
@@ -451,4 +456,9 @@
             mAppearFraction = oldController.mAppearFraction;
         }
     }
+
+    @Override
+    public void onFullyHiddenChanged(boolean isFullyHidden) {
+        updateTopEntry();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index cbaf85c..a7e7f08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -72,8 +72,6 @@
     private NotificationGroupManager mGroupManager;
     private VisualStabilityManager mVisualStabilityManager;
     private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
-    @VisibleForTesting
-    int mAutoDismissNotificationDecayDozing;
     private boolean mReleaseOnExpandFinish;
 
     private int mStatusBarHeight;
@@ -120,8 +118,6 @@
             KeyguardBypassController bypassController) {
         super(context);
         Resources resources = mContext.getResources();
-        mAutoDismissNotificationDecayDozing = resources.getInteger(
-                R.integer.heads_up_notification_decay_dozing);
         mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
         mAutoHeadsUpNotificationDecay = resources.getInteger(
                 R.integer.auto_heads_up_notification_decay);
@@ -367,12 +363,15 @@
     }
 
     public Region calculateTouchableRegion() {
-        if (!hasPinnedHeadsUp()) {
+        NotificationEntry topEntry = getTopEntry();
+        // This call could be made in an inconsistent state while the pinnedMode hasn't been
+        // updated yet, but callbacks leading out of the headsUp manager, querying it. Let's
+        // therefore also check if the topEntry is null.
+        if (!hasPinnedHeadsUp() || topEntry == null) {
             mTouchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
             updateRegionForNotch(mTouchableRegion);
 
         } else {
-            NotificationEntry topEntry = getTopEntry();
             if (topEntry.isChildInGroup()) {
                 final NotificationEntry groupSummary =
                         mGroupManager.getGroupSummary(topEntry.notification);
@@ -612,9 +611,7 @@
         }
 
         private int getDecayDuration() {
-            if (mStatusBarStateController.isDozing()) {
-                return mAutoDismissNotificationDecayDozing;
-            } else if (isAutoHeadsUp()) {
+            if (isAutoHeadsUp()) {
                 return getRecommendedHeadsUpTimeoutMs(mAutoHeadsUpNotificationDecay);
             } else {
                 return getRecommendedHeadsUpTimeoutMs(mAutoDismissNotificationDecay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 21a22ec..c4d346c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -170,7 +170,7 @@
 
         // Split up the work over multiple frames.
         DejankUtils.removeCallbacks(mResetRunnable);
-        if (mUnlockMethodCache.isUnlockingWithFacePossible() && !needsFullscreenBouncer()
+        if (mUnlockMethodCache.isFaceAuthEnabled() && !needsFullscreenBouncer()
                 && !mKeyguardUpdateMonitor.userNeedsStrongAuth()) {
             mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
         } else {
@@ -207,14 +207,12 @@
      * @see #onFullyShown()
      */
     private void onFullyHidden() {
-        if (!mShowingSoon) {
-            cancelShowRunnable();
-            if (mRoot != null) {
-                mRoot.setVisibility(View.INVISIBLE);
-            }
-            mFalsingManager.onBouncerHidden();
-            DejankUtils.postAfterTraversal(mResetRunnable);
+        cancelShowRunnable();
+        if (mRoot != null) {
+            mRoot.setVisibility(View.INVISIBLE);
         }
+        mFalsingManager.onBouncerHidden();
+        DejankUtils.postAfterTraversal(mResetRunnable);
     }
 
     private final Runnable mShowRunnable = new Runnable() {
@@ -346,10 +344,10 @@
     }
 
     /**
-     * {@link #show(boolean)} was called but we're not showing yet.
+     * {@link #show(boolean)} was called but we're not showing yet, or being dragged.
      */
-    public boolean willShowSoon() {
-        return mShowingSoon;
+    public boolean inTransit() {
+        return mShowingSoon || mExpansion != EXPANSION_HIDDEN && mExpansion != EXPANSION_VISIBLE;
     }
 
     /**
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 d7deedc..70d3bff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -21,11 +21,11 @@
 import android.hardware.biometrics.BiometricSourceType
 import android.hardware.face.FaceManager
 import android.provider.Settings
-import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.tuner.TunerService
+import java.io.PrintWriter
 import javax.inject.Inject
 import javax.inject.Singleton
 
@@ -47,7 +47,7 @@
      * If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
      */
     var bypassEnabled: Boolean = false
-        get() = field && unlockMethodCache.isUnlockingWithFacePossible
+        get() = field && unlockMethodCache.isFaceAuthEnabled
         private set
 
     var bouncerShowing: Boolean = false
@@ -62,18 +62,15 @@
         }
 
     @Inject
-    constructor(context: Context, tunerService: TunerService,
-                statusBarStateController: StatusBarStateController,
-                lockscreenUserManager: NotificationLockscreenUserManager) {
+    constructor(
+        context: Context,
+        tunerService: TunerService,
+        statusBarStateController: StatusBarStateController,
+        lockscreenUserManager: NotificationLockscreenUserManager
+    ) {
         unlockMethodCache = UnlockMethodCache.getInstance(context)
         this.statusBarStateController = statusBarStateController
-        statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
-            override fun onStateChanged(newState: Int) {
-                if (newState != StatusBarState.KEYGUARD) {
-                    pendingUnlockType = null;
-                }
-            }
-        })
+
         if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
             return
         }
@@ -82,16 +79,19 @@
             return
         }
 
+        statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+            override fun onStateChanged(newState: Int) {
+                if (newState != StatusBarState.KEYGUARD) {
+                    pendingUnlockType = null
+                }
+            }
+        })
+
         val dismissByDefault = if (context.resources.getBoolean(
-                com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
-        tunerService.addTunable(
-                object : TunerService.Tunable {
-                        override fun onTuningChanged(key: String?, newValue: String?) {
-                                bypassEnabled = Settings.Secure.getIntForUser(
-                                        context.contentResolver,
-                                        Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
-                                        dismissByDefault,
-                                        KeyguardUpdateMonitor.getCurrentUser()) != 0
+                        com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
+        tunerService.addTunable(object : TunerService.Tunable {
+            override fun onTuningChanged(key: String?, newValue: String?) {
+                bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
             }
         }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
         lockscreenUserManager.addUserChangedListener { pendingUnlockType = null }
@@ -155,4 +155,20 @@
     fun onStartedGoingToSleep() {
         pendingUnlockType = null
     }
+
+    fun dump(pw: PrintWriter) {
+        pw.println("KeyguardBypassController:")
+        pw.print("  pendingUnlockType: "); pw.println(pendingUnlockType)
+        pw.print("  bypassEnabled: "); pw.println(bypassEnabled)
+        pw.print("  canBypass: "); pw.println(canBypass())
+        pw.print("  bouncerShowing: "); pw.println(bouncerShowing)
+        pw.print("  isPulseExpanding: "); pw.println(isPulseExpanding)
+        pw.print("  launchingAffordance: "); pw.println(launchingAffordance)
+        pw.print("  qSExpanded: "); pw.println(qSExpanded)
+        pw.print("  bouncerShowing: "); pw.println(bouncerShowing)
+    }
+
+    companion object {
+        const val BYPASS_PANEL_FADE_DURATION = 67
+    }
 }
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 49afae7..c9c80d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -102,6 +102,7 @@
     private boolean mWakeAndUnlockRunning;
     private boolean mKeyguardShowing;
     private boolean mShowingLaunchAffordance;
+    private boolean mKeyguardJustShown;
     private boolean mUpdatePending;
 
     private final KeyguardMonitor.Callback mKeyguardMonitorCallback =
@@ -115,6 +116,9 @@
                         mBlockUpdates = false;
                         force = true;
                     }
+                    if (!wasShowing && mKeyguardShowing) {
+                        mKeyguardJustShown = true;
+                    }
                     update(force);
                 }
 
@@ -213,7 +217,7 @@
         mConfigurationController.removeCallback(this);
         mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
         mKeyguardMonitor.removeCallback(mKeyguardMonitorCallback);
-        mWakeUpCoordinator.removeFullyHiddenChangedListener(this);
+        mWakeUpCoordinator.removeListener(this);
         mUnlockMethodCache.removeListener(this);
         if (mDockManager != null) {
             mDockManager.removeListener(mDockEventListener);
@@ -273,8 +277,10 @@
 
         int state = getState();
         int lastState = mLastState;
+        boolean keyguardJustShown = mKeyguardJustShown;
         mIsFaceUnlockState = state == STATE_SCANNING_FACE;
         mLastState = state;
+        mKeyguardJustShown = false;
 
         boolean shouldUpdate = lastState != state || mForceUpdate;
         if (mBlockUpdates && canBlockUpdates()) {
@@ -283,7 +289,7 @@
         if (shouldUpdate) {
             mForceUpdate = false;
             @LockAnimIndex final int lockAnimIndex = getAnimationIndexForTransition(lastState,
-                    state, mPulsing, mDozing);
+                    state, mPulsing, mDozing, keyguardJustShown);
             boolean isAnim = lockAnimIndex != -1;
             int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(state);
 
@@ -317,14 +323,24 @@
         }
         updateDarkTint();
 
+        updateIconVisibility();
+        updateClickability();
+
+        return true;
+    }
+
+    /**
+     * Update the icon visibility
+     * @return true if the visibility changed
+     */
+    private boolean updateIconVisibility() {
         boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
         boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
                 || mShowingLaunchAffordance;
         if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
-            if (mHeadsUpManager.isHeadsUpGoingAway()
-                    || mHeadsUpManager.hasPinnedHeadsUp()
-                    || (mStatusBarStateController.getState() == StatusBarState.KEYGUARD
-                    && !mWakeUpCoordinator.getNotificationsFullyHidden())) {
+            if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp())
+                    && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+                    && !mWakeUpCoordinator.getNotificationsFullyHidden()) {
                 invisible = true;
             }
         }
@@ -343,10 +359,9 @@
                         .setDuration(233)
                         .start();
             }
+            return true;
         }
-        updateClickability();
-
-        return true;
+        return false;
     }
 
     private boolean canBlockUpdates() {
@@ -412,7 +427,7 @@
     }
 
     private static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
-            boolean dozing) {
+            boolean dozing, boolean keyguardJustShown) {
 
         // Never animate when screen is off
         if (dozing && !pulsing) {
@@ -423,7 +438,7 @@
             return ERROR;
         } else if (oldState != STATE_LOCK_OPEN && newState == STATE_LOCK_OPEN) {
             return UNLOCK;
-        } else if (oldState == STATE_LOCK_OPEN && newState == STATE_LOCKED) {
+        } else if (oldState == STATE_LOCK_OPEN && newState == STATE_LOCKED && !keyguardJustShown) {
             return LOCK;
         } else if (newState == STATE_SCANNING_FACE) {
             return SCANNING;
@@ -434,7 +449,10 @@
     @Override
     public void onFullyHiddenChanged(boolean isFullyHidden) {
         if (mBypassController.getBypassEnabled()) {
-            update();
+            boolean changed = updateIconVisibility();
+            if (changed) {
+                update();
+            }
         }
     }
 
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 22e3edb..9296f7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -22,6 +22,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SEARCH_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
 
@@ -719,6 +720,8 @@
                 (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0, displayId);
         mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_HOME_DISABLED,
                 (mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0, displayId);
+        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SEARCH_DISABLED,
+                (mDisabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0, displayId);
         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/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index 4d7cf27..1df9411 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -16,42 +16,46 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.Activity.RESULT_OK;
+import static android.app.admin.DevicePolicyManager.STATE_USER_UNMANAGED;
 import static android.content.Intent.ACTION_OVERLAY_CHANGED;
 import static android.content.Intent.ACTION_PREFERRED_ACTIVITY_CHANGED;
+import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
 import static android.os.UserHandle.USER_CURRENT;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
-import android.app.Notification;
-import android.app.NotificationManager;
+import static com.android.systemui.shared.system.QuickStepContract.ACTION_ENABLE_GESTURE_NAV;
+import static com.android.systemui.shared.system.QuickStepContract.ACTION_ENABLE_GESTURE_NAV_RESULT;
+import static com.android.systemui.shared.system.QuickStepContract.EXTRA_RESULT_INTENT;
+
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.om.IOverlayManager;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.ApkAssets;
 import android.os.PatternMatcher;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseBooleanArray;
 
 import com.android.systemui.Dumpable;
-import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.util.NotificationChannels;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -70,11 +74,6 @@
     private static final String TAG = NavigationModeController.class.getSimpleName();
     private static final boolean DEBUG = false;
 
-    private static final int SYSTEM_APP_MASK =
-            ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-    static final String SHARED_PREFERENCES_NAME = "navigation_mode_controller_preferences";
-    static final String PREFS_SWITCHED_FROM_GESTURE_NAV_KEY = "switched_from_gesture_nav";
-
     public interface ModeChangedListener {
         void onNavigationModeChanged(int mode);
     }
@@ -90,8 +89,6 @@
     private int mMode = NAV_BAR_MODE_3BUTTON;
     private ArrayList<ModeChangedListener> mListeners = new ArrayList<>();
 
-    private String mLastDefaultLauncher;
-
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -102,18 +99,6 @@
                     }
                     updateCurrentInteractionMode(true /* notify */);
                     break;
-                case ACTION_PREFERRED_ACTIVITY_CHANGED:
-                    if (DEBUG) {
-                        Log.d(TAG, "ACTION_PREFERRED_ACTIVITY_CHANGED");
-                    }
-                    final String launcher = getDefaultLauncherPackageName(mCurrentUserContext);
-                    // Check if it is a default launcher change
-                    if (!TextUtils.equals(mLastDefaultLauncher, launcher)) {
-                        switchFromGestureNavModeIfNotSupportedByDefaultLauncher();
-                        showNotificationIfDefaultLauncherSupportsGestureNav();
-                        mLastDefaultLauncher = launcher;
-                    }
-                    break;
             }
         }
     };
@@ -149,7 +134,6 @@
 
                     // Update the nav mode for the current user
                     updateCurrentInteractionMode(true /* notify */);
-                    switchFromGestureNavModeIfNotSupportedByDefaultLauncher();
 
                     // When switching users, defer enabling the gestural nav overlay until the user
                     // is all set up
@@ -157,6 +141,8 @@
                 }
             };
 
+    private BroadcastReceiver mEnableGestureNavReceiver;
+
     @Inject
     public NavigationModeController(Context context,
             DeviceProvisionedController deviceProvisionedController,
@@ -177,16 +163,81 @@
         IntentFilter preferredActivityFilter = new IntentFilter(ACTION_PREFERRED_ACTIVITY_CHANGED);
         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, preferredActivityFilter, null,
                 null);
-        // We are only interested in launcher changes, so keeping track of the current default.
-        mLastDefaultLauncher = getDefaultLauncherPackageName(mContext);
 
         updateCurrentInteractionMode(false /* notify */);
-        switchFromGestureNavModeIfNotSupportedByDefaultLauncher();
 
         // Check if we need to defer enabling gestural nav
         deferGesturalNavOverlayIfNecessary();
     }
 
+    private void removeEnableGestureNavListener() {
+        if (mEnableGestureNavReceiver != null) {
+            if (DEBUG) {
+                Log.d(TAG, "mEnableGestureNavReceiver unregistered");
+            }
+            mContext.unregisterReceiver(mEnableGestureNavReceiver);
+            mEnableGestureNavReceiver = null;
+        }
+    }
+
+    private boolean setGestureModeOverlayForMainLauncher() {
+        removeEnableGestureNavListener();
+        if (getCurrentInteractionMode(mCurrentUserContext) == NAV_BAR_MODE_GESTURAL) {
+            // Already in gesture mode
+            return true;
+        }
+
+        Log.d(TAG, "Switching system navigation to full-gesture mode:"
+                + " contextUser="
+                + mCurrentUserContext.getUserId());
+
+        setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT);
+        return true;
+    }
+
+    private boolean enableGestureNav(Intent intent) {
+        if (!(intent.getParcelableExtra(EXTRA_RESULT_INTENT) instanceof PendingIntent)) {
+            Log.e(TAG, "No callback pending intent was attached");
+            return false;
+        }
+
+        PendingIntent callback = intent.getParcelableExtra(EXTRA_RESULT_INTENT);
+        Intent callbackIntent = callback.getIntent();
+        if (callbackIntent == null
+                || !ACTION_ENABLE_GESTURE_NAV_RESULT.equals(callbackIntent.getAction())) {
+            Log.e(TAG, "Invalid callback intent");
+            return false;
+        }
+        String callerPackage = callback.getCreatorPackage();
+        UserHandle callerUser = callback.getCreatorUserHandle();
+
+        DevicePolicyManager dpm = mCurrentUserContext.getSystemService(DevicePolicyManager.class);
+        ComponentName ownerComponent = dpm.getDeviceOwnerComponentOnCallingUser();
+
+        if (ownerComponent != null) {
+            // Verify that the caller is the owner component
+            if (!ownerComponent.getPackageName().equals(callerPackage)
+                    || !mCurrentUserContext.getUser().equals(callerUser)) {
+                Log.e(TAG, "Callback must be from the device owner");
+                return false;
+            }
+        } else {
+            UserHandle callerParent = mCurrentUserContext.getSystemService(UserManager.class)
+                    .getProfileParent(callerUser);
+            if (callerParent == null || !callerParent.equals(mCurrentUserContext.getUser())) {
+                Log.e(TAG, "Callback must be from a managed user");
+                return false;
+            }
+            ComponentName profileOwner = dpm.getProfileOwnerAsUser(callerUser);
+            if (profileOwner == null || !profileOwner.getPackageName().equals(callerPackage)) {
+                Log.e(TAG, "Callback must be from the profile owner");
+                return false;
+            }
+        }
+
+        return setGestureModeOverlayForMainLauncher();
+    }
+
     public void updateCurrentInteractionMode(boolean notify) {
         mCurrentUserContext = getCurrentUserContext();
         int mode = getCurrentInteractionMode(mCurrentUserContext);
@@ -245,6 +296,10 @@
         }
     }
 
+    private boolean supportsDeviceAdmin() {
+        return mContext.getPackageManager().hasSystemFeature(FEATURE_DEVICE_ADMIN);
+    }
+
     private void deferGesturalNavOverlayIfNecessary() {
         final int userId = mDeviceProvisionedController.getCurrentUser();
         mRestoreGesturalNavBarMode.put(userId, false);
@@ -255,6 +310,7 @@
                 Log.d(TAG, "deferGesturalNavOverlayIfNecessary: device is provisioned and user is "
                         + "setup");
             }
+            removeEnableGestureNavListener();
             return;
         }
 
@@ -270,6 +326,7 @@
                 Log.d(TAG, "deferGesturalNavOverlayIfNecessary: no default gestural overlay, "
                         + "default=" + defaultOverlays);
             }
+            removeEnableGestureNavListener();
             return;
         }
 
@@ -277,6 +334,24 @@
         // provisioned
         setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
         mRestoreGesturalNavBarMode.put(userId, true);
+
+        if (supportsDeviceAdmin() && mEnableGestureNavReceiver == null) {
+            mEnableGestureNavReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (DEBUG) {
+                        Log.d(TAG, "ACTION_ENABLE_GESTURE_NAV");
+                    }
+                    setResultCode(enableGestureNav(intent) ? RESULT_OK : RESULT_CANCELED);
+                }
+            };
+            // Register for all users so that we can get managed users as well
+            mContext.registerReceiverAsUser(mEnableGestureNavReceiver, UserHandle.ALL,
+                    new IntentFilter(ACTION_ENABLE_GESTURE_NAV), null, null);
+            if (DEBUG) {
+                Log.d(TAG, "mEnableGestureNavReceiver registered");
+            }
+        }
         if (DEBUG) {
             Log.d(TAG, "deferGesturalNavOverlayIfNecessary: setting to 3 button mode");
         }
@@ -290,7 +365,15 @@
         final int userId = mDeviceProvisionedController.getCurrentUser();
         if (mRestoreGesturalNavBarMode.get(userId)) {
             // Restore the gestural state if necessary
-            setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT);
+            if (!supportsDeviceAdmin()
+                    || mCurrentUserContext.getSystemService(DevicePolicyManager.class)
+                    .getUserProvisioningState() == STATE_USER_UNMANAGED) {
+                setGestureModeOverlayForMainLauncher();
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "Not restoring to gesture nav for managed user");
+                }
+            }
             mRestoreGesturalNavBarMode.put(userId, false);
         }
     }
@@ -309,100 +392,6 @@
         });
     }
 
-    private void switchFromGestureNavModeIfNotSupportedByDefaultLauncher() {
-        if (getCurrentInteractionMode(mCurrentUserContext) != NAV_BAR_MODE_GESTURAL) {
-            return;
-        }
-        final Boolean supported = isGestureNavSupportedByDefaultLauncher(mCurrentUserContext);
-        if (supported == null || supported) {
-            return;
-        }
-
-        Log.d(TAG, "Switching system navigation to 3-button mode:"
-                + " defaultLauncher=" + getDefaultLauncherPackageName(mCurrentUserContext)
-                + " contextUser=" + mCurrentUserContext.getUserId());
-
-        setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
-        showNotification(mCurrentUserContext, R.string.notification_content_system_nav_changed);
-        mCurrentUserContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
-                .edit().putBoolean(PREFS_SWITCHED_FROM_GESTURE_NAV_KEY, true).apply();
-    }
-
-    private void showNotificationIfDefaultLauncherSupportsGestureNav() {
-        boolean previouslySwitchedFromGestureNav = mCurrentUserContext
-                .getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
-                .getBoolean(PREFS_SWITCHED_FROM_GESTURE_NAV_KEY, false);
-        if (!previouslySwitchedFromGestureNav) {
-            return;
-        }
-        if (getCurrentInteractionMode(mCurrentUserContext) == NAV_BAR_MODE_GESTURAL) {
-            return;
-        }
-        final Boolean supported = isGestureNavSupportedByDefaultLauncher(mCurrentUserContext);
-        if (supported == null || !supported) {
-            return;
-        }
-
-        showNotification(mCurrentUserContext, R.string.notification_content_gesture_nav_available);
-        mCurrentUserContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
-                .edit().putBoolean(PREFS_SWITCHED_FROM_GESTURE_NAV_KEY, false).apply();
-    }
-
-    /**
-     * Returns null if there is no default launcher set for the current user. Returns true if the
-     * current default launcher supports Gesture Navigation. Returns false otherwise.
-     */
-    private Boolean isGestureNavSupportedByDefaultLauncher(Context context) {
-        final String defaultLauncherPackageName = getDefaultLauncherPackageName(context);
-        if (DEBUG) {
-            Log.d(TAG, "isGestureNavSupportedByDefaultLauncher:"
-                    + " defaultLauncher=" + defaultLauncherPackageName
-                    + " contextUser=" + context.getUserId());
-        }
-        if (defaultLauncherPackageName == null) {
-            return null;
-        }
-        if (isSystemApp(context, defaultLauncherPackageName)) {
-            return true;
-        }
-        return false;
-    }
-
-    private String getDefaultLauncherPackageName(Context context) {
-        final ComponentName cn = context.getPackageManager().getHomeActivities(new ArrayList<>());
-        if (cn == null) {
-            return null;
-        }
-        return cn.getPackageName();
-    }
-
-    /** Returns true if the app for the given package name is a system app for this device */
-    private boolean isSystemApp(Context context, String packageName) {
-        try {
-            ApplicationInfo ai = context.getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_META_DATA);
-            return ai != null && ((ai.flags & SYSTEM_APP_MASK) != 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
-        }
-    }
-
-    private void showNotification(Context context, int resId) {
-        final CharSequence message = context.getResources().getString(resId);
-        if (DEBUG) {
-            Log.d(TAG, "showNotification: message=" + message);
-        }
-
-        final Notification.Builder builder =
-                new Notification.Builder(mContext, NotificationChannels.ALERTS)
-                        .setContentText(message)
-                        .setStyle(new Notification.BigTextStyle())
-                        .setSmallIcon(R.drawable.ic_info)
-                        .setAutoCancel(true)
-                        .setContentIntent(PendingIntent.getActivity(context, 0, new Intent(), 0));
-        context.getSystemService(NotificationManager.class).notify(TAG, 0, builder.build());
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("NavigationModeController:");
@@ -415,12 +404,6 @@
         }
         pw.println("  defaultOverlays=" + defaultOverlays);
         dumpAssetPaths(mCurrentUserContext);
-
-        pw.println("  defaultLauncher=" + mLastDefaultLauncher);
-        boolean previouslySwitchedFromGestureNav = mCurrentUserContext
-                .getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
-                .getBoolean(PREFS_SWITCHED_FROM_GESTURE_NAV_KEY, false);
-        pw.println("  previouslySwitchedFromGestureNav=" + previouslySwitchedFromGestureNav);
     }
 
     private void dumpAssetPaths(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 0bbfbef..195870b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -464,7 +464,7 @@
         if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
             return false;
         }
-        if (!mHeadsUpManager.isAlerting(entry.key)) {
+        if (mHeadsUpManager != null && !mHeadsUpManager.isAlerting(entry.key)) {
             return false;
         }
         return (sbn.getNotification().fullScreenIntent != null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index d2159ca..21de8a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -4,7 +4,6 @@
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.provider.Settings;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -32,7 +31,6 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.tuner.TunerService;
 
 import java.util.ArrayList;
 import java.util.Objects;
@@ -58,7 +56,6 @@
     private final KeyguardBypassController mBypassController;
     private final DozeParameters mDozeParameters;
 
-    private boolean mShowSilentOnLockscreen = true;
     private int mIconSize;
     private int mIconHPadding;
     private int mIconTint = Color.WHITE;
@@ -101,11 +98,6 @@
 
         initializeNotificationAreaViews(context);
         reloadAodColor();
-
-        TunerService tunerService = Dependency.get(TunerService.class);
-        tunerService.addTunable((key, newValue) -> {
-            mShowSilentOnLockscreen = "1".equals(newValue);
-        }, Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS);
     }
 
     protected View inflateIconArea(LayoutInflater inflater) {
@@ -238,7 +230,7 @@
     }
 
     protected boolean shouldShowNotificationIcon(NotificationEntry entry,
-            boolean showAmbient, boolean showLowPriority, boolean hideDismissed,
+            boolean showAmbient, boolean hideDismissed,
             boolean hideRepliedMessages, boolean hideCurrentMedia, boolean hideCenteredIcon,
             boolean hidePulsing, boolean onlyShowCenteredIcon) {
 
@@ -257,9 +249,6 @@
         if (hideCurrentMedia && entry.key.equals(mMediaManager.getMediaNotificationKey())) {
             return false;
         }
-        if (!showLowPriority && !entry.isHighPriority()) {
-            return false;
-        }
         if (!entry.isTopLevelChild()) {
             return false;
         }
@@ -297,7 +286,6 @@
     private void updateShelfIcons() {
         updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
                 true /* showAmbient */,
-                true /* showLowPriority */,
                 false /* hideDismissed */,
                 false /* hideRepliedMessages */,
                 false /* hideCurrentMedia */,
@@ -309,7 +297,6 @@
     public void updateStatusBarIcons() {
         updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
                 false /* showAmbient */,
-                true /* showLowPriority */,
                 true /* hideDismissed */,
                 true /* hideRepliedMessages */,
                 false /* hideCurrentMedia */,
@@ -321,7 +308,6 @@
     private void updateCenterIcon() {
         updateIconsForLayout(entry -> entry.centeredIcon, mCenteredIcon,
                 false /* showAmbient */,
-                true /* showLowPriority */,
                 false /* hideDismissed */,
                 false /* hideRepliedMessages */,
                 false /* hideCurrentMedia */,
@@ -333,7 +319,6 @@
     public void updateAodNotificationIcons() {
         updateIconsForLayout(entry -> entry.aodIcon, mAodIcons,
                 false /* showAmbient */,
-                mShowSilentOnLockscreen /* showLowPriority */,
                 true /* hideDismissed */,
                 true /* hideRepliedMessages */,
                 true /* hideCurrentMedia */,
@@ -353,7 +338,7 @@
      * @param hidePulsing should pulsing notifications be hidden
      */
     private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
-            NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority,
+            NotificationIconContainer hostLayout, boolean showAmbient,
             boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia,
             boolean hideCenteredIcon, boolean hidePulsing, boolean onlyShowCenteredIcon) {
         ArrayList<StatusBarIconView> toShow = new ArrayList<>(
@@ -364,7 +349,7 @@
             View view = mNotificationScrollLayout.getChildAt(i);
             if (view instanceof ExpandableNotificationRow) {
                 NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
-                if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed,
+                if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed,
                         hideRepliedMessages, hideCurrentMedia, hideCenteredIcon, hidePulsing,
                         onlyShowCenteredIcon)) {
                     StatusBarIconView iconView = function.apply(ent);
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 971a7ee..792b83a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -454,6 +454,11 @@
         mPulseExpansionHandler.setUp(mNotificationStackScroller, this, mShadeController);
         mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
             @Override
+            public void onFullyHiddenChanged(boolean isFullyHidden) {
+                updateKeyguardStatusBarForHeadsUp();
+            }
+
+            @Override
             public void onPulseExpansionChanged(boolean expandingChanged) {
                 if (mKeyguardBypassController.getBypassEnabled()) {
                     // Position the notifications while dragging down while pulsing
@@ -803,8 +808,7 @@
             if (suppressedSummary) {
                 continue;
             }
-            if (!mLockscreenUserManager.shouldShowOnKeyguard(
-                    row.getStatusBarNotification())) {
+            if (!mLockscreenUserManager.shouldShowOnKeyguard(row.getEntry())) {
                 continue;
             }
             if (row.isRemoved()) {
@@ -1278,6 +1282,7 @@
         }
         mExpectingSynthesizedDown = true;
         onTrackingStarted();
+        updatePanelExpanded();
     }
 
     /**
@@ -1560,9 +1565,15 @@
         anim.setStartDelay(mKeyguardMonitor.isKeyguardFadingAway()
                 ? mKeyguardMonitor.getKeyguardFadingAwayDelay()
                 : 0);
-        anim.setDuration(mKeyguardMonitor.isKeyguardFadingAway()
-                ? mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2
-                : StackStateAnimator.ANIMATION_DURATION_STANDARD);
+
+        long duration;
+        if (mKeyguardMonitor.isKeyguardFadingAway()) {
+            duration = mKeyguardMonitor.getShortenedFadingAwayDuration();
+        } else {
+            duration = StackStateAnimator.ANIMATION_DURATION_STANDARD;
+        }
+        anim.setDuration(duration);
+
         anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -1605,7 +1616,7 @@
             mKeyguardBottomArea.animate()
                     .alpha(0f)
                     .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
-                    .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+                    .setDuration(mKeyguardMonitor.getShortenedFadingAwayDuration())
                     .setInterpolator(Interpolators.ALPHA_OUT)
                     .withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable)
                     .start();
@@ -1634,7 +1645,7 @@
             if (keyguardFadingAway) {
                 mKeyguardStatusView.animate()
                         .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
-                        .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration() / 2)
+                        .setDuration(mKeyguardMonitor.getShortenedFadingAwayDuration())
                         .start();
             }
         } else if (mBarState == StatusBarState.SHADE_LOCKED
@@ -1717,8 +1728,8 @@
             mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
                     false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
         }
-        if (mExpansionListener != null) {
-            mExpansionListener.onQsExpansionChanged(mQsMaxExpansionHeight != 0
+        for (int i = 0; i < mExpansionListeners.size(); i++) {
+            mExpansionListeners.get(i).onQsExpansionChanged(mQsMaxExpansionHeight != 0
                     ? mQsExpansionHeight / mQsMaxExpansionHeight : 0);
         }
         if (DEBUG) {
@@ -2029,7 +2040,7 @@
     }
 
     private void updatePanelExpanded() {
-        boolean isExpanded = !isFullyCollapsed();
+        boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown;
         if (mPanelExpanded != isExpanded) {
             mHeadsUpManager.setIsPanelExpanded(isExpanded);
             mStatusBar.setPanelExpanded(isExpanded);
@@ -3374,24 +3385,4 @@
         mOnReinflationListener = onReinflationListener;
     }
 
-    /**
-     * Panel and QS expansion callbacks.
-     */
-    public interface PanelExpansionListener {
-        /**
-         * Invoked whenever the notification panel expansion changes, at every animation frame.
-         * This is the main expansion that happens when the user is swiping up to dismiss the
-         * lock screen.
-         *
-         * @param expansion 0 when collapsed, 1 when expanded.
-         * @param tracking {@code true} when the user is actively dragging the panel.
-         */
-        void onPanelExpansionChanged(float expansion, boolean tracking);
-
-        /**
-         * Invoked whenever the QS expansion changes, at every animation frame.
-         * @param expansion 0 when collapsed, 1 when expanded.
-         */
-        void onQsExpansionChanged(float expansion);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java
new file mode 100644
index 0000000..655a25d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java
@@ -0,0 +1,38 @@
+/*
+ * 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.statusbar.phone;
+
+/**
+ * Panel and QS expansion callbacks.
+ */
+public interface PanelExpansionListener {
+    /**
+     * Invoked whenever the notification panel expansion changes, at every animation frame.
+     * This is the main expansion that happens when the user is swiping up to dismiss the
+     * lock screen.
+     *
+     * @param expansion 0 when collapsed, 1 when expanded.
+     * @param tracking {@code true} when the user is actively dragging the panel.
+     */
+    void onPanelExpansionChanged(float expansion, boolean tracking);
+
+    /**
+     * Invoked whenever the QS expansion changes, at every animation frame.
+     * @param expansion 0 when collapsed, 1 when expanded.
+     */
+    default void onQsExpansionChanged(float expansion) {};
+}
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 853faab..727f72b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -49,11 +49,11 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView.PanelExpansionListener;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
 public abstract class PanelView extends FrameLayout {
     public static final boolean DEBUG = PanelBar.DEBUG;
@@ -68,7 +68,7 @@
     private boolean mVibrateOnOpening;
     protected boolean mLaunchingNotification;
     private int mFixedDuration = NO_FIXED_DURATION;
-    protected PanelExpansionListener mExpansionListener;
+    protected ArrayList<PanelExpansionListener> mExpansionListeners = new ArrayList<>();
 
     private final void logf(String fmt, Object... args) {
         Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -1173,13 +1173,13 @@
                     || mPeekAnimator != null || mInstantExpanding
                     || isPanelVisibleBecauseOfHeadsUp() || mTracking || mHeightAnimator != null);
         }
-        if (mExpansionListener != null) {
-            mExpansionListener.onPanelExpansionChanged(mExpandedFraction, mTracking);
+        for (int i = 0; i < mExpansionListeners.size(); i++) {
+            mExpansionListeners.get(i).onPanelExpansionChanged(mExpandedFraction, mTracking);
         }
     }
 
-    public void setExpansionListener(PanelExpansionListener panelExpansionListener) {
-        mExpansionListener = panelExpansionListener;
+    public void addExpansionListener(PanelExpansionListener panelExpansionListener) {
+        mExpansionListeners.add(panelExpansionListener);
     }
 
     protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 3f38c04..b12bf5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -487,6 +487,22 @@
     }
 
     /**
+     * Set front scrim to black, cancelling animations, in order to prepare to fade them
+     * away once the display turns on.
+     */
+    public void prepareForGentleWakeUp() {
+        if (mState == ScrimState.AOD) {
+            mCurrentInFrontAlpha = 1f;
+            mCurrentInFrontTint = Color.BLACK;
+            mCurrentBehindTint = Color.BLACK;
+            mAnimateChange = false;
+            updateScrims();
+            mAnimateChange = true;
+            mAnimationDuration = ANIMATION_DURATION_LONG;
+        }
+    }
+
+    /**
      * If the lock screen sensor is active.
      */
     public void setWakeLockScreenSensorActive(boolean active) {
@@ -932,6 +948,12 @@
         }
     }
 
+    public void setUnlockIsFading(boolean unlockFading) {
+        for (ScrimState state : ScrimState.values()) {
+            state.setUnlockIsFading(unlockFading);
+        }
+    }
+
     public void setLaunchingAffordanceWithPreview(boolean launchingAffordanceWithPreview) {
         for (ScrimState state : ScrimState.values()) {
             state.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index d152ecd..c706062 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -129,7 +129,10 @@
         public void prepare(ScrimState previousState) {
             mCurrentInFrontAlpha = 0f;
             mCurrentBehindTint = Color.BLACK;
+            mCurrentInFrontTint = Color.BLACK;
             mBlankScreen = mDisplayRequiresBlanking;
+            mAnimationDuration = mWakeLockScreenSensorActive
+                    ? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
         }
 
         @Override
@@ -147,7 +150,9 @@
         public void prepare(ScrimState previousState) {
             mCurrentBehindAlpha = 0;
             mCurrentInFrontAlpha = 0;
-            mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION;
+            mAnimationDuration = mUnlockIsFading
+                    ? KeyguardBypassController.BYPASS_PANEL_FADE_DURATION
+                    : StatusBar.FADE_KEYGUARD_DURATION;
             mAnimateChange = !mLaunchingAffordanceWithPreview;
 
             if (previousState == ScrimState.AOD) {
@@ -198,6 +203,7 @@
     boolean mHasBackdrop;
     boolean mLaunchingAffordanceWithPreview;
     boolean mWakeLockScreenSensorActive;
+    boolean mUnlockIsFading;
 
     ScrimState(int index) {
         mIndex = index;
@@ -285,4 +291,8 @@
     public void setWakeLockScreenSensorActive(boolean active) {
         mWakeLockScreenSensorActive = active;
     }
+
+    public void setUnlockIsFading(boolean unlockIsFading) {
+        mUnlockIsFading = unlockIsFading;
+    }
 }
\ No newline at end of file
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 fc68379a..096ca99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -813,6 +813,7 @@
         inflateShelf();
         mNotificationIconAreaController.setupShelf(mNotificationShelf);
         mNotificationPanel.setOnReinflationListener(mNotificationIconAreaController::initAodIcons);
+        mNotificationPanel.addExpansionListener(mWakeUpCoordinator);
 
         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
         // Allow plugins to reference DarkIconDispatcher and StatusBarStateController
@@ -855,7 +856,8 @@
                     }
                     mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                             mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow,
-                            mStatusBarStateController, mKeyguardBypassController);
+                            mStatusBarStateController, mKeyguardBypassController,
+                            mWakeUpCoordinator);
                     mHeadsUpAppearanceController.readFrom(oldController);
                     mStatusBarWindow.setStatusBarView(mStatusBarView);
                     updateAreThereNotifications();
@@ -1229,6 +1231,7 @@
                 mDozeScrimController, keyguardViewMediator,
                 mScrimController, this, UnlockMethodCache.getInstance(mContext),
                 new Handler(), mKeyguardUpdateMonitor, mKeyguardBypassController);
+        putComponent(BiometricUnlockController.class, mBiometricUnlockController);
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                 getBouncerContainer(), mNotificationPanel, mBiometricUnlockController,
                 mStatusBarWindow.findViewById(R.id.lock_icon_container), mStackScroller,
@@ -1800,6 +1803,8 @@
                     mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
                 }
                 mNotificationPanel.expand(true /* animate */);
+                ((NotificationListContainer) mStackScroller).setWillExpand(true);
+                mHeadsUpManager.unpinAll(true /* userUnpinned */);
                 mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
             } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
                 mNotificationPanel.flingSettings(0 /* velocity */,
@@ -1937,7 +1942,6 @@
 
         if (start) {
             mNotificationPanel.startWaitingForOpenPanelGesture();
-            setPanelExpanded(true);
         } else {
             mNotificationPanel.stopWaitingForOpenPanelGesture(velocity);
         }
@@ -2386,6 +2390,14 @@
             mLightBarController.dump(fd, pw, args);
         }
 
+        if (mUnlockMethodCache != null) {
+            mUnlockMethodCache.dump(pw);
+        }
+
+        if (mKeyguardBypassController != null) {
+            mKeyguardBypassController.dump(pw);
+        }
+
         if (mKeyguardUpdateMonitor != null) {
             mKeyguardUpdateMonitor.dump(fd, pw, args);
         }
@@ -3194,12 +3206,13 @@
 
     /**
      * Notifies the status bar the Keyguard is fading away with the specified timings.
-     *
-     * @param startTime the start time of the animations in uptime millis
+     *  @param startTime the start time of the animations in uptime millis
      * @param delay the precalculated animation delay in milliseconds
      * @param fadeoutDuration the duration of the exit animation, in milliseconds
+     * @param isBypassFading is this a fading away animation while bypassing
      */
-    public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
+    public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration,
+            boolean isBypassFading) {
         mCommandQueue.appTransitionStarting(mDisplayId, startTime + fadeoutDuration
                         - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
@@ -3207,7 +3220,7 @@
         mCommandQueue.appTransitionStarting(mDisplayId,
                     startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                     LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
-        mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
+        mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration, isBypassFading);
     }
 
     /**
@@ -3435,7 +3448,7 @@
         mNotificationPanel.resetViews(dozingAnimated);
 
         updateQsExpansionEnabled();
-        mKeyguardViewMediator.setAodShowing(mDozing);
+        mKeyguardViewMediator.setDozing(mDozing);
 
         mEntryManager.updateNotifications();
         updateDozingState();
@@ -3557,6 +3570,9 @@
                 userAllowsPrivateNotificationsInPublic(mLockscreenUserManager.getCurrentUserId())
                 || !mLockscreenUserManager.shouldShowLockscreenNotifications()
                 || mFalsingManager.shouldEnforceBouncer();
+        if (mKeyguardBypassController.getBypassEnabled()) {
+            fullShadeNeedsBouncer = false;
+        }
         if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
             mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
             showBouncerIfKeyguard();
@@ -3835,6 +3851,7 @@
 
     public void notifyBiometricAuthModeChanged() {
         updateDozing();
+        mScrimController.setUnlockIsFading(mBiometricUnlockController.isUnlockFading());
         updateScrimController();
         mStatusBarWindow.onBiometricAuthModeChanged(mBiometricUnlockController.isWakeAndUnlock(),
                 mBiometricUnlockController.isBiometricUnlock());
@@ -3846,7 +3863,8 @@
 
         // We don't want to end up in KEYGUARD state when we're unlocking with
         // fingerprint from doze. We should cross fade directly from black.
-        boolean wakeAndUnlocking = mBiometricUnlockController.isWakeAndUnlock();
+        boolean unlocking = mBiometricUnlockController.isWakeAndUnlock()
+                || mKeyguardMonitor.isKeyguardFadingAway();
 
         // Do not animate the scrim expansion when triggered by the fingerprint sensor.
         mScrimController.setExpansionAffectsAlpha(
@@ -3871,9 +3889,9 @@
         } else if (isPulsing()) {
             mScrimController.transitionTo(ScrimState.PULSING,
                     mDozeScrimController.getScrimCallback());
-        } else if (mDozing && !wakeAndUnlocking) {
+        } else if (mDozing && !unlocking) {
             mScrimController.transitionTo(ScrimState.AOD);
-        } else if (mIsKeyguard && !wakeAndUnlocking) {
+        } else if (mIsKeyguard && !unlocking) {
             mScrimController.transitionTo(ScrimState.KEYGUARD);
         } else if (mBubbleController.isStackExpanded()) {
             mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
@@ -4114,6 +4132,11 @@
             mScrimController.setAodFrontScrimAlpha(scrimOpacity);
         }
 
+        @Override
+        public void prepareForGentleWakeUp() {
+            mScrimController.prepareForGentleWakeUp();
+        }
+
         private void dispatchTap(View view, float x, float y) {
             long now = SystemClock.elapsedRealtime();
             dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index d678182..3508c90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -70,7 +70,7 @@
  */
 public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
         StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
-        NotificationPanelView.PanelExpansionListener, NavigationModeController.ModeChangedListener {
+        PanelExpansionListener, NavigationModeController.ModeChangedListener {
 
     // When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
     private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -85,7 +85,6 @@
     // make everything a bit slower to bridge a gap until the user is unlocked and home screen has
     // dranw its first frame.
     private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
-    private static final long BYPASS_PANEL_FADE_DURATION = 67;
 
     private static String TAG = "StatusBarKeyguardViewManager";
 
@@ -224,7 +223,7 @@
                 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
                 mExpansionCallback, falsingManager);
         mNotificationPanelView = notificationPanelView;
-        notificationPanelView.setExpansionListener(this);
+        notificationPanelView.addExpansionListener(this);
         mBypassController = bypassController;
         mNotificationContainer = notificationContainer;
     }
@@ -270,7 +269,7 @@
         boolean keyguardWithoutQs = mStatusBarStateController.getState() == StatusBarState.KEYGUARD
                 && !mNotificationPanelView.isQsExpanded();
         boolean lockVisible = (mBouncer.isShowing() || keyguardWithoutQs)
-                && !mBouncer.isAnimatingAway();
+                && !mBouncer.isAnimatingAway() && !mKeyguardMonitor.isKeyguardFadingAway();
 
         if (mLastLockVisible != lockVisible) {
             mLastLockVisible = lockVisible;
@@ -279,8 +278,14 @@
                         AppearAnimationUtils.DEFAULT_APPEAR_DURATION /* duration */,
                         0 /* delay */);
             } else {
+                final long duration;
+                if (needsBypassFading()) {
+                    duration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION;
+                } else {
+                    duration = AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2;
+                }
                 CrossFadeHelper.fadeOut(mLockIconContainer,
-                        AppearAnimationUtils.DEFAULT_APPEAR_DURATION / 2 /* duration */,
+                        duration /* duration */,
                         0 /* delay */, null /* runnable */);
             }
         }
@@ -556,18 +561,22 @@
             executeAfterKeyguardGoneAction();
             boolean wakeUnlockPulsing =
                     mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
-            if (wakeUnlockPulsing) {
+            boolean needsFading = needsBypassFading();
+            if (needsFading) {
+                delay = 0;
+                fadeoutDuration = KeyguardBypassController.BYPASS_PANEL_FADE_DURATION;
+            } else if (wakeUnlockPulsing) {
                 delay = 0;
                 fadeoutDuration = 240;
             }
-            mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
+            mStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration, needsFading);
             mBiometricUnlockController.startKeyguardFadingAway();
             hideBouncer(true /* destroyView */);
             if (wakeUnlockPulsing) {
-                if (needsBypassFading()) {
+                if (needsFading) {
                     ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
                             mNotificationContainer,
-                            BYPASS_PANEL_FADE_DURATION,
+                            fadeoutDuration,
                                     () -> {
                         mStatusBar.hideKeyguard();
                         onKeyguardFadedAway();
@@ -580,10 +589,10 @@
                 boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
                 if (!staying) {
                     mStatusBarWindowController.setKeyguardFadingAway(true);
-                    if (needsBypassFading()) {
+                    if (needsFading) {
                         ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
                                 mNotificationContainer,
-                                BYPASS_PANEL_FADE_DURATION,
+                                fadeoutDuration,
                                 () -> {
                                     mStatusBar.hideKeyguard();
                                 });
@@ -602,6 +611,7 @@
                     mBiometricUnlockController.finishKeyguardFadingAway();
                 }
             }
+            updateLockIcon();
             updateStates();
             mStatusBarWindowController.setKeyguardShowing(false);
             mViewMediatorCallback.keyguardGone();
@@ -720,7 +730,7 @@
      * animation didn't finish yet.
      */
     public boolean bouncerIsOrWillBeShowing() {
-        return mBouncer.isShowing() || mBouncer.willShowSoon();
+        return mBouncer.isShowing() || mBouncer.inTransit();
     }
 
     public boolean isFullscreenBouncer() {
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 4ddd0e9..d9a9f7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -51,12 +51,13 @@
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
 import com.google.android.collect.Lists;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Field;
-
 import java.util.ArrayList;
+
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -352,7 +353,7 @@
     }
 
     private void applyForceStatusBarVisibleFlag(State state) {
-        if (state.forceStatusBarVisible) {
+        if (state.forceStatusBarVisible || state.forcePluginOpen) {
             mLpChanged.privateFlags |= WindowManager
                     .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
         } else {
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 f1049f0..33b863f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -418,7 +418,7 @@
         if (mNotificationPanel.isFullyExpanded()
                 && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
                 && !mService.isBouncerShowing()
-                && !mBypassController.getBypassEnabled()
+                && (!mBypassController.getBypassEnabled() || mNotificationPanel.isQsExpanded())
                 && !mService.isDozing()) {
             intercept = mDragDownHelper.onInterceptTouchEvent(ev);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index f36c56f..b1d6ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -28,6 +28,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 /**
@@ -51,7 +52,7 @@
     private boolean mTrustManaged;
     private boolean mTrusted;
     private boolean mDebugUnlocked = false;
-    private boolean mIsUnlockingWithFacePossible;
+    private boolean mFaceAuthEnabled;
 
     private UnlockMethodCache(Context ctx) {
         mLockPatternUtils = new LockPatternUtils(ctx);
@@ -107,8 +108,11 @@
         mListeners.remove(listener);
     }
 
-    public boolean isUnlockingWithFacePossible() {
-        return mIsUnlockingWithFacePossible;
+    /**
+     * If there are faces enrolled and user enabled face auth on keyguard.
+     */
+    public boolean isFaceAuthEnabled() {
+        return mFaceAuthEnabled;
     }
 
     private void update(boolean updateAlways) {
@@ -119,15 +123,16 @@
                 || (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
         boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
         boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
-        boolean hasEnrolledFaces = mKeyguardUpdateMonitor.isUnlockWithFacePossible(user);
-        boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer ||
-                trustManaged != mTrustManaged || mIsUnlockingWithFacePossible != hasEnrolledFaces;
+        boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(user);
+        boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer
+                || trustManaged != mTrustManaged
+                || mFaceAuthEnabled != faceAuthEnabled;
         if (changed || updateAlways) {
             mSecure = secure;
             mCanSkipBouncer = canSkipBouncer;
             mTrusted = trusted;
             mTrustManaged = trustManaged;
-            mIsUnlockingWithFacePossible = hasEnrolledFaces;
+            mFaceAuthEnabled = faceAuthEnabled;
             notifyListeners();
         }
         Trace.endSection();
@@ -139,6 +144,16 @@
         }
     }
 
+    public void dump(PrintWriter pw) {
+        pw.println("UnlockMethodCache");
+        pw.println("  mSecure: " + mSecure);
+        pw.println("  mCanSkipBouncer: " + mCanSkipBouncer);
+        pw.println("  mTrustManaged: " + mTrustManaged);
+        pw.println("  mTrusted: " + mTrusted);
+        pw.println("  mDebugUnlocked: " + mDebugUnlocked);
+        pw.println("  mFaceAuthEnabled: " + mFaceAuthEnabled);
+    }
+
     private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
         @Override
         public void onUserSwitchComplete(int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index f61b556..070136e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -29,6 +29,19 @@
     long getKeyguardFadingAwayDelay();
     long calculateGoingToFullShadeDelay();
 
+    /**
+     * @return a shortened fading away duration similar to
+     * {{@link #getKeyguardFadingAwayDuration()}} which may only span half of the duration, unless
+     * we're bypassing
+     */
+    default long getShortenedFadingAwayDuration() {
+        if (isBypassFadingAnimation()) {
+            return getKeyguardFadingAwayDuration();
+        } else {
+            return getKeyguardFadingAwayDuration() / 2;
+        }
+    }
+
     default boolean isDeviceInteractive() {
         return false;
     }
@@ -39,7 +52,21 @@
     default void notifyKeyguardGoingAway(boolean b) {
     }
 
-    default void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
+    /**
+     * @return {@code true} if the current fading away animation is the fast bypass fading.
+     */
+    default boolean isBypassFadingAnimation() {
+        return false;
+    }
+
+    /**
+     * Notifies that the Keyguard is fading away with the specified timings.
+     * @param delay the precalculated animation delay in milliseconds
+     * @param fadeoutDuration the duration of the exit animation, in milliseconds
+     * @param isBypassFading is this a fading away animation while bypassing
+     */
+    default void notifyKeyguardFadingAway(long delay, long fadeoutDuration,
+            boolean isBypassFading) {
     }
 
     default void notifyKeyguardDoneFading() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index 68d0070..8829be4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -54,6 +54,7 @@
     private long mKeyguardFadingAwayDuration;
     private boolean mKeyguardGoingAway;
     private boolean mLaunchTransitionFadingAway;
+    private boolean mBypassFadingAnimation;
 
     /**
      */
@@ -140,10 +141,11 @@
         new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
     }
 
-    public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
+    public void notifyKeyguardFadingAway(long delay, long fadeoutDuration, boolean isBypassFading) {
         setKeyguardFadingAway(true);
         mKeyguardFadingAwayDelay = delay;
         mKeyguardFadingAwayDuration = fadeoutDuration;
+        mBypassFadingAnimation = isBypassFading;
     }
 
     private void setKeyguardFadingAway(boolean keyguardFadingAway) {
@@ -172,6 +174,11 @@
     }
 
     @Override
+    public boolean isBypassFadingAnimation() {
+        return mBypassFadingAnimation;
+    }
+
+    @Override
     public long getKeyguardFadingAwayDelay() {
         return mKeyguardFadingAwayDelay;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index b21ba09..4562763 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -163,7 +163,8 @@
                         | PhoneStateListener.LISTEN_CALL_STATE
                         | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
                         | PhoneStateListener.LISTEN_DATA_ACTIVITY
-                        | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
+                        | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE
+                        | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
         mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
                 true, mObserver);
         mContext.getContentResolver().registerContentObserver(Global.getUriFor(
@@ -636,6 +637,13 @@
 
             updateTelephony();
         }
+
+        @Override
+        public void onActiveDataSubscriptionIdChanged(int subId) {
+            if (DEBUG) Log.d(mTag, "onActiveDataSubscriptionIdChanged: subId=" + subId);
+            updateDataSim();
+            updateTelephony();
+        }
     };
 
     static class MobileIconGroup extends SignalController.IconGroup {
diff --git a/packages/SystemUI/tests/res/values/overlayable_icons_test.xml b/packages/SystemUI/tests/res/values/overlayable_icons_test.xml
deleted file mode 100644
index 24cd8cb..0000000
--- a/packages/SystemUI/tests/res/values/overlayable_icons_test.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<!--
-   Copyright (C) 2019 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
--->
-<resources>
-  <!-- overlayable_icons references all of the drawables in this package
-       that are being overlayed by resource overlays. If you remove/rename
-       any of these resources, you must also change the resource overlay icons.-->
-  <array name="overlayable_icons">
-    <item>@drawable/ic_alarm</item>
-    <item>@drawable/ic_alarm_dim</item>
-    <item>@drawable/ic_arrow_back</item>
-    <item>@drawable/ic_bluetooth_connected</item>
-    <item>@drawable/ic_brightness_thumb</item>
-    <item>@drawable/ic_camera</item>
-    <item>@drawable/ic_cast</item>
-    <item>@drawable/ic_cast_connected</item>
-    <item>@drawable/ic_close_white</item>
-    <item>@drawable/ic_data_saver</item>
-    <item>@drawable/ic_data_saver_off</item>
-    <item>@drawable/ic_drag_handle</item>
-    <item>@drawable/ic_headset</item>
-    <item>@drawable/ic_headset_mic</item>
-    <item>@drawable/ic_hotspot</item>
-    <item>@drawable/ic_info</item>
-    <item>@drawable/ic_info_outline</item>
-    <item>@drawable/ic_invert_colors</item>
-    <item>@drawable/ic_location</item>
-    <item>@drawable/ic_lockscreen_ime</item>
-    <item>@drawable/ic_notifications_alert</item>
-    <item>@drawable/ic_notifications_silence</item>
-    <item>@drawable/ic_power_low</item>
-    <item>@drawable/ic_power_saver</item>
-    <item>@drawable/ic_qs_bluetooth_connecting</item>
-    <item>@drawable/ic_qs_cancel</item>
-    <item>@drawable/ic_qs_no_sim</item>
-    <item>@drawable/ic_qs_wifi_0</item>
-    <item>@drawable/ic_qs_wifi_1</item>
-    <item>@drawable/ic_qs_wifi_2</item>
-    <item>@drawable/ic_qs_wifi_3</item>
-    <item>@drawable/ic_qs_wifi_4</item>
-    <item>@drawable/ic_qs_wifi_disconnected</item>
-    <item>@drawable/ic_screenshot_delete</item>
-    <item>@drawable/ic_settings</item>
-    <item>@drawable/ic_swap_vert</item>
-    <item>@drawable/ic_tune_black_16dp</item>
-    <item>@drawable/ic_volume_alarm_mute</item>
-    <item>@drawable/ic_volume_bt_sco</item>
-    <item>@drawable/ic_volume_media</item>
-    <item>@drawable/ic_volume_media_mute</item>
-    <item>@drawable/ic_volume_odi_captions</item>
-    <item>@drawable/ic_volume_odi_captions_disabled</item>
-    <item>@drawable/ic_volume_ringer</item>
-    <item>@drawable/ic_volume_ringer_mute</item>
-    <item>@drawable/ic_volume_ringer_vibrate</item>
-    <item>@drawable/ic_volume_voice</item>
-    <item>@drawable/stat_sys_managed_profile_status</item>
-    <item>@drawable/stat_sys_mic_none</item>
-    <item>@drawable/stat_sys_vpn_ic</item>
-  </array>
-</resources>
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index bdc6341..db6177a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -103,7 +103,8 @@
         when(context.getPackageManager()).thenReturn(mPackageManager);
         doAnswer(invocation -> {
             IBiometricEnabledOnKeyguardCallback callback = invocation.getArgument(0);
-            callback.onChanged(BiometricSourceType.FACE, true /* enabled */);
+            callback.onChanged(BiometricSourceType.FACE, true /* enabled */,
+                    KeyguardUpdateMonitor.getCurrentUser());
             return null;
         }).when(mBiometricManager).registerEnabledOnKeyguardCallback(any());
         when(mFaceManager.isHardwareDetected()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/IconPackOverlayTest.java b/packages/SystemUI/tests/src/com/android/systemui/IconPackOverlayTest.java
deleted file mode 100644
index ccc9afc..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/IconPackOverlayTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui;
-
-import static junit.framework.Assert.fail;
-
-import static org.junit.Assert.assertEquals;
-
-import android.annotation.DrawableRes;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.text.TextUtils;
-import android.util.TypedValue;
-
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.XmlUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class IconPackOverlayTest extends SysuiTestCase {
-
-    private static final String[] ICON_PACK_OVERLAY_PACKAGES = {
-            "com.android.theme.icon_pack.circular.systemui",
-            "com.android.theme.icon_pack.rounded.systemui",
-            "com.android.theme.icon_pack.filled.systemui",
-    };
-
-    private static final int[] VECTOR_ATTRIBUTES = {
-            android.R.attr.tint,
-            android.R.attr.height,
-            android.R.attr.width,
-            android.R.attr.alpha,
-            android.R.attr.autoMirrored,
-    };
-
-    private final TypedValue mTargetTypedValue = new TypedValue();
-    private final TypedValue mOverlayTypedValue = new TypedValue();
-
-    private Resources mResources;
-    private TypedArray mOverlayableIcons;
-
-    @Before
-    public void setup() {
-        mResources = mContext.getResources();
-        mOverlayableIcons = mResources.obtainTypedArray(R.array.overlayable_icons);
-    }
-
-    @After
-    public void teardown() {
-        mOverlayableIcons.recycle();
-    }
-
-    /**
-     * Ensure that all icons contained in overlayable_icons_test.xml exist in all 3 overlay icon
-     * packs for systemui. This test fails if you remove or rename an overlaid icon. If so,
-     * make the same change to the corresponding drawables in {@link #ICON_PACK_OVERLAY_PACKAGES}.
-     */
-    @Test
-    public void testIconPack_containAllOverlayedIcons() {
-        StringBuilder errors = new StringBuilder();
-
-        for (String overlayPackage : ICON_PACK_OVERLAY_PACKAGES) {
-            Resources overlayResources;
-            try {
-                overlayResources = mContext.getPackageManager()
-                        .getResourcesForApplication(overlayPackage);
-            } catch (PackageManager.NameNotFoundException e) {
-                continue; // No need to test overlay resources if apk is not on the system.
-            }
-
-            for (int i = 0; i < mOverlayableIcons.length(); i++) {
-                int sysuiRid = mOverlayableIcons.getResourceId(i, 0);
-                String sysuiResourceName = mResources.getResourceName(sysuiRid);
-                String overlayResourceName = sysuiResourceName
-                        .replace(mContext.getPackageName(), overlayPackage);
-                if (overlayResources.getIdentifier(overlayResourceName, null, null)
-                        == Resources.ID_NULL) {
-                    errors.append(String.format("[%s] is not contained in overlay package [%s]",
-                            overlayResourceName, overlayPackage));
-                }
-            }
-        }
-
-        if (!TextUtils.isEmpty(errors)) {
-            fail(errors.toString());
-        }
-    }
-
-    /**
-     * Ensures that all overlay icons have the same values for {@link #VECTOR_ATTRIBUTES} as the
-     * underlying drawable in systemui. To fix this test, make the attribute change to all of the
-     * corresponding drawables in {@link #ICON_PACK_OVERLAY_PACKAGES}.
-     */
-    @Test
-    public void testIconPacks_haveEqualVectorDrawableAttributes() {
-        StringBuilder errors = new StringBuilder();
-
-        for (String overlayPackage : ICON_PACK_OVERLAY_PACKAGES) {
-            Resources overlayResources;
-            try {
-                overlayResources = mContext.getPackageManager()
-                        .getResourcesForApplication(overlayPackage);
-            } catch (PackageManager.NameNotFoundException e) {
-                continue; // No need to test overlay resources if apk is not on the system.
-            }
-
-            for (int i = 0; i < mOverlayableIcons.length(); i++) {
-                int sysuiRid = mOverlayableIcons.getResourceId(i, 0);
-                String sysuiResourceName = mResources.getResourceName(sysuiRid);
-                TypedArray sysuiAttrs = getAVDAttributes(mResources, sysuiRid);
-                if (sysuiAttrs == null) {
-                    errors.append(String.format("[%s] does not exist or is not a valid AVD.",
-                            sysuiResourceName));
-                    continue;
-                }
-
-                String overlayResourceName = sysuiResourceName
-                        .replace(mContext.getPackageName(), overlayPackage);
-                int overlayRid = overlayResources.getIdentifier(overlayResourceName, null, null);
-                TypedArray overlayAttrs = getAVDAttributes(overlayResources, overlayRid);
-                if (overlayAttrs == null) {
-                    errors.append(String.format("[%s] does not exist or is not a valid AVD.",
-                            overlayResourceName));
-                    continue;
-                }
-
-                if (!attributesEquals(sysuiAttrs, overlayAttrs)) {
-                    errors.append(String.format("[%s] AVD attributes do not match [%s]\n",
-                            sysuiResourceName, overlayResourceName));
-                }
-                sysuiAttrs.recycle();
-                overlayAttrs.recycle();
-            }
-        }
-
-        if (!TextUtils.isEmpty(errors)) {
-            fail(errors.toString());
-        }
-    }
-
-    private TypedArray getAVDAttributes(Resources resources, @DrawableRes int rid) {
-        try {
-            XmlResourceParser parser = resources.getXml(rid);
-            XmlUtils.nextElement(parser);
-            return resources.obtainAttributes(parser, VECTOR_ATTRIBUTES);
-        } catch (XmlPullParserException | IOException  | Resources.NotFoundException e) {
-            return null;
-        }
-    }
-
-    private boolean attributesEquals(TypedArray target, TypedArray overlay) {
-        assertEquals(target.length(), overlay.length());
-        for (int i = 0; i < target.length(); i++) {
-            target.getValue(i, mTargetTypedValue);
-            overlay.getValue(i, mOverlayTypedValue);
-            if (!attributesEquals(mTargetTypedValue, mOverlayTypedValue)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean attributesEquals(TypedValue target, TypedValue overlay) {
-        return target.type == overlay.type && target.data == overlay.data;
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
index 329ef1c..7ea6493 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
@@ -56,6 +56,9 @@
         mHandler = new Handler(mTestableLooper.getLooper());
         mDefaultConfigValue = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_MANAGER_ENABLED, false);
+        // In case it runs on a device where it's been set to true, set it to false by hand.
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+                BRIGHTLINE_FALSING_MANAGER_ENABLED, "false", false);
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index 2d6ae26..2ed0970 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.withSettings;
 
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.utils.hardware.FakeSensorManager;
 
 import org.mockito.Answers;
 import org.mockito.MockSettings;
@@ -39,6 +40,7 @@
         when(params.getPickupPerformsProxCheck()).thenReturn(true);
         when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
         when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);
+        when(params.getDisplayNeedsBlanking()).thenReturn(false);
 
         doneHolder[0] = true;
         return params;
@@ -52,11 +54,17 @@
         when(config.pickupGestureEnabled(anyInt())).thenReturn(false);
         when(config.pulseOnNotificationEnabled(anyInt())).thenReturn(true);
         when(config.alwaysOnEnabled(anyInt())).thenReturn(false);
+        when(config.enabled(anyInt())).thenReturn(true);
+        when(config.getWakeLockScreenDebounce()).thenReturn(0L);
 
         when(config.doubleTapSensorType()).thenReturn(null);
         when(config.tapSensorType()).thenReturn(null);
         when(config.longPressSensorType()).thenReturn(null);
 
+        when(config.tapGestureEnabled(anyInt())).thenReturn(true);
+        when(config.tapSensorAvailable()).thenReturn(true);
+        when(config.tapSensorType()).thenReturn(FakeSensorManager.TAP_SENSOR_TYPE);
+
         when(config.dozePickupSensorAvailable()).thenReturn(false);
         when(config.wakeScreenGestureAvailable()).thenReturn(false);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 6979fd8..eb8ef09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -19,6 +19,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -27,18 +28,17 @@
 import static org.mockito.Mockito.when;
 
 import android.app.AlarmManager;
-import android.app.Instrumentation;
+import android.hardware.Sensor;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.Handler;
 import android.os.Looper;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.wakelock.WakeLock;
 import com.android.systemui.util.wakelock.WakeLockFake;
@@ -46,14 +46,12 @@
 
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @SmallTest
-@Ignore("failing")
 @RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 public class DozeTriggersTest extends SysuiTestCase {
     private DozeTriggers mTriggers;
     private DozeMachine mMachine;
@@ -61,10 +59,10 @@
     private AmbientDisplayConfiguration mConfig;
     private DozeParameters mParameters;
     private FakeSensorManager mSensors;
+    private Sensor mTapSensor;
     private WakeLock mWakeLock;
-    private Instrumentation mInstrumentation;
     private AlarmManager mAlarmManager;
-    private DockManagerFake mDockManagerFake;
+    private DockManager mDockManagerFake;
 
     @BeforeClass
     public static void setupSuite() {
@@ -74,15 +72,15 @@
 
     @Before
     public void setUp() throws Exception {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mMachine = mock(DozeMachine.class);
         mAlarmManager = mock(AlarmManager.class);
-        mHost = new DozeHostFake();
+        mHost = spy(new DozeHostFake());
         mConfig = DozeConfigurationUtil.createMockConfig();
         mParameters = DozeConfigurationUtil.createMockParameters();
-        mSensors = new FakeSensorManager(mContext);
+        mSensors = spy(new FakeSensorManager(mContext));
+        mTapSensor = mSensors.getFakeTapSensor().getSensor();
         mWakeLock = new WakeLockFake();
-        mDockManagerFake = spy(new DockManagerFake());
+        mDockManagerFake = mock(DockManager.class);
 
         mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, mConfig, mParameters,
                 mSensors, Handler.createAsync(Looper.myLooper()), mWakeLock, true,
@@ -95,29 +93,45 @@
 
         mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
         mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+        clearInvocations(mMachine);
 
         mHost.callback.onNotificationAlerted();
-
         mSensors.getMockProximitySensor().sendProximityResult(false); /* Near */
 
         verify(mMachine, never()).requestState(any());
         verify(mMachine, never()).requestPulse(anyInt());
 
         mHost.callback.onNotificationAlerted();
-
         mSensors.getMockProximitySensor().sendProximityResult(true); /* Far */
 
         verify(mMachine).requestPulse(anyInt());
     }
 
     @Test
+    public void testTransitionTo_disablesAndEnablesTouchSensors() {
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+
+        mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+        verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor));
+
+        clearInvocations(mSensors);
+        mTriggers.transitionTo(DozeMachine.State.DOZE,
+                DozeMachine.State.DOZE_REQUEST_PULSE);
+        mTriggers.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
+                DozeMachine.State.DOZE_PULSING);
+        verify(mSensors).cancelTriggerSensor(any(), eq(mTapSensor));
+
+        clearInvocations(mSensors);
+        mTriggers.transitionTo(DozeMachine.State.DOZE_PULSING, DozeMachine.State.DOZE_PULSE_DONE);
+        verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor));
+    }
+
+    @Test
     public void testDockEventListener_registerAndUnregister() {
         mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-
         verify(mDockManagerFake).addListener(any());
 
         mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
-
         verify(mDockManagerFake).removeListener(any());
     }
 
@@ -128,7 +142,6 @@
         mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
                 false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
                 null /* rawValues */);
-
         verify(mMachine, never()).wakeUp();
     }
 
@@ -142,7 +155,7 @@
                 false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
                 null /* rawValues */);
 
-        verify(mHost).setAodDimmingScrim(eq(255));
+        verify(mHost).setAodDimmingScrim(eq(1f));
         verify(mMachine).wakeUp();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
index 87ae85f..f07edf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -29,6 +30,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.DozeParameters;
 
 import org.junit.Before;
@@ -44,12 +46,14 @@
 
     private DozeWallpaperState mDozeWallpaperState;
     @Mock IWallpaperManager mIWallpaperManager;
+    @Mock BiometricUnlockController mBiometricUnlockController;
     @Mock DozeParameters mDozeParameters;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mDozeParameters);
+        mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mBiometricUnlockController,
+                mDozeParameters);
     }
 
     @Test
@@ -102,6 +106,20 @@
     }
 
     @Test
+    public void testDoesNotAnimate_whenWakeAndUnlock() throws RemoteException {
+        // Pre-conditions
+        when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+        when(mBiometricUnlockController.unlockedByWakeAndUnlock()).thenReturn(true);
+
+        mDozeWallpaperState.transitionTo(DozeMachine.State.UNINITIALIZED,
+                DozeMachine.State.DOZE_AOD);
+        clearInvocations(mIWallpaperManager);
+
+        mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD, DozeMachine.State.FINISH);
+        verify(mIWallpaperManager).setInAmbientMode(eq(false), eq(0L));
+    }
+
+    @Test
     public void testTransitionTo_requestPulseIsAmbientMode() throws RemoteException {
         mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE,
                 DozeMachine.State.DOZE_REQUEST_PULSE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 893f3d1..9576cb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -48,6 +48,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -197,6 +198,7 @@
 
     @Test
     public void onMetadataChanged_updatesSlice() {
+        mProvider.onStateChanged(StatusBarState.KEYGUARD);
         mProvider.onDozingChanged(true);
         reset(mContentResolver);
         mProvider.onMetadataOrStateChanged(mock(MediaMetadata.class), PlaybackState.STATE_PLAYING);
@@ -210,6 +212,7 @@
 
     @Test
     public void onDozingChanged_updatesSliceIfMedia() {
+        mProvider.onStateChanged(StatusBarState.KEYGUARD);
         mProvider.onMetadataOrStateChanged(mock(MediaMetadata.class), PlaybackState.STATE_PLAYING);
         reset(mContentResolver);
         // Show media when dozing
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 5c1f473..881cc39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -64,7 +64,7 @@
     protected static final int TEST_AUTO_DISMISS_TIME = 500;
     // Number of notifications to use in tests requiring multiple notifications
     private static final int TEST_NUM_NOTIFICATIONS = 4;
-    protected static final int TEST_TIMEOUT_TIME = 10000;
+    protected static final int TEST_TIMEOUT_TIME = 15000;
     protected final Runnable TEST_TIMEOUT_RUNNABLE = () -> mTimedOut = true;
 
     private AlertingNotificationManager mAlertingNotificationManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 49a263a..57dd8c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -38,7 +38,6 @@
 import android.os.Looper;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
@@ -48,6 +47,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
@@ -166,7 +166,7 @@
                 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
         when(mNotificationData.isHighPriority(any())).thenReturn(false);
 
-        assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class)));
+        assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class)));
     }
 
     @Test
@@ -179,7 +179,7 @@
                 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
         when(mNotificationData.isHighPriority(any())).thenReturn(false);
 
-        assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class)));
+        assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(NotificationEntry.class)));
     }
 
     private class TestNotificationLockscreenUserManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 73abda9..59d0f91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -263,6 +263,8 @@
                     when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
                     when(notifRow.getEntry().isHighPriority())
                             .thenReturn(children[i] == ChildType.HIPRI);
+                    when(notifRow.getEntry().isTopBucket())
+                            .thenReturn(children[i] == ChildType.HIPRI);
                     when(notifRow.getParent()).thenReturn(mNssl);
                     child = notifRow;
                     break;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index a99dc7f..4a41349 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -80,7 +82,7 @@
         MockitoAnnotations.initMocks(this);
         when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
         when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
-        when(mUnlockMethodCache.isUnlockingWithFacePossible()).thenReturn(true);
+        when(mUnlockMethodCache.isFaceAuthEnabled()).thenReturn(true);
         when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
         when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
         mContext.addMockSystemService(PowerManager.class, mPowerManager);
@@ -192,6 +194,34 @@
     }
 
     @Test
+    public void onBiometricAuthenticated_whenBypassOnBouncer_dismissBouncer() {
+        reset(mKeyguardBypassController);
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+                BiometricSourceType.FACE);
+
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
+    }
+
+    @Test
+    public void onBiometricAuthenticated_whenBypassOnBouncer_respectsCanPlaySubtleAnim() {
+        when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
+        when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
+        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+                BiometricSourceType.FACE);
+
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+        assertThat(mBiometricUnlockController.getMode())
+                .isEqualTo(BiometricUnlockController.MODE_UNLOCK_FADING);
+    }
+
+    @Test
     public void onBiometricAuthenticated_whenFaceAndPulsing_dontDismissKeyguard() {
         reset(mUpdateMonitor);
         reset(mStatusBarKeyguardViewManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index b45707e..a38094d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -35,6 +35,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
@@ -59,6 +60,7 @@
     private View mOperatorNameView;
     private StatusBarStateController mStatusbarStateController;
     private KeyguardBypassController mBypassController;
+    private NotificationWakeUpCoordinator mWakeUpCoordinator;
 
     @Before
     public void setUp() throws Exception {
@@ -72,11 +74,13 @@
         mOperatorNameView = new View(mContext);
         mStatusbarStateController = mock(StatusBarStateController.class);
         mBypassController = mock(KeyguardBypassController.class);
+        mWakeUpCoordinator = mock(NotificationWakeUpCoordinator.class);
         mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                 mock(NotificationIconAreaController.class),
                 mHeadsUpManager,
                 mStatusbarStateController,
                 mBypassController,
+                mWakeUpCoordinator,
                 mHeadsUpStatusBarView,
                 mStackScroller,
                 mPanelView,
@@ -153,6 +157,7 @@
                 mHeadsUpManager,
                 mStatusbarStateController,
                 mBypassController,
+                mWakeUpCoordinator,
                 mHeadsUpStatusBarView,
                 mStackScroller,
                 mPanelView,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index f8b9e68..48934da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -70,7 +70,6 @@
             setUp(statusBarWindowView, groupManager, bar, vsManager);
             mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
             mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
-            mAutoDismissNotificationDecayDozing = TEST_AUTO_DISMISS_TIME;
         }
     }
 
@@ -134,13 +133,11 @@
 
     @Test
     public void testExtendHeadsUp() {
-        when(mStatusBarStateController.isDozing()).thenReturn(true);
         mHeadsUpManager.showNotification(mEntry);
         Runnable pastNormalTimeRunnable =
                 () -> mLivesPastNormalTime = mHeadsUpManager.isAlerting(mEntry.key);
         mTestHandler.postDelayed(pastNormalTimeRunnable,
-                mHeadsUpManager.mAutoDismissNotificationDecayDozing +
-                        mHeadsUpManager.mExtensionTime / 2);
+                TEST_AUTO_DISMISS_TIME + mHeadsUpManager.mExtensionTime / 2);
         mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_TIMEOUT_TIME);
 
         mHeadsUpManager.extendHeadsUp();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 4e0ef56..907e695 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -379,7 +379,7 @@
 
     @Test
     public void testShow_delaysIfFaceAuthIsRunning() {
-        when(mUnlockMethodCache.isUnlockingWithFacePossible()).thenReturn(true);
+        when(mUnlockMethodCache.isFaceAuthEnabled()).thenReturn(true);
         mBouncer.show(true /* reset */);
 
         ArgumentCaptor<Runnable> showRunnable = ArgumentCaptor.forClass(Runnable.class);
@@ -394,4 +394,15 @@
     public void testRegisterUpdateMonitorCallback() {
         verify(mKeyguardUpdateMonitor).registerCallback(any());
     }
+
+    @Test
+    public void testInTransit_whenTranslation() {
+        mBouncer.show(true);
+        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
+        assertThat(mBouncer.inTransit()).isFalse();
+        mBouncer.setExpansion(0.5f);
+        assertThat(mBouncer.inTransit()).isTrue();
+        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
+        assertThat(mBouncer.inTransit()).isFalse();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index d8e90a5..0dbf308 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -225,11 +225,12 @@
 
         mScrimController.transitionTo(ScrimState.PULSING);
         mScrimController.finishAnimationsImmediately();
-        // Front scrim should be transparent
+        // Front scrim should be transparent, but tinted
         // Back scrim should be semi-transparent so the user can see the wallpaper
         // Pulse callback should have been invoked
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
         assertScrimTint(mScrimBehind, true /* tinted */);
+        assertScrimTint(mScrimInFront, true /* tinted */);
 
         mScrimController.setWakeLockScreenSensorActive(true);
         mScrimController.finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
index a4ae166..29b8ab60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
@@ -40,18 +40,23 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
+import javax.annotation.Nullable;
+
 /**
  * Rudimentary fake for SensorManager
  *
- * Currently only supports the proximity sensor.
+ * Currently only supports proximity, light and tap sensors.
  *
  * Note that this class ignores the "Handler" argument, so the test is responsible for calling the
  * listener on the right thread.
  */
 public class FakeSensorManager extends SensorManager {
 
+    public static final String TAP_SENSOR_TYPE = "tapSensorType";
+
     private final MockProximitySensor mMockProximitySensor;
     private final FakeGenericSensor mFakeLightSensor;
+    private final FakeGenericSensor mFakeTapSensor;
     private final FakeGenericSensor[] mSensors;
 
     public FakeSensorManager(Context context) throws Exception {
@@ -59,12 +64,13 @@
                 .getDefaultSensor(Sensor.TYPE_PROXIMITY);
         if (proxSensor == null) {
             // No prox? Let's create a fake one!
-            proxSensor = createSensor(Sensor.TYPE_PROXIMITY);
+            proxSensor = createSensor(Sensor.TYPE_PROXIMITY, null);
         }
 
         mSensors = new FakeGenericSensor[]{
                 mMockProximitySensor = new MockProximitySensor(proxSensor),
-                mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT)),
+                mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)),
+                mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE))
         };
     }
 
@@ -76,6 +82,10 @@
         return mFakeLightSensor;
     }
 
+    public FakeGenericSensor getFakeTapSensor() {
+        return mFakeTapSensor;
+    }
+
     @Override
     public Sensor getDefaultSensor(int type) {
         Sensor s = super.getDefaultSensor(type);
@@ -160,13 +170,13 @@
 
     @Override
     protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
-        return false;
+        return true;
     }
 
     @Override
     protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
             boolean disable) {
-        return false;
+        return true;
     }
 
     @Override
@@ -185,12 +195,15 @@
         return false;
     }
 
-    private Sensor createSensor(int type) throws Exception {
+    private Sensor createSensor(int type, @Nullable String stringType) throws Exception {
         Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
         constr.setAccessible(true);
         Sensor sensor = constr.newInstance();
 
         setSensorType(sensor, type);
+        if (stringType != null) {
+            setSensorField(sensor, "mStringType", stringType);
+        }
         setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type);
         setSensorField(sensor, "mVendor", "Mock Vendor");
         setSensorField(sensor, "mVersion", 1);
diff --git a/cmds/statsd/tools/dogfood/Android.bp b/packages/overlays/tests/Android.bp
similarity index 66%
rename from cmds/statsd/tools/dogfood/Android.bp
rename to packages/overlays/tests/Android.bp
index bb494a6..343367a 100644
--- a/cmds/statsd/tools/dogfood/Android.bp
+++ b/packages/overlays/tests/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 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.
@@ -11,27 +11,27 @@
 // WITHOUT 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: "StatsdDogfood",
-    platform_apis: true,
+android_test {
+    name: "OverlayTests",
+
+    certificate: "platform",
 
     srcs: ["src/**/*.java"],
 
-    resource_dirs: ["res"],
-    static_libs: [
-        "platformprotoslite",
-        "statsdprotolite",
+    libs: [
+        "android.test.runner",
+        "android.test.base",
     ],
 
-    privileged: true,
-    dex_preopt: {
-        enabled: false,
-    },
-    certificate: "platform",
-    optimize: {
-        enabled: false,
-    },
+    platform_apis: true,
+
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.espresso.core",
+        "mockito-target-minus-junit4",
+        "truth-prebuilt",
+    ],
+
+    dxflags: ["--multi-dex"],
 }
diff --git a/packages/overlays/tests/AndroidManifest.xml b/packages/overlays/tests/AndroidManifest.xml
new file mode 100644
index 0000000..6ebc555
--- /dev/null
+++ b/packages/overlays/tests/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.overlays">
+
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY"/>
+    <uses-permission android:name="android.permission.SET_TIME_ZONE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.systemui"
+        android:label="Tests for Overlays">
+    </instrumentation>
+</manifest>
diff --git a/packages/overlays/tests/AndroidTest.xml b/packages/overlays/tests/AndroidTest.xml
new file mode 100644
index 0000000..8843d62
--- /dev/null
+++ b/packages/overlays/tests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?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
+  -->
+<configuration description="Runs Tests for Overlays.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="OverlayTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="OverlayTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.overlays" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/packages/overlays/tests/src/com/android/theme/icon/IconPackOverlayTest.java b/packages/overlays/tests/src/com/android/theme/icon/IconPackOverlayTest.java
new file mode 100644
index 0000000..6bc56ba
--- /dev/null
+++ b/packages/overlays/tests/src/com/android/theme/icon/IconPackOverlayTest.java
@@ -0,0 +1,293 @@
+/*
+ * 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.theme.icon;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+
+import android.annotation.DrawableRes;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.text.TextUtils;
+import android.util.TypedValue;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.XmlUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class IconPackOverlayTest {
+    private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+    private static final String[] SYSTEMUI_ICON_PACK_OVERLAY_PACKAGES = {
+            "com.android.theme.icon_pack.circular.systemui",
+            "com.android.theme.icon_pack.rounded.systemui",
+            "com.android.theme.icon_pack.filled.systemui",
+    };
+    private static final String ANDROID_PACKAGE = "android";
+    private static final String[] ANDROID_ICON_PACK_OVERLAY_PACKAGES = {
+            "com.android.theme.icon_pack.circular.android",
+            "com.android.theme.icon_pack.rounded.android",
+            "com.android.theme.icon_pack.filled.android",
+    };
+    private static final String SETTINGS_PACKAGE = "com.android.settings";
+    private static final String[] SETTINGS_ICON_PACK_OVERLAY_PACKAGES = {
+            "com.android.theme.icon_pack.circular.settings",
+            "com.android.theme.icon_pack.rounded.settings",
+            "com.android.theme.icon_pack.filled.settings",
+    };
+
+    private static final int[] VECTOR_ATTRIBUTES = {
+            android.R.attr.tint,
+            android.R.attr.height,
+            android.R.attr.width,
+            android.R.attr.alpha,
+            android.R.attr.autoMirrored,
+    };
+
+    private final TypedValue mTargetTypedValue = new TypedValue();
+    private final TypedValue mOverlayTypedValue = new TypedValue();
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getContext();
+    }
+
+    /**
+     * Ensure that drawable icons in icon packs targeting android have corresponding underlying
+     * drawables in android. This test fails if you remove/rename an overlaid icon in android.
+     * If so, make the same change to the corresponding drawables in the overlay packages.
+     */
+    @Test
+    public void testAndroidFramework_containsAllOverlayedIcons() {
+        containsAllOverlayedIcons(ANDROID_PACKAGE, ANDROID_ICON_PACK_OVERLAY_PACKAGES);
+    }
+
+    /**
+     * Ensure that drawable icons in icon packs targeting settings have corresponding underlying
+     * drawables in settings. This test fails if you remove/rename an overlaid icon in settings.
+     * If so, make the same change to the corresponding drawables in the overlay packages.
+     */
+    @Test
+    public void testSettings_containsAllOverlayedIcons() {
+        containsAllOverlayedIcons(SETTINGS_PACKAGE, SETTINGS_ICON_PACK_OVERLAY_PACKAGES);
+    }
+
+    /**
+     * Ensure that drawable icons in icon packs targeting systemui have corresponding underlying
+     * drawables in systemui. This test fails if you remove/rename an overlaid icon in systemui.
+     * If so, make the same change to the corresponding drawables in the overlay packages.
+     */
+    @Test
+    public void testSystemUI_containAllOverlayedIcons() {
+        containsAllOverlayedIcons(SYSTEMUI_PACKAGE, SYSTEMUI_ICON_PACK_OVERLAY_PACKAGES);
+    }
+
+    /**
+     * Ensures that all overlay icons have the same values for {@link #VECTOR_ATTRIBUTES} as the
+     * underlying drawable in android. To fix this test, make the attribute change to all of the
+     * corresponding drawables in the overlay packages.
+     */
+    @Test
+    public void testAndroidFramework_hasEqualVectorDrawableAttributes() {
+        hasEqualVectorDrawableAttributes(ANDROID_PACKAGE, ANDROID_ICON_PACK_OVERLAY_PACKAGES);
+    }
+
+    /**
+     * Ensures that all overlay icons have the same values for {@link #VECTOR_ATTRIBUTES} as the
+     * underlying drawable in settings. To fix this test, make the attribute change to all of the
+     * corresponding drawables in the overlay packages.
+     */
+    @Test
+    public void testSettings_hasEqualVectorDrawableAttributes() {
+        hasEqualVectorDrawableAttributes(SETTINGS_PACKAGE, SETTINGS_ICON_PACK_OVERLAY_PACKAGES);
+    }
+
+    /**
+     * Ensures that all overlay icons have the same values for {@link #VECTOR_ATTRIBUTES} as the
+     * underlying drawable in systemui. To fix this test, make the attribute change to all of the
+     * corresponding drawables in the overlay packages.
+     */
+    @Test
+    public void testSystemUI_hasEqualVectorDrawableAttributes() {
+        hasEqualVectorDrawableAttributes(SYSTEMUI_PACKAGE, SYSTEMUI_ICON_PACK_OVERLAY_PACKAGES);
+    }
+
+    private void containsAllOverlayedIcons(String targetPkg, String[] overlayPkgs) {
+        final Resources targetResources;
+        try {
+            targetResources = mContext.getPackageManager()
+                    .getResourcesForApplication(targetPkg);
+        } catch (PackageManager.NameNotFoundException e) {
+            return; // No need to test overlays if target package does not exist on the system.
+        }
+
+        StringBuilder errors = new StringBuilder();
+        for (String overlayPackage : overlayPkgs) {
+            final ApplicationInfo info;
+            try {
+                info = mContext.getPackageManager().getApplicationInfo(overlayPackage, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                continue; // No need to test overlay resources if apk is not on the system.
+            }
+            final List<String> iconPackDrawables = getDrawablesFromOverlay(info);
+            for (int i = 0; i < iconPackDrawables.size(); i++) {
+                String resourceName = iconPackDrawables.get(i);
+                int targetRid = targetResources.getIdentifier(resourceName, "drawable", targetPkg);
+                if (targetRid == Resources.ID_NULL) {
+                    errors.append(String.format("[%s] is not contained in the target package [%s]",
+                            resourceName, targetPkg));
+                }
+            }
+        }
+
+        if (!TextUtils.isEmpty(errors)) {
+            fail(errors.toString());
+        }
+    }
+
+    private void hasEqualVectorDrawableAttributes(String targetPkg, String[] overlayPackages) {
+        final Resources targetRes;
+        try {
+            targetRes = mContext.getPackageManager().getResourcesForApplication(targetPkg);
+        } catch (PackageManager.NameNotFoundException e) {
+            return; // No need to test overlays if target package does not exist on the system.
+        }
+
+        StringBuilder errors = new StringBuilder();
+
+        for (String overlayPkg : overlayPackages) {
+            final ApplicationInfo info;
+            try {
+                info = mContext.getPackageManager().getApplicationInfo(overlayPkg, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                continue; // No need to test overlay resources if apk is not on the system.
+            }
+            final List<String> iconPackDrawables = getDrawablesFromOverlay(info);
+            final Resources overlayRes;
+            try {
+                overlayRes = mContext.getPackageManager().getResourcesForApplication(overlayPkg);
+            } catch (PackageManager.NameNotFoundException e) {
+                continue; // No need to test overlay resources if apk is not on the system.
+            }
+
+            for (int i = 0; i < iconPackDrawables.size(); i++) {
+                String resourceName = iconPackDrawables.get(i);
+                int targetRid = targetRes.getIdentifier(resourceName, "drawable", targetPkg);
+                int overlayRid = overlayRes.getIdentifier(resourceName, "drawable", overlayPkg);
+                TypedArray targetAttrs = getAVDAttributes(targetRes, targetRid);
+                if (targetAttrs == null) {
+                    errors.append(String.format(
+                            "[%s] in pkg [%s] does not exist or is not a valid vector drawable.\n",
+                            resourceName, targetPkg));
+                    continue;
+                }
+
+                TypedArray overlayAttrs = getAVDAttributes(overlayRes, overlayRid);
+                if (overlayAttrs == null) {
+                    errors.append(String.format(
+                            "[%s] in pkg [%s] does not exist or is not a valid vector drawable.\n",
+                            resourceName, overlayPkg));
+                    continue;
+                }
+
+                if (!attributesEquals(targetAttrs, overlayAttrs)) {
+                    errors.append(String.format("[drawable/%s] in [%s] does not have the same "
+                                    + "attributes as the corresponding drawable from [%s]\n",
+                            resourceName, targetPkg, overlayPkg));
+                }
+                targetAttrs.recycle();
+                overlayAttrs.recycle();
+            }
+        }
+
+        if (!TextUtils.isEmpty(errors)) {
+            fail(errors.toString());
+        }
+    }
+
+    private TypedArray getAVDAttributes(Resources resources, @DrawableRes int rid) {
+        try {
+            XmlResourceParser parser = resources.getXml(rid);
+            XmlUtils.nextElement(parser);
+            // Always use the the test apk theme to resolve attributes.
+            return mContext.getTheme().obtainStyledAttributes(parser, VECTOR_ATTRIBUTES, 0, 0);
+        } catch (XmlPullParserException | IOException  | Resources.NotFoundException e) {
+            return null;
+        }
+    }
+
+    private boolean attributesEquals(TypedArray target, TypedArray overlay) {
+        assertEquals(target.length(), overlay.length());
+        for (int i = 0; i < target.length(); i++) {
+            target.getValue(i, mTargetTypedValue);
+            overlay.getValue(i, mOverlayTypedValue);
+            if (!attributesEquals(mTargetTypedValue, mOverlayTypedValue)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean attributesEquals(TypedValue target, TypedValue overlay) {
+        return target.type == overlay.type && target.data == overlay.data;
+    }
+
+    private static List<String> getDrawablesFromOverlay(ApplicationInfo applicationInfo) {
+        try {
+            final ArrayList<String> drawables = new ArrayList<>();
+            ZipFile file = new ZipFile(applicationInfo.sourceDir);
+            Enumeration<? extends ZipEntry> entries = file.entries();
+            while (entries.hasMoreElements()) {
+                ZipEntry element = entries.nextElement();
+                String name = element.getName();
+                if (name.contains("/drawable/")) {
+                    name = name.substring(name.lastIndexOf('/') + 1);
+                    if (name.contains(".")) {
+                        name = name.substring(0, name.indexOf('.'));
+                    }
+                    drawables.add(name);
+                }
+            }
+            return drawables;
+        } catch (IOException e) {
+            fail(String.format("Failed to retrieve drawables from package [%s] with message [%s]",
+                    applicationInfo.packageName, e.getMessage()));
+            return null;
+        }
+    }
+}
diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto
index 381d983..821db86 100644
--- a/proto/src/task_snapshot.proto
+++ b/proto/src/task_snapshot.proto
@@ -33,4 +33,5 @@
      bool is_translucent = 9;
      string top_activity_component = 10;
      float scale = 11;
- }
\ No newline at end of file
+     int64 id = 12;
+ }
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index f9a2ca2..8ad2489 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -551,6 +551,30 @@
 
   // Histogram of the EAP method type of all installed Passpoint profiles for R2
   repeated PasspointProfileTypeCount installed_passpoint_profile_type_for_r2 = 148;
+
+  // Histogram of Tx link speed at 2G
+  repeated Int32Count tx_link_speed_count_2g = 149;
+
+  // Histogram of Tx link speed at 5G low band
+  repeated Int32Count tx_link_speed_count_5g_low = 150;
+
+  // Histogram of Tx link speed at 5G middle band
+  repeated Int32Count tx_link_speed_count_5g_mid = 151;
+
+  // Histogram of Tx link speed at 5G high band
+  repeated Int32Count tx_link_speed_count_5g_high = 152;
+
+  // Histogram of Rx link speed at 2G
+  repeated Int32Count rx_link_speed_count_2g = 153;
+
+  // Histogram of Rx link speed at 5G low band
+  repeated Int32Count rx_link_speed_count_5g_low = 154;
+
+  // Histogram of Rx link speed at 5G middle band
+  repeated Int32Count rx_link_speed_count_5g_mid = 155;
+
+  // Histogram of Rx link speed at 5G high band
+  repeated Int32Count rx_link_speed_count_5g_high = 156;
 }
 
 // Information that gets logged for every WiFi connection.
@@ -827,6 +851,7 @@
   optional int64 rssi_sum_of_squares_dbm_sq = 4;
 }
 
+
 // Number of occurrences of Soft AP session durations
 message SoftApDurationBucket {
   // Bucket covers duration : [duration_sec, duration_sec + bucket_size_sec)
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 3bdfc33..d923bed 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -17,7 +17,6 @@
 package com.android.server.accessibility;
 
 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
-import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
@@ -38,6 +37,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.graphics.Region;
+import android.hardware.display.DisplayManager;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -50,6 +50,7 @@
 import android.os.SystemClock;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.Display;
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
 import android.view.View;
@@ -89,9 +90,10 @@
 
     protected final Context mContext;
     protected final SystemSupport mSystemSupport;
-    private final WindowManagerInternal mWindowManagerService;
+    protected final WindowManagerInternal mWindowManagerService;
     private final GlobalActionPerformer mGlobalActionPerformer;
     private final AccessibilityWindowManager mA11yWindowManager;
+    private final DisplayManager mDisplayManager;
     private final PowerManager mPowerManager;
 
     // Handler for scheduling method invocations on the main thread.
@@ -150,7 +152,7 @@
     // types as message types allowing us to remove messages per event type.
     public Handler mEventDispatchHandler;
 
-    final IBinder mOverlayWindowToken = new Binder();
+    final SparseArray<IBinder> mOverlayWindowTokens = new SparseArray();
 
 
     public interface SystemSupport {
@@ -166,9 +168,10 @@
         @Nullable MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId);
 
         /**
-         * @return The current injector of motion events, if one exists
+         * @param displayId The display id.
+         * @return The current injector of motion events used on the display, if one exists.
          */
-        @Nullable MotionEventInjector getMotionEventInjectorLocked();
+        @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId);
 
         /**
          * @return The current dispatcher for fingerprint gestures, if one exists
@@ -223,6 +226,7 @@
         mSystemSupport = systemSupport;
         mInvocationHandler = new InvocationHandler(mainHandler.getLooper());
         mA11yWindowManager = a11yWindowManager;
+        mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mEventDispatchHandler = new Handler(mainHandler.getLooper()) {
             @Override
@@ -713,6 +717,10 @@
     }
 
     @Override
+    public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
+    }
+
+    @Override
     public boolean performAccessibilityAction(int accessibilityWindowId,
             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
@@ -929,24 +937,73 @@
     }
 
     public void onAdded() {
+        final Display[] displays = mDisplayManager.getDisplays();
+        for (int i = 0; i < displays.length; i++) {
+            final int displayId = displays[i].getDisplayId();
+            onDisplayAdded(displayId);
+        }
+    }
+
+    /**
+     * Called whenever a logical display has been added to the system. Add a window token for adding
+     * an accessibility overlay.
+     *
+     * @param displayId The id of the logical display that was added.
+     */
+    public void onDisplayAdded(int displayId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            mWindowManagerService.addWindowToken(mOverlayWindowToken,
-                    TYPE_ACCESSIBILITY_OVERLAY, DEFAULT_DISPLAY);
+            final IBinder overlayWindowToken = new Binder();
+            mWindowManagerService.addWindowToken(overlayWindowToken, TYPE_ACCESSIBILITY_OVERLAY,
+                    displayId);
+            synchronized (mLock) {
+                mOverlayWindowTokens.put(displayId, overlayWindowToken);
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
     public void onRemoved() {
+        final Display[] displays = mDisplayManager.getDisplays();
+        for (int i = 0; i < displays.length; i++) {
+            final int displayId = displays[i].getDisplayId();
+            onDisplayRemoved(displayId);
+        }
+    }
+
+    /**
+     * Called whenever a logical display has been removed from the system. Remove a window token for
+     * removing an accessibility overlay.
+     *
+     * @param displayId The id of the logical display that was added.
+     */
+    public void onDisplayRemoved(int displayId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            mWindowManagerService.removeWindowToken(mOverlayWindowToken, true, DEFAULT_DISPLAY);
+            mWindowManagerService.removeWindowToken(mOverlayWindowTokens.get(displayId), true,
+                    displayId);
+            synchronized (mLock) {
+                mOverlayWindowTokens.remove(displayId);
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
+    /**
+     * Gets overlay window token by the display Id.
+     *
+     * @param displayId The id of the logical display that was added.
+     * @return window token.
+     */
+    @Override
+    public IBinder getOverlayWindowToken(int displayId) {
+        synchronized (mLock) {
+            return mOverlayWindowTokens.get(displayId);
+        }
+    }
+
     public void resetLocked() {
         mSystemSupport.getKeyEventDispatcher().flush(this);
         try {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index b6cbbac..5111bec 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -114,7 +114,7 @@
     private final SparseArray<MagnificationGestureHandler> mMagnificationGestureHandler =
             new SparseArray<>(0);
 
-    private final SparseArray<MotionEventInjector> mMotionEventInjector = new SparseArray<>(0);
+    private final SparseArray<MotionEventInjector> mMotionEventInjectors = new SparseArray<>(0);
 
     private AutoclickController mAutoclickController;
 
@@ -412,12 +412,14 @@
                 MotionEventInjector injector = new MotionEventInjector(
                         mContext.getMainLooper());
                 addFirstEventHandler(displayId, injector);
-                // TODO: Need to set MotionEventInjector per display.
-                mAms.setMotionEventInjector(injector);
-                mMotionEventInjector.put(displayId, injector);
+                mMotionEventInjectors.put(displayId, injector);
             }
         }
 
+        if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
+            mAms.setMotionEventInjectors(mMotionEventInjectors);
+        }
+
         if ((mEnabledFeatures & FLAG_FEATURE_FILTER_KEY_EVENTS) != 0) {
             mKeyboardInterceptor = new KeyboardInterceptor(mAms,
                     LocalServices.getService(WindowManagerPolicy.class));
@@ -462,15 +464,14 @@
     }
 
     private void disableFeatures() {
-        for (int i = mMotionEventInjector.size() - 1; i >= 0; i--) {
-            final MotionEventInjector injector = mMotionEventInjector.valueAt(i);
-            // TODO: Need to set MotionEventInjector per display.
-            mAms.setMotionEventInjector(null);
+        for (int i = mMotionEventInjectors.size() - 1; i >= 0; i--) {
+            final MotionEventInjector injector = mMotionEventInjectors.valueAt(i);
             if (injector != null) {
                 injector.onDestroy();
             }
         }
-        mMotionEventInjector.clear();
+        mAms.setMotionEventInjectors(null);
+        mMotionEventInjectors.clear();
         if (mAutoclickController != null) {
             mAutoclickController.onDestroy();
             mAutoclickController = null;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7c0702a..8148536 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -211,7 +211,7 @@
 
     private KeyEventDispatcher mKeyEventDispatcher;
 
-    private MotionEventInjector mMotionEventInjector;
+    private SparseArray<MotionEventInjector> mMotionEventInjectors;
 
     private FingerprintGestureDispatcher mFingerprintGestureDispatcher;
 
@@ -580,10 +580,11 @@
             // Make sure clients receiving this event will be able to get the
             // current state of the windows as the window manager may be delaying
             // the computation for performance reasons.
+            // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
             if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
                     && mA11yWindowManager.isTrackingWindowsLocked()) {
                 WindowManagerInternal wm = LocalServices.getService(WindowManagerInternal.class);
-                wm.computeWindowsForAccessibility();
+                wm.computeWindowsForAccessibility(Display.DEFAULT_DISPLAY);
             }
             synchronized (mLock) {
                 notifyAccessibilityServicesDelayedLocked(event, false);
@@ -860,30 +861,34 @@
      * Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector.
      * Not using a getter because the AccessibilityInputFilter isn't thread-safe
      *
-     * @param motionEventInjector The new value of the motionEventInjector. May be null.
+     * @param motionEventInjectors The array of motionEventInjectors. May be null.
+     *
      */
-    void setMotionEventInjector(MotionEventInjector motionEventInjector) {
+    void setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors) {
         synchronized (mLock) {
-            mMotionEventInjector = motionEventInjector;
+            mMotionEventInjectors = motionEventInjectors;
             // We may be waiting on this object being set
             mLock.notifyAll();
         }
     }
 
     @Override
-    public MotionEventInjector getMotionEventInjectorLocked() {
+    public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) {
         final long endMillis = SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS;
-        while ((mMotionEventInjector == null) && (SystemClock.uptimeMillis() < endMillis)) {
+        MotionEventInjector motionEventInjector = null;
+        while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) {
             try {
                 mLock.wait(endMillis - SystemClock.uptimeMillis());
             } catch (InterruptedException ie) {
                 /* ignore */
             }
         }
-        if (mMotionEventInjector == null) {
+        if (mMotionEventInjectors == null) {
             Slog.e(LOG_TAG, "MotionEventInjector installation timed out");
+        } else {
+            motionEventInjector = mMotionEventInjectors.get(displayId);
         }
-        return mMotionEventInjector;
+        return motionEventInjector;
     }
 
     /**
@@ -2551,6 +2556,13 @@
                     mInputFilter.onDisplayChanged();
                 }
                 UserState userState = getCurrentUserStateLocked();
+                if (displayId != Display.DEFAULT_DISPLAY) {
+                    final List<AccessibilityServiceConnection> services = userState.mBoundServices;
+                    for (int i = 0; i < services.size(); i++) {
+                        AccessibilityServiceConnection boundClient = services.get(i);
+                        boundClient.onDisplayAdded(displayId);
+                    }
+                }
                 updateMagnificationLocked(userState);
             }
         }
@@ -2567,6 +2579,14 @@
                 if (mInputFilter != null) {
                     mInputFilter.onDisplayChanged();
                 }
+                UserState userState = getCurrentUserStateLocked();
+                if (displayId != Display.DEFAULT_DISPLAY) {
+                    final List<AccessibilityServiceConnection> services = userState.mBoundServices;
+                    for (int i = 0; i < services.size(); i++) {
+                        AccessibilityServiceConnection boundClient = services.get(i);
+                        boundClient.onDisplayRemoved(displayId);
+                    }
+                }
             }
             if (mMagnificationController != null) {
                 mMagnificationController.onDisplayRemoved(displayId);
@@ -2602,8 +2622,6 @@
         public final RemoteCallbackList<IAccessibilityManagerClient> mUserClients =
                 new RemoteCallbackList<>();
 
-        public final SparseArray<IBinder> mWindowTokens = new SparseArray<>();
-
         // Transient state.
 
         public final ArrayList<AccessibilityServiceConnection> mBoundServices = new ArrayList<>();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 547f7d3..961168a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -31,6 +31,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
+import android.view.Display;
 
 import com.android.server.accessibility.AccessibilityManagerService.UserState;
 import com.android.server.wm.WindowManagerInternal;
@@ -196,7 +197,7 @@
             return;
         }
         try {
-            serviceInterface.init(this, mId, mOverlayWindowToken);
+            serviceInterface.init(this, mId, mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
         } catch (RemoteException re) {
             Slog.w(LOG_TAG, "Error while setting connection for service: "
                     + serviceInterface, re);
@@ -237,7 +238,6 @@
         return (userState != null) ? userState.getSoftKeyboardShowMode() : 0;
     }
 
-
     @Override
     public boolean isAccessibilityButtonAvailable() {
         synchronized (mLock) {
@@ -353,12 +353,13 @@
     }
 
     @Override
-    public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
+    public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
+        final boolean isTouchableDisplay = mWindowManagerService.isTouchableDisplay(displayId);
         synchronized (mLock) {
             if (mSecurityPolicy.canPerformGestures(this)) {
                 MotionEventInjector motionEventInjector =
-                        mSystemSupport.getMotionEventInjectorLocked();
-                if (motionEventInjector != null) {
+                        mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
+                if (motionEventInjector != null && isTouchableDisplay) {
                     motionEventInjector.injectEvents(
                             gestureSteps.getList(), mServiceInterface, sequence);
                 } else {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 8415272..c129291 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -23,7 +23,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Binder;
 import android.os.Handler;
@@ -34,6 +33,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.Display;
 import android.view.IWindow;
 import android.view.WindowInfo;
 import android.view.WindowManager;
@@ -277,7 +277,7 @@
         } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) {
             return true;
         }
-        if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
+        if (!oldWindow.regionInScreen.equals(newWindow.regionInScreen)) {
             return true;
         }
         if (oldWindow.childTokens != null && newWindow.childTokens != null
@@ -312,7 +312,9 @@
                 // In some cases, onWindowsForAccessibilityChanged will be called immediately in
                 // setWindowsForAccessibilityCallback. We'll lost windows if flag is false.
                 mTrackingWindows = true;
-                mWindowManagerInternal.setWindowsForAccessibilityCallback(this);
+                // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
+                mWindowManagerInternal.setWindowsForAccessibilityCallback(Display.DEFAULT_DISPLAY,
+                        this);
             }
         }
     }
@@ -323,7 +325,9 @@
     public void stopTrackingWindows() {
         synchronized (mLock) {
             if (mTrackingWindows) {
-                mWindowManagerInternal.setWindowsForAccessibilityCallback(null);
+                // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
+                mWindowManagerInternal.setWindowsForAccessibilityCallback(Display.DEFAULT_DISPLAY,
+                        null);
                 mTrackingWindows = false;
                 clearWindowsLocked();
             }
@@ -522,7 +526,8 @@
                 }
             }
         }
-        mWindowManagerInternal.computeWindowsForAccessibility();
+        // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
+        mWindowManagerInternal.computeWindowsForAccessibility(Display.DEFAULT_DISPLAY);
         return windowId;
     }
 
@@ -755,20 +760,20 @@
         boolean windowInteractiveRegionChanged = false;
 
         final int windowCount = mWindows.size();
-        final Rect currentWindowBounds = new Rect();
+        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.getBoundsInScreen(currentWindowBounds);
-                    outRegion.set(currentWindowBounds);
+                    currentWindow.getRegionInScreen(currentWindowRegions);
+                    outRegion.set(currentWindowRegions);
                     windowInteractiveRegion = outRegion;
                     continue;
                 }
             } else if (currentWindow.getType()
                     != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) {
-                currentWindow.getBoundsInScreen(currentWindowBounds);
-                if (windowInteractiveRegion.op(currentWindowBounds, Region.Op.DIFFERENCE)) {
+                currentWindow.getRegionInScreen(currentWindowRegions);
+                if (windowInteractiveRegion.op(currentWindowRegions, Region.Op.DIFFERENCE)) {
                     windowInteractiveRegionChanged = true;
                 }
             }
@@ -1115,7 +1120,7 @@
         reportedWindow.setType(getTypeForWindowManagerWindowType(window.type));
         reportedWindow.setLayer(window.layer);
         reportedWindow.setFocused(window.focused);
-        reportedWindow.setBoundsInScreen(window.boundsInScreen);
+        reportedWindow.setRegionInScreen(window.regionInScreen);
         reportedWindow.setTitle(window.title);
         reportedWindow.setAnchorId(window.accessibilityIdOfAnchor);
         reportedWindow.setPictureInPicture(window.inPictureInPicture);
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index 285bd09..2698b72 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -27,6 +27,7 @@
 import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
 import android.util.Slog;
+import android.view.Display;
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.util.DumpUtils;
@@ -246,7 +247,8 @@
                     // another thread.
                     if (serviceInterface != null) {
                         service.linkToDeath(this, 0);
-                        serviceInterface.init(this, mId, mOverlayWindowToken);
+                        serviceInterface.init(this, mId,
+                                mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY));
                     }
                 } catch (RemoteException re) {
                     Slog.w(LOG_TAG, "Error initialized connection", re);
diff --git a/services/art-profile b/services/art-profile
index a9d5982..cbc4627 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -16071,7 +16071,7 @@
 PLcom/android/server/wm/DisplayPolicy;->offsetInputMethodWindowLw(Lcom/android/server/wm/WindowState;Lcom/android/server/wm/DisplayFrames;)V
 HSPLcom/android/server/wm/DisplayPolicy;->onConfigurationChanged()V
 PLcom/android/server/wm/DisplayPolicy;->onPowerKeyDown(Z)V
-HSPLcom/android/server/wm/DisplayPolicy;->prepareAddWindowLw(Lcom/android/server/wm/WindowState;Landroid/view/WindowManager$LayoutParams;)I
+HSPLcom/android/server/wm/DisplayPolicy;->validateAddingWindowLw(Landroid/view/WindowManager$LayoutParams;)I
 HSPLcom/android/server/wm/DisplayPolicy;->removeWindowLw(Lcom/android/server/wm/WindowState;)V
 HSPLcom/android/server/wm/DisplayPolicy;->requestTransientBars(Lcom/android/server/wm/WindowState;)V
 HSPLcom/android/server/wm/DisplayPolicy;->resetSystemUiVisibilityLw()V
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index aada967..1e1e07d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -769,6 +769,19 @@
     }
 
     /**
+     * Updates the last fill response when a dataset is shown.
+     */
+    void logDatasetShown(int sessionId, @Nullable Bundle clientState) {
+        synchronized (mLock) {
+            if (isValidEventLocked("logDatasetShown", sessionId)) {
+                mEventHistory.addEvent(
+                        new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
+                                null, null, null, null, null));
+            }
+        }
+    }
+
+    /**
      * Updates the last fill response when an autofill context is committed.
      */
     @GuardedBy("mLock")
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 988db6a..46c2a85 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2497,6 +2497,8 @@
                 mService.getServicePackageName(), mComponentName,
                 serviceLabel, serviceIcon, this, id, mCompatMode);
 
+        mService.logDatasetShown(id, mClientState);
+
         synchronized (mLock) {
             if (mUiShownTime == 0) {
                 // Log first time UI is shown.
diff --git a/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java b/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java
index e68263a..813fc8d 100644
--- a/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java
+++ b/services/autofill/java/com/android/server/autofill/ui/CustomScrollView.java
@@ -64,12 +64,13 @@
             return;
         }
 
+        mWidth = MeasureSpec.getSize(widthMeasureSpec);
         calculateDimensions();
         setMeasuredDimension(mWidth, mHeight);
     }
 
     private void calculateDimensions() {
-        if (mWidth != -1) return;
+        if (mHeight != -1) return;
 
         final TypedValue typedValue = new TypedValue();
         final Point point = new Point();
@@ -81,7 +82,6 @@
         final int childHeight = child.getMeasuredHeight();
         final int maxHeight = (int) typedValue.getFraction(point.y, point.y);
 
-        mWidth = point.x;
         mHeight = Math.min(childHeight, maxHeight);
         if (sDebug) {
             Slog.d(TAG, "calculateDimensions(): maxHeight=" + maxHeight
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 73f5cb8..e2cdddb 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -165,7 +165,13 @@
         mComponentName = componentName;
         mCompatMode = compatMode;
 
-        context = new ContextThemeWrapper(context, mThemeId);
+        context = new ContextThemeWrapper(context, mThemeId) {
+            @Override
+            public void startActivity(Intent intent) {
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                super.startActivity(intent);
+            }
+        };
         final LayoutInflater inflater = LayoutInflater.from(context);
         final View view = inflater.inflate(R.layout.autofill_save, null);
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 8df25b5..d5a7c81 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -194,6 +194,11 @@
         }
     }
 
+    boolean isAbleToServeUser(int userId) {
+        return getServiceUsers().get(UserHandle.USER_SYSTEM) != null
+                && getServiceUsers().get(userId) != null;
+    }
+
     /**
      *  Returns a lst of users currently unlocked that have a
      *  {@link UserBackupManagerService} registered.
diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java
index f62a875..088e1f9 100644
--- a/services/backup/java/com/android/server/backup/FullBackupJob.java
+++ b/services/backup/java/com/android/server/backup/FullBackupJob.java
@@ -16,6 +16,8 @@
 
 package com.android.server.backup;
 
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
 import android.app.job.JobScheduler;
@@ -37,7 +39,7 @@
     public static final int MAX_JOB_ID = 52419896;
 
     private static ComponentName sIdleService =
-            new ComponentName("android", FullBackupJob.class.getName());
+            new ComponentName(PLATFORM_PACKAGE_NAME, FullBackupJob.class.getName());
 
     @GuardedBy("mParamsForUser")
     private final SparseArray<JobParameters> mParamsForUser = new SparseArray<>();
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
index 72d81d3..ac43fc3 100644
--- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -17,6 +17,7 @@
 package com.android.server.backup;
 
 import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.app.AlarmManager;
 import android.app.job.JobInfo;
@@ -43,7 +44,7 @@
 public class KeyValueBackupJob extends JobService {
     private static final String TAG = "KeyValueBackupJob";
     private static ComponentName sKeyValueJobService =
-            new ComponentName("android", KeyValueBackupJob.class.getName());
+            new ComponentName(PLATFORM_PACKAGE_NAME, KeyValueBackupJob.class.getName());
 
     private static final String USER_ID_EXTRA_KEY = "userId";
 
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 53bbac4..f4b6645 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -202,11 +202,10 @@
         }
     }
 
-    // A user is ready for a backup if it's unlocked and is not suppressed by a device
-    // admin (device owner or profile owner).
+    // This method should not perform any I/O (e.g. do not call isBackupActivatedForUser),
+    // it's used in multiple places where I/O waits would cause system lock-ups.
     private boolean isUserReadyForBackup(int userId) {
-        return mService != null && mService.getServiceUsers().get(userId) != null
-                && isBackupActivatedForUser(userId);
+        return mService != null && mService.isAbleToServeUser(userId);
     }
 
     /**
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 18ee7a4..18c38dc 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -128,7 +128,7 @@
 
     private static final String TAG = "PFTBT";
 
-    private UserBackupManagerService backupManagerService;
+    private UserBackupManagerService mUserBackupManagerService;
     private final Object mCancelLock = new Object();
 
     ArrayList<PackageInfo> mPackages;
@@ -159,7 +159,7 @@
             @Nullable IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener,
             boolean userInitiated) {
         super(observer);
-        this.backupManagerService = backupManagerService;
+        this.mUserBackupManagerService = backupManagerService;
         mTransportClient = transportClient;
         mUpdateSchedule = updateSchedule;
         mLatch = latch;
@@ -252,16 +252,16 @@
     }
 
     private void registerTask() {
-        synchronized (backupManagerService.getCurrentOpLock()) {
+        synchronized (mUserBackupManagerService.getCurrentOpLock()) {
             Slog.d(TAG, "backupmanager pftbt token=" + Integer.toHexString(mCurrentOpToken));
-            backupManagerService.getCurrentOperations().put(
+            mUserBackupManagerService.getCurrentOperations().put(
                     mCurrentOpToken,
                     new Operation(OP_PENDING, this, OP_TYPE_BACKUP));
         }
     }
 
     public void unregisterTask() {
-        backupManagerService.removeOperation(mCurrentOpToken);
+        mUserBackupManagerService.removeOperation(mCurrentOpToken);
     }
 
     @Override
@@ -288,7 +288,7 @@
 
             mCancelAll = true;
             if (mIsDoingBackup) {
-                backupManagerService.handleCancel(mBackupRunnerOpToken, cancelAll);
+                mUserBackupManagerService.handleCancel(mBackupRunnerOpToken, cancelAll);
                 try {
                     // If we're running a backup we should be connected to a transport
                     IBackupTransport transport =
@@ -320,16 +320,17 @@
         int backupRunStatus = BackupManager.SUCCESS;
 
         try {
-            if (!backupManagerService.isEnabled() || !backupManagerService.isSetupComplete()) {
+            if (!mUserBackupManagerService.isEnabled()
+                    || !mUserBackupManagerService.isSetupComplete()) {
                 // Backups are globally disabled, so don't proceed.
                 if (DEBUG) {
-                    Slog.i(TAG, "full backup requested but enabled=" + backupManagerService
+                    Slog.i(TAG, "full backup requested but enabled=" + mUserBackupManagerService
                             .isEnabled()
-                            + " setupComplete=" + backupManagerService.isSetupComplete()
+                            + " setupComplete=" + mUserBackupManagerService.isSetupComplete()
                             + "; ignoring");
                 }
                 int monitoringEvent;
-                if (backupManagerService.isSetupComplete()) {
+                if (mUserBackupManagerService.isSetupComplete()) {
                     monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED;
                 } else {
                     monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
@@ -532,7 +533,8 @@
                 // Roll this package to the end of the backup queue if we're
                 // in a queue-driven mode (regardless of success/failure)
                 if (mUpdateSchedule) {
-                    backupManagerService.enqueueFullBackup(packageName, System.currentTimeMillis());
+                    mUserBackupManagerService.enqueueFullBackup(
+                            packageName, System.currentTimeMillis());
                 }
 
                 if (backupPackageStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
@@ -549,7 +551,8 @@
                     // from the preflight pass.  If we got as far as preflight, we now need
                     // to tear down the target process.
                     if (mBackupRunner != null) {
-                        backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
+                        mUserBackupManagerService.tearDownAgentAndKill(
+                                currentPackage.applicationInfo);
                     }
                     // ... and continue looping.
                 } else if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
@@ -561,7 +564,7 @@
                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
                                 packageName);
                     }
-                    backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
+                    mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
                     // Do nothing, clean up, and continue looping.
                 } else if (backupPackageStatus == BackupTransport.AGENT_ERROR) {
                     BackupObserverUtils
@@ -569,7 +572,7 @@
                                     BackupManager.ERROR_AGENT_FAILURE);
                     Slog.w(TAG, "Application failure for package: " + packageName);
                     EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, packageName);
-                    backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
+                    mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
                     // Do nothing, clean up, and continue looping.
                 } else if (backupPackageStatus == BackupManager.ERROR_BACKUP_CANCELLED) {
                     BackupObserverUtils
@@ -578,7 +581,7 @@
                     Slog.w(TAG, "Backup cancelled. package=" + packageName +
                             ", cancelAll=" + mCancelAll);
                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_CANCELLED, packageName);
-                    backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
+                    mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
                     // Do nothing, clean up, and continue looping.
                 } else if (backupPackageStatus != BackupTransport.TRANSPORT_OK) {
                     BackupObserverUtils
@@ -588,7 +591,7 @@
                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
                     // Abort entire backup pass.
                     backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
-                    backupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
+                    mUserBackupManagerService.tearDownAgentAndKill(currentPackage.applicationInfo);
                     return;
                 } else {
                     // Success!
@@ -596,14 +599,14 @@
                             .sendBackupOnPackageResult(mBackupObserver, packageName,
                                     BackupManager.SUCCESS);
                     EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS, packageName);
-                    backupManagerService.logBackupComplete(packageName);
+                    mUserBackupManagerService.logBackupComplete(packageName);
                 }
                 cleanUpPipes(transportPipes);
                 cleanUpPipes(enginePipes);
                 if (currentPackage.applicationInfo != null) {
                     Slog.i(TAG, "Unbinding agent in " + packageName);
                     try {
-                        backupManagerService.getActivityManager().unbindBackupAgent(
+                        mUserBackupManagerService.getActivityManager().unbindBackupAgent(
                                 currentPackage.applicationInfo);
                     } catch (RemoteException e) { /* can't happen; activity manager is local */ }
                 }
@@ -639,8 +642,8 @@
                 mJob.finishBackupPass(mUserId);
             }
 
-            synchronized (backupManagerService.getQueueLock()) {
-                backupManagerService.setRunningFullBackupTask(null);
+            synchronized (mUserBackupManagerService.getQueueLock()) {
+                mUserBackupManagerService.setRunningFullBackupTask(null);
             }
 
             mListener.onFinished("PFTBT.run()");
@@ -650,11 +653,11 @@
             // Now that we're actually done with schedule-driven work, reschedule
             // the next pass based on the new queue state.
             if (mUpdateSchedule) {
-                backupManagerService.scheduleNextFullBackupJob(backoff);
+                mUserBackupManagerService.scheduleNextFullBackupJob(backoff);
             }
 
             Slog.i(TAG, "Full data backup pass finished.");
-            backupManagerService.getWakelock().release();
+            mUserBackupManagerService.getWakelock().release();
         }
     }
 
@@ -709,13 +712,13 @@
             long fullBackupAgentTimeoutMillis =
                     mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             try {
-                backupManagerService.prepareOperationTimeout(
+                mUserBackupManagerService.prepareOperationTimeout(
                         mCurrentOpToken, fullBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT);
                 if (MORE_DEBUG) {
                     Slog.d(TAG, "Preflighting full payload of " + pkg.packageName);
                 }
                 agent.doMeasureFullBackup(mQuota, mCurrentOpToken,
-                        backupManagerService.getBackupManagerBinder(), mTransportFlags);
+                        mUserBackupManagerService.getBackupManagerBinder(), mTransportFlags);
 
                 // Now wait to get our result back.  If this backstop timeout is reached without
                 // the latch being thrown, flow will continue as though a result or "normal"
@@ -765,7 +768,7 @@
             }
             mResult.set(result);
             mLatch.countDown();
-            backupManagerService.removeOperation(mCurrentOpToken);
+            mUserBackupManagerService.removeOperation(mCurrentOpToken);
         }
 
         @Override
@@ -775,7 +778,7 @@
             }
             mResult.set(BackupTransport.AGENT_ERROR);
             mLatch.countDown();
-            backupManagerService.removeOperation(mCurrentOpToken);
+            mUserBackupManagerService.removeOperation(mCurrentOpToken);
         }
 
         @Override
@@ -812,7 +815,7 @@
             mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
             mTarget = target;
             mCurrentOpToken = currentOpToken;
-            mEphemeralToken = backupManagerService.generateRandomIntegerToken();
+            mEphemeralToken = mUserBackupManagerService.generateRandomIntegerToken();
             mPreflight = new SinglePackageBackupPreflight(
                     transportClient, quota, mEphemeralToken, transportFlags);
             mPreflightLatch = new CountDownLatch(1);
@@ -825,23 +828,32 @@
         }
 
         void registerTask() {
-            synchronized (backupManagerService.getCurrentOpLock()) {
-                backupManagerService.getCurrentOperations().put(
+            synchronized (mUserBackupManagerService.getCurrentOpLock()) {
+                mUserBackupManagerService.getCurrentOperations().put(
                         mCurrentOpToken, new Operation(OP_PENDING, this, OP_TYPE_BACKUP_WAIT));
             }
         }
 
         void unregisterTask() {
-            synchronized (backupManagerService.getCurrentOpLock()) {
-                backupManagerService.getCurrentOperations().remove(mCurrentOpToken);
+            synchronized (mUserBackupManagerService.getCurrentOpLock()) {
+                mUserBackupManagerService.getCurrentOperations().remove(mCurrentOpToken);
             }
         }
 
         @Override
         public void run() {
             FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
-            mEngine = new FullBackupEngine(backupManagerService, out, mPreflight, mTarget, false,
-                    this, mQuota, mCurrentOpToken, mTransportFlags);
+            mEngine =
+                    new FullBackupEngine(
+                            mUserBackupManagerService,
+                            out,
+                            mPreflight,
+                            mTarget,
+                            false,
+                            this,
+                            mQuota,
+                            mCurrentOpToken,
+                            mTransportFlags);
             try {
                 try {
                     if (!mIsCancelled) {
@@ -928,13 +940,13 @@
                     mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
             mIsCancelled = true;
             // Cancel tasks spun off by this task.
-            backupManagerService.handleCancel(mEphemeralToken, cancelAll);
-            backupManagerService.tearDownAgentAndKill(mTarget.applicationInfo);
+            mUserBackupManagerService.handleCancel(mEphemeralToken, cancelAll);
+            mUserBackupManagerService.tearDownAgentAndKill(mTarget.applicationInfo);
             // Free up everyone waiting on this task and its children.
             mPreflightLatch.countDown();
             mBackupLatch.countDown();
             // We are done with this operation.
-            backupManagerService.removeOperation(mCurrentOpToken);
+            mUserBackupManagerService.removeOperation(mCurrentOpToken);
         }
     }
 }
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index a45f0c0..675a6eb 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -26,6 +26,7 @@
 import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.Nullable;
 import android.app.ApplicationThreadConstants;
@@ -222,7 +223,7 @@
                 try {
                     PackageManager pm = backupManagerService.getPackageManager();
                     PackageInfo info = pm.getPackageInfoAsUser(filterSet[i], 0, mUserId);
-                    if ("android".equals(info.packageName)) {
+                    if (PLATFORM_PACKAGE_NAME.equals(info.packageName)) {
                         hasSystem = true;
                         continue;
                     }
@@ -241,7 +242,7 @@
             if (hasSystem) {
                 try {
                     mAcceptSet.add(0, backupManagerService.getPackageManager().getPackageInfoAsUser(
-                                    "android", 0, mUserId));
+                                    PLATFORM_PACKAGE_NAME, 0, mUserId));
                 } catch (NameNotFoundException e) {
                     // won't happen; we know a priori that it's valid
                 }
@@ -681,7 +682,7 @@
         // an optimization: we know there's no widget data hosted/published by that
         // package, and this way we avoid doing a spurious copy of MB-sized wallpaper
         // data following the download.
-        boolean staging = !packageName.equals("android");
+        boolean staging = !packageName.equals(PLATFORM_PACKAGE_NAME);
         ParcelFileDescriptor stage;
         File downloadFile = (staging) ? mStageName : mBackupDataName;
         boolean startedAgentRestore = false;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 9855e4e..9518196 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -13,6 +13,7 @@
     },
     srcs: [
         "java/**/*.java",
+        ":platformcompat_aidl",
         ":dumpstate_aidl",
         ":idmap2_aidl",
         ":installd_aidl",
@@ -80,3 +81,11 @@
     name: "gps_debug.conf",
     src: "java/com/android/server/location/gps_debug.conf",
 }
+
+filegroup {
+    name: "platformcompat_aidl",
+    srcs: [
+        "java/com/android/server/compat/IPlatformCompat.aidl",
+    ],
+    path: "java",
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 188d654..208b638 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1185,7 +1185,8 @@
         if (isBluetoothDisallowed) {
             return;
         }
-        if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
+        final boolean isSafeMode = mContext.getPackageManager().isSafeMode();
+        if (mEnableExternal && isBluetoothPersistedStateOnBluetooth() && !isSafeMode) {
             if (DBG) {
                 Slog.d(TAG, "Auto-enabling Bluetooth.");
             }
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
index 5c5b477..112cf08 100644
--- a/services/core/java/com/android/server/BluetoothService.java
+++ b/services/core/java/com/android/server/BluetoothService.java
@@ -18,8 +18,7 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
-
-import com.android.internal.os.RoSystemProperties;
+import android.os.UserManager;
 
 class BluetoothService extends SystemService {
     private BluetoothManagerService mBluetoothManagerService;
@@ -47,7 +46,7 @@
             publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
                     mBluetoothManagerService);
         } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY &&
-                !RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER) {
+                !UserManager.isHeadlessSystemUserMode()) {
             initialize();
         }
     }
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index ddfc3a6..a303718 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1742,6 +1742,12 @@
             return mConstants;
         }
 
+
+        /** Returns the current elapsed realtime in milliseconds. */
+        long getElapsedRealtime() {
+            return SystemClock.elapsedRealtime();
+        }
+
         LocationManager getLocationManager() {
             if (mLocationManager == null) {
                 mLocationManager = mContext.getSystemService(LocationManager.class);
@@ -2023,7 +2029,7 @@
 
     private void unregisterDeviceIdleConstraintInternal(IDeviceIdleConstraint constraint) {
         synchronized (this) {
-            // Artifically force the constraint to inactive to unblock anything waiting for it.
+            // Artificially force the constraint to inactive to unblock anything waiting for it.
             onConstraintStateChangedLocked(constraint, /* active= */ false);
 
             // Let the constraint know that we are not listening to it any more.
@@ -2746,9 +2752,18 @@
                 mState = STATE_QUICK_DOZE_DELAY;
                 // Make sure any motion sensing or locating is stopped.
                 resetIdleManagementLocked();
-                // Wait a small amount of time in case something (eg: background service from
-                // recently closed app) needs to finish running.
-                scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+                if (isUpcomingAlarmClock()) {
+                    // If there's an upcoming AlarmClock alarm, we won't go into idle, so
+                    // setting a wakeup alarm before the upcoming alarm is futile. Set the quick
+                    // doze alarm to after the upcoming AlarmClock alarm.
+                    scheduleAlarmLocked(
+                            mAlarmManager.getNextWakeFromIdleTime() - mInjector.getElapsedRealtime()
+                                    + mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+                } else {
+                    // Wait a small amount of time in case something (eg: background service from
+                    // recently closed app) needs to finish running.
+                    scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+                }
                 EventLogTags.writeDeviceIdle(mState, "no activity");
             } else if (mState == STATE_ACTIVE) {
                 mState = STATE_INACTIVE;
@@ -2758,7 +2773,16 @@
                 if (shouldUseIdleTimeoutFactorLocked()) {
                     delay = (long) (mPreIdleFactor * delay);
                 }
-                scheduleAlarmLocked(delay, false);
+                if (isUpcomingAlarmClock()) {
+                    // If there's an upcoming AlarmClock alarm, we won't go into idle, so
+                    // setting a wakeup alarm before the upcoming alarm is futile. Set the idle
+                    // alarm to after the upcoming AlarmClock alarm.
+                    scheduleAlarmLocked(
+                            mAlarmManager.getNextWakeFromIdleTime() - mInjector.getElapsedRealtime()
+                                    + delay, false);
+                } else {
+                    scheduleAlarmLocked(delay, false);
+                }
                 EventLogTags.writeDeviceIdle(mState, "no activity");
             }
         }
@@ -2906,13 +2930,21 @@
         return mState;
     }
 
+    /**
+     * Returns true if there's an upcoming AlarmClock alarm that is soon enough to prevent the
+     * device from going into idle.
+     */
+    private boolean isUpcomingAlarmClock() {
+        return mInjector.getElapsedRealtime() + mConstants.MIN_TIME_TO_ALARM
+                >= mAlarmManager.getNextWakeFromIdleTime();
+    }
+
     @VisibleForTesting
     void stepIdleStateLocked(String reason) {
         if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
         EventLogTags.writeDeviceIdleStep();
 
-        final long now = SystemClock.elapsedRealtime();
-        if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
+        if (isUpcomingAlarmClock()) {
             // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
             if (mState != STATE_ACTIVE) {
                 mActiveReason = ACTIVE_REASON_ALARM;
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 9dead16..aeb3e7f 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -41,7 +41,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -582,11 +582,9 @@
         }
 
         int numFound = 0, numArgs = searchArgs.size();
-        Time time = new Time();
         out.append("\n");
         for (EntryFile entry : mAllFiles.contents) {
-            time.set(entry.timestampMillis);
-            String date = time.format("%Y-%m-%d %H:%M:%S");
+            String date = TimeMigrationUtils.formatMillisWithFixedFormat(entry.timestampMillis);
             boolean match = true;
             for (int i = 0; i < numArgs && match; i++) {
                 String arg = searchArgs.get(i);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index b36bbaa..5089ee0 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -42,7 +42,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
 import android.content.res.Resources;
@@ -121,6 +120,7 @@
 import com.android.server.location.MockProvider;
 import com.android.server.location.PassiveProvider;
 import com.android.server.location.RemoteListenerHelper;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
@@ -282,12 +282,12 @@
 
         // Let the package manager query which are the default location
         // providers as they get certain permissions granted by default.
-        PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
-        packageManagerInternal.setLocationPackagesProvider(
+        PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
+                PermissionManagerServiceInternal.class);
+        permissionManagerInternal.setLocationPackagesProvider(
                 userId -> mContext.getResources().getStringArray(
                         com.android.internal.R.array.config_locationProviderPackageNames));
-        packageManagerInternal.setLocationExtraPackagesProvider(
+        permissionManagerInternal.setLocationExtraPackagesProvider(
                 userId -> mContext.getResources().getStringArray(
                       com.android.internal.R.array.config_locationExtraPackageNames));
 
@@ -467,7 +467,7 @@
         // the user being changed will cause a reload of all user specific settings, which causes
         // provider initialization, and propagates changes until a steady state is reached
         mCurrentUserId = UserHandle.USER_NULL;
-        onUserChangedLocked(UserHandle.USER_SYSTEM);
+        onUserChangedLocked(ActivityManager.getCurrentUser());
 
         // initialize in-memory settings values
         onBackgroundThrottleWhitelistChangedLocked();
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 80d7ac9..df5005e 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -26,7 +26,6 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.database.ContentObserver;
 import android.location.LocationManager;
 import android.net.INetworkRecommendationProvider;
@@ -54,15 +53,14 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.IntArray;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.TransferPipe;
-import com.android.internal.telephony.SmsApplication;
 import com.android.internal.util.DumpUtils;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -294,7 +292,7 @@
                     String useOpenWifiPackage = Global.getString(mContext.getContentResolver(),
                             Global.USE_OPEN_WIFI_PACKAGE);
                     if (!TextUtils.isEmpty(useOpenWifiPackage)) {
-                        LocalServices.getService(PackageManagerInternal.class)
+                        LocalServices.getService(PermissionManagerServiceInternal.class)
                                 .grantDefaultPermissionsToDefaultUseOpenWifiApp(useOpenWifiPackage,
                                         userId);
                     }
@@ -306,17 +304,14 @@
                 false /*notifyForDescendants*/,
                 mUseOpenWifiPackageObserver);
         // Set a callback for the package manager to query the use open wifi app.
-        LocalServices.getService(PackageManagerInternal.class).setUseOpenWifiAppPackagesProvider(
-                new PackageManagerInternal.PackagesProvider() {
-                    @Override
-                    public String[] getPackages(int userId) {
-                        String useOpenWifiPackage = Global.getString(mContext.getContentResolver(),
-                                Global.USE_OPEN_WIFI_PACKAGE);
-                        if (!TextUtils.isEmpty(useOpenWifiPackage)) {
-                            return new String[]{useOpenWifiPackage};
-                        }
-                        return null;
+        LocalServices.getService(PermissionManagerServiceInternal.class)
+                .setUseOpenWifiAppPackagesProvider((userId) -> {
+                    String useOpenWifiPackage = Global.getString(mContext.getContentResolver(),
+                            Global.USE_OPEN_WIFI_PACKAGE);
+                    if (!TextUtils.isEmpty(useOpenWifiPackage)) {
+                        return new String[]{useOpenWifiPackage};
                     }
+                    return null;
                 });
     }
 
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index bc7da3f..b9d7c68 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -48,7 +48,6 @@
 import android.os.ShellCommand;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings.Secure;
 import android.service.dreams.Sandman;
 import android.service.vr.IVrManager;
@@ -218,6 +217,15 @@
         }
     };
 
+    private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) {
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE,
+                    mNightMode, 0);
+            SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode));
+        }
+    };
+
     @Override
     public void onSwitchUser(int userHandle) {
         super.onSwitchUser(userHandle);
@@ -293,6 +301,9 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         context.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
+
+        context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE),
+                false, mDarkThemeObserver, 0);
     }
 
     // Records whether setup wizard has happened or not and adds an observer for this user if not.
@@ -413,11 +424,6 @@
             try {
                 synchronized (mLock) {
                     if (mNightMode != mode) {
-                        if (UserManager.get(getContext()).isPrimaryUser()) {
-                            SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME,
-                                    Integer.toString(mode));
-                        }
-
                         // Only persist setting if not in car mode
                         if (!mCarModeEnabled) {
                             Secure.putIntForUser(getContext().getContentResolver(),
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index d848796..4f54e64 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1440,6 +1440,11 @@
 
     @Override
     public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
+        UserInfo user = getUserManager().getUserInfo(userId);
+        if (user == null) {
+            Log.w(TAG, "onServiceChanged: ignore removed user " + userId);
+            return;
+        }
         validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8cd675c..268e813 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -210,7 +210,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageManagerInternal.CheckPermissionDelegate;
 import android.content.pm.PackageParser;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PathPermission;
@@ -270,6 +269,7 @@
 import android.os.WorkSource;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
+import android.permission.PermissionManagerInternal.CheckPermissionDelegate;
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfig.Properties;
 import android.provider.Settings;
@@ -347,11 +347,13 @@
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
 import com.android.server.appop.AppOpsService;
+import com.android.server.compat.CompatConfig;
 import com.android.server.contentcapture.ContentCaptureManagerInternal;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.job.JobSchedulerInternal;
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.uri.GrantUri;
 import com.android.server.uri.UriGrantsManagerInternal;
 import com.android.server.utils.PriorityDump;
@@ -391,7 +393,9 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -1561,6 +1565,7 @@
     final HiddenApiSettings mHiddenApiBlacklist;
 
     PackageManagerInternal mPackageManagerInt;
+    PermissionManagerServiceInternal mPermissionManagerInt;
 
     /**
      * Whether to force background check on all apps (for battery saver) or not.
@@ -2394,7 +2399,7 @@
         final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
         mProcessList.init(this, activeUids);
         mLowMemDetector = null;
-        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
+        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, handlerThread);
 
         mIntentFirewall = hasHandlerThread
                 ? new IntentFirewall(new IntentFirewallInterface(), mHandler) : null;
@@ -5025,6 +5030,7 @@
             bindApplicationTimeMillis = SystemClock.elapsedRealtime();
             mAtmInternal.preBindApplication(app.getWindowProcessController());
             final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
+            long[] disabledCompatChanges = CompatConfig.get().getDisabledChanges(app.info);
             if (app.isolatedEntryPoint != null) {
                 // This is an isolated process which should just call an entry point instead of
                 // being bound to an application.
@@ -5040,7 +5046,8 @@
                         new Configuration(app.getWindowProcessController().getConfiguration()),
                         app.compat, getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
-                        buildSerial, autofillOptions, contentCaptureOptions);
+                        buildSerial, autofillOptions, contentCaptureOptions,
+                        disabledCompatChanges);
             } else {
                 thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                         null, null, null, testMode,
@@ -5049,7 +5056,8 @@
                         new Configuration(app.getWindowProcessController().getConfiguration()),
                         app.compat, getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
-                        buildSerial, autofillOptions, contentCaptureOptions);
+                        buildSerial, autofillOptions, contentCaptureOptions,
+                        disabledCompatChanges);
             }
             if (profilerInfo != null) {
                 profilerInfo.closeFd();
@@ -7207,6 +7215,14 @@
         return mPackageManagerInt;
     }
 
+    private PermissionManagerServiceInternal getPermissionManagerInternalLocked() {
+        if (mPermissionManagerInt == null) {
+            mPermissionManagerInt =
+                    LocalServices.getService(PermissionManagerServiceInternal.class);
+        }
+        return mPermissionManagerInt;
+    }
+
     @Override
     public final ContentProviderHolder getContentProvider(
             IApplicationThread caller, String callingPackage, String name, int userId,
@@ -7696,6 +7712,34 @@
         return null;
     }
 
+    int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) {
+        final String name = uri.getAuthority();
+        final long ident = Binder.clearCallingIdentity();
+        ContentProviderHolder holder = null;
+        try {
+            holder = getContentProviderExternalUnchecked(name, null, callingUid,
+                    "*checkContentProviderUriPermission*", userId);
+            if (holder != null) {
+                return holder.provider.checkUriPermission(null, uri, callingUid, modeFlags);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Content provider dead retrieving " + uri, e);
+            return PackageManager.PERMISSION_DENIED;
+        } catch (Exception e) {
+            Log.w(TAG, "Exception while determining type of " + uri, e);
+            return PackageManager.PERMISSION_DENIED;
+        } finally {
+            try {
+                if (holder != null) {
+                    removeContentProviderExternalUnchecked(name, null, userId);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+        return PackageManager.PERMISSION_DENIED;
+    }
+
     private boolean canClearIdentity(int callingPid, int callingUid, int userId) {
         if (UserHandle.getUserId(callingUid) == userId) {
             return true;
@@ -15937,7 +15981,7 @@
             // Can't call out of the system process with a lock held, so post a message.
             if (instr.mUiAutomationConnection != null) {
                 mAppOpsService.setAppOpsServiceDelegate(null);
-                getPackageManagerInternalLocked().setCheckPermissionDelegate(null);
+                getPermissionManagerInternalLocked().setCheckPermissionDelegate(null);
                 mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
                         instr.mUiAutomationConnection).sendToTarget();
             }
@@ -17816,6 +17860,35 @@
         }
 
         @Override
+        public int checkContentProviderUriPermission(Uri uri, int userId,
+                int callingUid, int modeFlags) {
+            // We can find ourselves needing to check Uri permissions while
+            // already holding the WM lock, which means reaching back here for
+            // the AM lock would cause an inversion. The WM team has requested
+            // that we use the strategy below instead of shifting where Uri
+            // grants are calculated.
+
+            // Since we could also arrive here while holding the AM lock, we
+            // can't always delegate the call through the handler, and we need
+            // to delicately dance between the deadlocks.
+            if (Thread.currentThread().holdsLock(ActivityManagerService.this)) {
+                return ActivityManagerService.this.checkContentProviderUriPermission(uri,
+                        userId, callingUid, modeFlags);
+            } else {
+                final CompletableFuture<Integer> res = new CompletableFuture<>();
+                mHandler.post(() -> {
+                    res.complete(ActivityManagerService.this.checkContentProviderUriPermission(uri,
+                            userId, callingUid, modeFlags));
+                });
+                try {
+                    return res.get();
+                } catch (InterruptedException | ExecutionException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+
+        @Override
         public void onWakefulnessChanged(int wakefulness) {
             ActivityManagerService.this.onWakefulnessChanged(wakefulness);
         }
@@ -18893,7 +18966,7 @@
         synchronized (ActivityManagerService.this) {
             // If there is a delegate it should be the same instance for app ops and permissions.
             if (mAppOpsService.getAppOpsServiceDelegate()
-                    != getPackageManagerInternalLocked().getCheckPermissionDelegate()) {
+                    != getPermissionManagerInternalLocked().getCheckPermissionDelegate()) {
                 throw new IllegalStateException("Bad shell delegate state");
             }
 
@@ -18928,7 +19001,7 @@
                 final ShellDelegate shellDelegate = new ShellDelegate(
                         instr.mTargetInfo.packageName, delegateUid, permissions);
                 mAppOpsService.setAppOpsServiceDelegate(shellDelegate);
-                getPackageManagerInternalLocked().setCheckPermissionDelegate(shellDelegate);
+                getPermissionManagerInternalLocked().setCheckPermissionDelegate(shellDelegate);
                 return;
             }
         }
@@ -18942,7 +19015,7 @@
         }
         synchronized (ActivityManagerService.this) {
             mAppOpsService.setAppOpsServiceDelegate(null);
-            getPackageManagerInternalLocked().setCheckPermissionDelegate(null);
+            getPermissionManagerInternalLocked().setCheckPermissionDelegate(null);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index f7512f9..0dd7199 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -79,7 +79,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.TextUtils;
-import android.text.format.Time;
 import android.util.ArrayMap;
 import android.util.DebugUtils;
 import android.util.DisplayMetrics;
@@ -89,6 +88,7 @@
 import com.android.internal.util.HexDump;
 import com.android.internal.util.MemInfoReader;
 import com.android.internal.util.Preconditions;
+import com.android.server.compat.CompatConfig;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -97,12 +97,16 @@
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.net.URISyntaxException;
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -115,10 +119,14 @@
 
 final class ActivityManagerShellCommand extends ShellCommand {
     public static final String NO_CLASS_ERROR_CODE = "Error type 3";
+
     private static final String SHELL_PACKAGE_NAME = "com.android.shell";
 
     private static final int USER_OPERATION_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
 
+    private static final DateTimeFormatter LOG_NAME_TIME_FORMATTER =
+            DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss", Locale.ROOT);
+
     // IPC interface to activity manager -- don't need to do additional security checks.
     final IActivityManager mInterface;
     final IActivityTaskManager mTaskInterface;
@@ -290,6 +298,8 @@
                     return runNoHomeScreen(pw);
                 case "wait-for-broadcast-idle":
                     return runWaitForBroadcastIdle(pw);
+                case "compat":
+                    return runCompat(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -919,9 +929,9 @@
         String process = getNextArgRequired();
         String heapFile = getNextArg();
         if (heapFile == null) {
-            final Time t = new Time();
-            t.set(System.currentTimeMillis());
-            heapFile = "/data/local/tmp/heapdump-" + t.format("%Y%m%d-%H%M%S") + ".prof";
+            LocalDateTime localDateTime = LocalDateTime.now(Clock.systemDefaultZone());
+            String logNameTimeString = LOG_NAME_TIME_FORMATTER.format(localDateTime);
+            heapFile = "/data/local/tmp/heapdump-" + logNameTimeString + ".prof";
         }
         pw.println("File: " + heapFile);
         pw.flush();
@@ -2874,6 +2884,50 @@
         return 0;
     }
 
+    private int runCompat(PrintWriter pw) {
+        final CompatConfig config = CompatConfig.get();
+        String toggleValue = getNextArgRequired();
+        long changeId;
+        String changeIdString = getNextArgRequired();
+        try {
+            changeId = Long.parseLong(changeIdString);
+        } catch (NumberFormatException e) {
+            changeId = config.lookupChangeId(changeIdString);
+        }
+        if (changeId == -1) {
+            pw.println("Unknown or invalid change: '" + changeIdString + "'.");
+        }
+        String packageName = getNextArgRequired();
+        switch(toggleValue) {
+            case "enable":
+                if (!config.addOverride(changeId, packageName, true)) {
+                    pw.println("Warning! Change " + changeId + " is not known yet. Enabling it"
+                            + " could have no effect.");
+                }
+                pw.println("Enabled change " + changeId + " for " + packageName + ".");
+                return 0;
+            case "disable":
+                if (!config.addOverride(changeId, packageName, false)) {
+                    pw.println("Warning! Change " + changeId + " is not known yet. Disabling it"
+                            + " could have no effect.");
+                }
+                pw.println("Disabled change " + changeId + " for " + packageName + ".");
+                return 0;
+            case "reset":
+                if (config.removeOverride(changeId, packageName)) {
+                    pw.println("Reset change " + changeId + " for " + packageName
+                            + " to default value.");
+                } else {
+                    pw.println("No override exists for changeId " + changeId + ".");
+                }
+                return 0;
+            default:
+                pw.println("Invalid toggle value: '" + toggleValue + "'.");
+        }
+        return -1;
+    }
+
+
     private Resources getResources(PrintWriter pw) throws RemoteException {
         // system resources does not contain all the device configuration, construct it manually.
         Configuration config = mInterface.getConfiguration();
@@ -3181,6 +3235,8 @@
             pw.println("      without restarting any processes.");
             pw.println("  write");
             pw.println("      Write all pending state to storage.");
+            pw.println("  compat enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
+            pw.println("      Toggles a change either by id or by name for <PACKAGE_NAME>.");
             pw.println();
             Intent.printIntentArgsHelp(pw, "");
         }
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 421b755..cf0de06 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -146,4 +146,7 @@
 30065 am_on_top_resumed_lost_called (Token|1|5),(Component Name|3),(Reason|3)
 
 # An activity been add into stopping list
-30066 am_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
\ No newline at end of file
+30066 am_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
+
+# Keyguard status changed
++30067 am_set_keyguard_shown (keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(Reason|3)
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/OomAdjProfiler.java b/services/core/java/com/android/server/am/OomAdjProfiler.java
index 9846b31..7e381840 100644
--- a/services/core/java/com/android/server/am/OomAdjProfiler.java
+++ b/services/core/java/com/android/server/am/OomAdjProfiler.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.os.Message;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.SystemClock;
@@ -29,14 +30,20 @@
 import java.io.PrintWriter;
 
 public class OomAdjProfiler {
-    // Disable profiling for Q. Re-enable once b/130635979 is fixed.
-    private static final boolean PROFILING_DISABLED = true;
+    private static final int MSG_UPDATE_CPU_TIME = 42;
 
     @GuardedBy("this")
     private boolean mOnBattery;
     @GuardedBy("this")
     private boolean mScreenOff;
 
+    /** The value of {@link #mOnBattery} when the CPU time update was last scheduled. */
+    @GuardedBy("this")
+    private boolean mLastScheduledOnBattery;
+    /** The value of {@link #mScreenOff} when the CPU time update was last scheduled. */
+    @GuardedBy("this")
+    private boolean mLastScheduledScreenOff;
+
     @GuardedBy("this")
     private long mOomAdjStartTimeMs;
     @GuardedBy("this")
@@ -59,9 +66,6 @@
     final RingBuffer<CpuTimes> mSystemServerCpuTimesHist = new RingBuffer<>(CpuTimes.class, 10);
 
     void batteryPowerChanged(boolean onBattery) {
-        if (PROFILING_DISABLED) {
-            return;
-        }
         synchronized (this) {
             scheduleSystemServerCpuTimeUpdate();
             mOnBattery = onBattery;
@@ -69,9 +73,6 @@
     }
 
     void onWakefulnessChanged(int wakefulness) {
-        if (PROFILING_DISABLED) {
-            return;
-        }
         synchronized (this) {
             scheduleSystemServerCpuTimeUpdate();
             mScreenOff = wakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -79,9 +80,6 @@
     }
 
     void oomAdjStarted() {
-        if (PROFILING_DISABLED) {
-            return;
-        }
         synchronized (this) {
             mOomAdjStartTimeMs = SystemClock.currentThreadTimeMillis();
             mOomAdjStarted = true;
@@ -89,9 +87,6 @@
     }
 
     void oomAdjEnded() {
-        if (PROFILING_DISABLED) {
-            return;
-        }
         synchronized (this) {
             if (!mOomAdjStarted) {
                 return;
@@ -101,31 +96,33 @@
     }
 
     private void scheduleSystemServerCpuTimeUpdate() {
-        if (PROFILING_DISABLED) {
-            return;
-        }
         synchronized (this) {
             if (mSystemServerCpuTimeUpdateScheduled) {
                 return;
             }
+            mLastScheduledOnBattery = mOnBattery;
+            mLastScheduledScreenOff = mScreenOff;
             mSystemServerCpuTimeUpdateScheduled = true;
-            BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+            Message scheduledMessage = PooledLambda.obtainMessage(
                     OomAdjProfiler::updateSystemServerCpuTime,
-                    this, mOnBattery, mScreenOff));
+                    this, mLastScheduledOnBattery, mLastScheduledScreenOff, true);
+            scheduledMessage.setWhat(MSG_UPDATE_CPU_TIME);
+
+            BackgroundThread.getHandler().sendMessage(scheduledMessage);
         }
     }
 
-    private void updateSystemServerCpuTime(boolean onBattery, boolean screenOff) {
-        if (PROFILING_DISABLED) {
-            return;
-        }
+    private void updateSystemServerCpuTime(boolean onBattery, boolean screenOff,
+            boolean onlyIfScheduled) {
         final long cpuTimeMs = mProcessCpuTracker.getCpuTimeForPid(Process.myPid());
         synchronized (this) {
+            if (onlyIfScheduled && !mSystemServerCpuTimeUpdateScheduled) {
+                return;
+            }
             mSystemServerCpuTime.addCpuTimeMs(
                     cpuTimeMs - mLastSystemServerCpuTimeMs, onBattery, screenOff);
             mLastSystemServerCpuTimeMs = cpuTimeMs;
             mSystemServerCpuTimeUpdateScheduled = false;
-            notifyAll();
         }
     }
 
@@ -142,20 +139,14 @@
     }
 
     void dump(PrintWriter pw) {
-        if (PROFILING_DISABLED) {
-            return;
-        }
         synchronized (this) {
             if (mSystemServerCpuTimeUpdateScheduled) {
-                while (mSystemServerCpuTimeUpdateScheduled) {
-                    try {
-                        wait();
-                    } catch (InterruptedException e) {
-                        Thread.currentThread().interrupt();
-                    }
-                }
+                // Cancel the scheduled update since we're going to update it here instead.
+                BackgroundThread.getHandler().removeMessages(MSG_UPDATE_CPU_TIME);
+                // Make sure the values are attributed to the right states.
+                updateSystemServerCpuTime(mLastScheduledOnBattery, mLastScheduledScreenOff, false);
             } else {
-                updateSystemServerCpuTime(mOnBattery, mScreenOff);
+                updateSystemServerCpuTime(mOnBattery, mScreenOff, false);
             }
 
             pw.println("System server and oomAdj runtimes (ms) in recent battery sessions "
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index a2613d8..770cb3d 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -162,6 +162,21 @@
     private final ProcessList mProcessList;
 
     OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
+        this(service, processList, activeUids, createAdjusterThread());
+    }
+
+    private static ServiceThread createAdjusterThread() {
+        // The process group is usually critical to the response time of foreground app, so the
+        // setter should apply it as soon as possible.
+        final ServiceThread adjusterThread =
+                new ServiceThread(TAG, TOP_APP_PRIORITY_BOOST, false /* allowIo */);
+        adjusterThread.start();
+        Process.setThreadGroupAndCpuset(adjusterThread.getThreadId(), THREAD_GROUP_TOP_APP);
+        return adjusterThread;
+    }
+
+    OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
+            ServiceThread adjusterThread) {
         mService = service;
         mProcessList = processList;
         mActiveUids = activeUids;
@@ -170,12 +185,6 @@
         mConstants = mService.mConstants;
         mAppCompact = new AppCompactor(mService);
 
-        // The process group is usually critical to the response time of foreground app, so the
-        // setter should apply it as soon as possible.
-        final ServiceThread adjusterThread = new ServiceThread(TAG, TOP_APP_PRIORITY_BOOST,
-                false /* allowIo */);
-        adjusterThread.start();
-        Process.setThreadGroupAndCpuset(adjusterThread.getThreadId(), THREAD_GROUP_TOP_APP);
         mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> {
             final int pid = msg.arg1;
             final int group = msg.arg2;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index ffbc6b3..5465309 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1526,6 +1526,9 @@
             if ("1".equals(SystemProperties.get("debug.assert"))) {
                 runtimeFlags |= Zygote.DEBUG_ENABLE_ASSERT;
             }
+            if ("1".equals(SystemProperties.get("debug.ignoreappsignalhandler"))) {
+                runtimeFlags |= Zygote.DEBUG_IGNORE_APP_SIGNAL_HANDLER;
+            }
             if (mService.mNativeDebuggingApp != null
                     && mService.mNativeDebuggingApp.equals(app.processName)) {
                 // Enable all debug flags required by the native debugger.
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 2fe5bbe..3007016 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -198,6 +198,7 @@
         }
     };
 
+    @GuardedBy("this")
     @VisibleForTesting
     final SparseArray<UidState> mUidStates = new SparseArray<>();
 
@@ -1187,7 +1188,7 @@
         }
     }
 
-    private void pruneOp(Op op, int uid, String packageName) {
+    private void pruneOpLocked(Op op, int uid, String packageName) {
         if (!op.hasAnyTime()) {
             Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */, false /* edit */);
             if (ops != null) {
@@ -1396,7 +1397,7 @@
                     if (mode == AppOpsManager.opToDefaultMode(op.op)) {
                         // If going into the default mode, prune this op
                         // if there is nothing else interesting in it.
-                        pruneOp(op, uid, packageName);
+                        pruneOpLocked(op, uid, packageName);
                     }
                     scheduleFastWriteLocked();
                 }
@@ -2979,23 +2980,25 @@
                 out.startTag(null, "app-ops");
                 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
 
-                final int uidStateCount = mUidStates.size();
-                for (int i = 0; i < uidStateCount; i++) {
-                    UidState uidState = mUidStates.valueAt(i);
-                    if (uidState.opModes != null && uidState.opModes.size() > 0) {
-                        out.startTag(null, "uid");
-                        out.attribute(null, "n", Integer.toString(uidState.uid));
-                        SparseIntArray uidOpModes = uidState.opModes;
-                        final int opCount = uidOpModes.size();
-                        for (int j = 0; j < opCount; j++) {
-                            final int op = uidOpModes.keyAt(j);
-                            final int mode = uidOpModes.valueAt(j);
-                            out.startTag(null, "op");
-                            out.attribute(null, "n", Integer.toString(op));
-                            out.attribute(null, "m", Integer.toString(mode));
-                            out.endTag(null, "op");
+                synchronized (this) {
+                    final int uidStateCount = mUidStates.size();
+                    for (int i = 0; i < uidStateCount; i++) {
+                        UidState uidState = mUidStates.valueAt(i);
+                        if (uidState.opModes != null && uidState.opModes.size() > 0) {
+                            out.startTag(null, "uid");
+                            out.attribute(null, "n", Integer.toString(uidState.uid));
+                            SparseIntArray uidOpModes = uidState.opModes;
+                            final int opCount = uidOpModes.size();
+                            for (int j = 0; j < opCount; j++) {
+                                final int op = uidOpModes.keyAt(j);
+                                final int mode = uidOpModes.valueAt(j);
+                                out.startTag(null, "op");
+                                out.attribute(null, "n", Integer.toString(op));
+                                out.attribute(null, "m", Integer.toString(mode));
+                                out.endTag(null, "op");
+                            }
+                            out.endTag(null, "uid");
                         }
-                        out.endTag(null, "uid");
                     }
                 }
 
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 4d09c3b..cb6cf74 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -125,6 +125,8 @@
     /*package*/ void onAudioServerDied() {
         // Restore forced usage for communications and record
         synchronized (mDeviceStateLock) {
+            AudioSystem.setParameters(
+                    "BT_SCO=" + (mForcedUseForComm == AudioSystem.FORCE_BT_SCO ? "on" : "off"));
             onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied");
             onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied");
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 89e97d2..7458bee 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -54,8 +54,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
 import android.hardware.hdmi.HdmiAudioSystemClient;
 import android.hardware.hdmi.HdmiControlManager;
@@ -82,11 +80,7 @@
 import android.media.IVolumeController;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
-import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.media.MediaPlayer.OnErrorListener;
 import android.media.PlayerBase;
-import android.media.SoundPool;
 import android.media.VolumePolicy;
 import android.media.audiofx.AudioEffect;
 import android.media.audiopolicy.AudioMix;
@@ -102,7 +96,6 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -137,7 +130,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -146,15 +138,11 @@
 import com.android.server.pm.UserManagerService;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -294,19 +282,6 @@
     // protects mRingerMode
     private final Object mSettingsLock = new Object();
 
-    private SoundPool mSoundPool;
-    private final Object mSoundEffectsLock = new Object();
-    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
-
-    /* Sound effect file names  */
-    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
-    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
-
-    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
-     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
-     * uses soundpool (second column) */
-    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
-
    /** Maximum volume index values for audio streams */
     protected static int[] MAX_STREAM_VOLUME = new int[] {
         5,  // STREAM_VOICE_CALL
@@ -453,6 +428,9 @@
      * @see System#MUTE_STREAMS_AFFECTED */
     private int mMuteAffectedStreams;
 
+    @NonNull
+    private SoundEffectsHelper mSfxHelper;
+
     /**
      * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
      * mVibrateSetting is just maintained during deprecation period but vibration policy is
@@ -493,14 +471,6 @@
     private boolean mSystemReady;
     // true if Intent.ACTION_USER_SWITCHED has ever been received
     private boolean mUserSwitchedReceived;
-    // listener for SoundPool sample load completion indication
-    private SoundPoolCallback mSoundPoolCallBack;
-    // thread for SoundPool listener
-    private SoundPoolListenerThread mSoundPoolListenerThread;
-    // message looper for SoundPool listener
-    private Looper mSoundPoolLooper = null;
-    // volume applied to sound played with playSoundEffect()
-    private static int sSoundEffectVolumeDb;
     // previous volume adjustment direction received by checkForRingerModeChange()
     private int mPrevVolDirection = AudioManager.ADJUST_SAME;
     // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
@@ -642,6 +612,8 @@
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
 
+        mSfxHelper = new SoundEffectsHelper(mContext);
+
         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
 
@@ -732,9 +704,6 @@
                         MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
         }
 
-        sSoundEffectVolumeDb = context.getResources().getInteger(
-                com.android.internal.R.integer.config_soundEffectVolumeDb);
-
         createAudioSystemThread();
 
         AudioSystem.setErrorCallback(mAudioSystemCallback);
@@ -3369,104 +3338,30 @@
     //==========================================================================================
     // Sound Effects
     //==========================================================================================
+    private static final class LoadSoundEffectReply
+            implements SoundEffectsHelper.OnEffectsLoadCompleteHandler {
+        private static final int SOUND_EFFECTS_LOADING = 1;
+        private static final int SOUND_EFFECTS_LOADED = 0;
+        private static final int SOUND_EFFECTS_ERROR = -1;
+        private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
 
-    private static final String TAG_AUDIO_ASSETS = "audio_assets";
-    private static final String ATTR_VERSION = "version";
-    private static final String TAG_GROUP = "group";
-    private static final String ATTR_GROUP_NAME = "name";
-    private static final String TAG_ASSET = "asset";
-    private static final String ATTR_ASSET_ID = "id";
-    private static final String ATTR_ASSET_FILE = "file";
+        private int mStatus = SOUND_EFFECTS_LOADING;
 
-    private static final String ASSET_FILE_VERSION = "1.0";
-    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
-
-    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
-
-    class LoadSoundEffectReply {
-        public int mStatus = 1;
-    };
-
-    private void loadTouchSoundAssetDefaults() {
-        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
-        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
-            SOUND_EFFECT_FILES_MAP[i][0] = 0;
-            SOUND_EFFECT_FILES_MAP[i][1] = -1;
-        }
-    }
-
-    private void loadTouchSoundAssets() {
-        XmlResourceParser parser = null;
-
-        // only load assets once.
-        if (!SOUND_EFFECT_FILES.isEmpty()) {
-            return;
+        @Override
+        public synchronized void run(boolean success) {
+            mStatus = success ? SOUND_EFFECTS_LOADED : SOUND_EFFECTS_ERROR;
+            notify();
         }
 
-        loadTouchSoundAssetDefaults();
-
-        try {
-            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
-
-            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
-            String version = parser.getAttributeValue(null, ATTR_VERSION);
-            boolean inTouchSoundsGroup = false;
-
-            if (ASSET_FILE_VERSION.equals(version)) {
-                while (true) {
-                    XmlUtils.nextElement(parser);
-                    String element = parser.getName();
-                    if (element == null) {
-                        break;
-                    }
-                    if (element.equals(TAG_GROUP)) {
-                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
-                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
-                            inTouchSoundsGroup = true;
-                            break;
-                        }
-                    }
-                }
-                while (inTouchSoundsGroup) {
-                    XmlUtils.nextElement(parser);
-                    String element = parser.getName();
-                    if (element == null) {
-                        break;
-                    }
-                    if (element.equals(TAG_ASSET)) {
-                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
-                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
-                        int fx;
-
-                        try {
-                            Field field = AudioManager.class.getField(id);
-                            fx = field.getInt(null);
-                        } catch (Exception e) {
-                            Log.w(TAG, "Invalid touch sound ID: "+id);
-                            continue;
-                        }
-
-                        int i = SOUND_EFFECT_FILES.indexOf(file);
-                        if (i == -1) {
-                            i = SOUND_EFFECT_FILES.size();
-                            SOUND_EFFECT_FILES.add(file);
-                        }
-                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
-                    } else {
-                        break;
-                    }
+        public synchronized boolean waitForLoaded(int attempts) {
+            while ((mStatus == SOUND_EFFECTS_LOADING) && (attempts-- > 0)) {
+                try {
+                    wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
+                } catch (InterruptedException e) {
+                    Log.w(TAG, "Interrupted while waiting sound pool loaded.");
                 }
             }
-        } catch (Resources.NotFoundException e) {
-            Log.w(TAG, "audio assets file not found", e);
-        } catch (XmlPullParserException e) {
-            Log.w(TAG, "XML parser exception reading touch sound assets", e);
-        } catch (IOException e) {
-            Log.w(TAG, "I/O exception reading touch sound assets", e);
-        } finally {
-            if (parser != null) {
-                parser.close();
-            }
+            return mStatus == SOUND_EFFECTS_LOADED;
         }
     }
 
@@ -3496,20 +3391,9 @@
      * This method must be called at first when sound effects are enabled
      */
     public boolean loadSoundEffects() {
-        int attempts = 3;
         LoadSoundEffectReply reply = new LoadSoundEffectReply();
-
-        synchronized (reply) {
-            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
-            while ((reply.mStatus == 1) && (attempts-- > 0)) {
-                try {
-                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
-                } catch (InterruptedException e) {
-                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
-                }
-            }
-        }
-        return (reply.mStatus == 0);
+        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
+        return reply.waitForLoaded(3 /*attempts*/);
     }
 
     /**
@@ -3529,61 +3413,6 @@
         sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
     }
 
-    class SoundPoolListenerThread extends Thread {
-        public SoundPoolListenerThread() {
-            super("SoundPoolListenerThread");
-        }
-
-        @Override
-        public void run() {
-
-            Looper.prepare();
-            mSoundPoolLooper = Looper.myLooper();
-
-            synchronized (mSoundEffectsLock) {
-                if (mSoundPool != null) {
-                    mSoundPoolCallBack = new SoundPoolCallback();
-                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
-                }
-                mSoundEffectsLock.notify();
-            }
-            Looper.loop();
-        }
-    }
-
-    private final class SoundPoolCallback implements
-            android.media.SoundPool.OnLoadCompleteListener {
-
-        int mStatus = 1; // 1 means neither error nor last sample loaded yet
-        List<Integer> mSamples = new ArrayList<Integer>();
-
-        public int status() {
-            return mStatus;
-        }
-
-        public void setSamples(int[] samples) {
-            for (int i = 0; i < samples.length; i++) {
-                // do not wait ack for samples rejected upfront by SoundPool
-                if (samples[i] > 0) {
-                    mSamples.add(samples[i]);
-                }
-            }
-        }
-
-        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
-            synchronized (mSoundEffectsLock) {
-                int i = mSamples.indexOf(sampleId);
-                if (i >= 0) {
-                    mSamples.remove(i);
-                }
-                if ((status != 0) || mSamples. isEmpty()) {
-                    mStatus = status;
-                    mSoundEffectsLock.notify();
-                }
-            }
-        }
-    }
-
     /** @see AudioManager#reloadAudioSettings() */
     public void reloadAudioSettings() {
         readAudioSettings(false /*userSwitch*/);
@@ -5104,230 +4933,6 @@
             Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
         }
 
-        private String getSoundEffectFilePath(int effectType) {
-            String filePath = Environment.getProductDirectory() + SOUND_EFFECTS_PATH
-                    + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
-            if (!new File(filePath).isFile()) {
-                filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH
-                        + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
-            }
-            return filePath;
-        }
-
-        private boolean onLoadSoundEffects() {
-            int status;
-
-            synchronized (mSoundEffectsLock) {
-                if (!mSystemReady) {
-                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
-                    return false;
-                }
-
-                if (mSoundPool != null) {
-                    return true;
-                }
-
-                loadTouchSoundAssets();
-
-                mSoundPool = new SoundPool.Builder()
-                        .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
-                        .setAudioAttributes(new AudioAttributes.Builder()
-                            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-                            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                            .build())
-                        .build();
-                mSoundPoolCallBack = null;
-                mSoundPoolListenerThread = new SoundPoolListenerThread();
-                mSoundPoolListenerThread.start();
-                int attempts = 3;
-                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
-                    try {
-                        // Wait for mSoundPoolCallBack to be set by the other thread
-                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
-                    } catch (InterruptedException e) {
-                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
-                    }
-                }
-
-                if (mSoundPoolCallBack == null) {
-                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
-                    if (mSoundPoolLooper != null) {
-                        mSoundPoolLooper.quit();
-                        mSoundPoolLooper = null;
-                    }
-                    mSoundPoolListenerThread = null;
-                    mSoundPool.release();
-                    mSoundPool = null;
-                    return false;
-                }
-                /*
-                 * poolId table: The value -1 in this table indicates that corresponding
-                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
-                 * Once loaded, the value in poolId is the sample ID and the same
-                 * sample can be reused for another effect using the same file.
-                 */
-                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
-                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
-                    poolId[fileIdx] = -1;
-                }
-                /*
-                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
-                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
-                 * this indicates we have a valid sample loaded for this effect.
-                 */
-
-                int numSamples = 0;
-                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
-                    // Do not load sample if this effect uses the MediaPlayer
-                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
-                        continue;
-                    }
-                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
-                        String filePath = getSoundEffectFilePath(effect);
-                        int sampleId = mSoundPool.load(filePath, 0);
-                        if (sampleId <= 0) {
-                            Log.w(TAG, "Soundpool could not load file: "+filePath);
-                        } else {
-                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
-                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
-                            numSamples++;
-                        }
-                    } else {
-                        SOUND_EFFECT_FILES_MAP[effect][1] =
-                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
-                    }
-                }
-                // wait for all samples to be loaded
-                if (numSamples > 0) {
-                    mSoundPoolCallBack.setSamples(poolId);
-
-                    attempts = 3;
-                    status = 1;
-                    while ((status == 1) && (attempts-- > 0)) {
-                        try {
-                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
-                            status = mSoundPoolCallBack.status();
-                        } catch (InterruptedException e) {
-                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
-                        }
-                    }
-                } else {
-                    status = -1;
-                }
-
-                if (mSoundPoolLooper != null) {
-                    mSoundPoolLooper.quit();
-                    mSoundPoolLooper = null;
-                }
-                mSoundPoolListenerThread = null;
-                if (status != 0) {
-                    Log.w(TAG,
-                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
-                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
-                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
-                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
-                        }
-                    }
-
-                    mSoundPool.release();
-                    mSoundPool = null;
-                }
-            }
-            return (status == 0);
-        }
-
-        /**
-         *  Unloads samples from the sound pool.
-         *  This method can be called to free some memory when
-         *  sound effects are disabled.
-         */
-        private void onUnloadSoundEffects() {
-            synchronized (mSoundEffectsLock) {
-                if (mSoundPool == null) {
-                    return;
-                }
-
-                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
-                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
-                    poolId[fileIdx] = 0;
-                }
-
-                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
-                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
-                        continue;
-                    }
-                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
-                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
-                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
-                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
-                    }
-                }
-                mSoundPool.release();
-                mSoundPool = null;
-            }
-        }
-
-        private void onPlaySoundEffect(int effectType, int volume) {
-            synchronized (mSoundEffectsLock) {
-
-                onLoadSoundEffects();
-
-                if (mSoundPool == null) {
-                    return;
-                }
-                float volFloat;
-                // use default if volume is not specified by caller
-                if (volume < 0) {
-                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
-                } else {
-                    volFloat = volume / 1000.0f;
-                }
-
-                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
-                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
-                                        volFloat, volFloat, 0, 0, 1.0f);
-                } else {
-                    MediaPlayer mediaPlayer = new MediaPlayer();
-                    try {
-                        String filePath = getSoundEffectFilePath(effectType);
-                        mediaPlayer.setDataSource(filePath);
-                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
-                        mediaPlayer.prepare();
-                        mediaPlayer.setVolume(volFloat);
-                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
-                            public void onCompletion(MediaPlayer mp) {
-                                cleanupPlayer(mp);
-                            }
-                        });
-                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
-                            public boolean onError(MediaPlayer mp, int what, int extra) {
-                                cleanupPlayer(mp);
-                                return true;
-                            }
-                        });
-                        mediaPlayer.start();
-                    } catch (IOException ex) {
-                        Log.w(TAG, "MediaPlayer IOException: "+ex);
-                    } catch (IllegalArgumentException ex) {
-                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
-                    } catch (IllegalStateException ex) {
-                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
-                    }
-                }
-            }
-        }
-
-        private void cleanupPlayer(MediaPlayer mp) {
-            if (mp != null) {
-                try {
-                    mp.stop();
-                    mp.release();
-                } catch (IllegalStateException ex) {
-                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
-                }
-            }
-        }
-
         private void onPersistSafeVolumeState(int state) {
             Settings.Global.putInt(mContentResolver,
                     Settings.Global.AUDIO_SAFE_VOLUME_STATE,
@@ -5374,24 +4979,25 @@
                     break;
 
                 case MSG_UNLOAD_SOUND_EFFECTS:
-                    onUnloadSoundEffects();
+                    mSfxHelper.unloadSoundEffects();
                     break;
 
                 case MSG_LOAD_SOUND_EFFECTS:
-                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
-                    // can take several dozens of milliseconds to complete
-                    boolean loaded = onLoadSoundEffects();
-                    if (msg.obj != null) {
-                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
-                        synchronized (reply) {
-                            reply.mStatus = loaded ? 0 : -1;
-                            reply.notify();
+                {
+                    LoadSoundEffectReply reply = (LoadSoundEffectReply) msg.obj;
+                    if (mSystemReady) {
+                        mSfxHelper.loadSoundEffects(reply);
+                    } else {
+                        Log.w(TAG, "[schedule]loadSoundEffects() called before boot complete");
+                        if (reply != null) {
+                            reply.run(false);
                         }
                     }
+                }
                     break;
 
                 case MSG_PLAY_SOUND_EFFECT:
-                    onPlaySoundEffect(msg.arg1, msg.arg2);
+                    mSfxHelper.playSoundEffect(msg.arg1, msg.arg2);
                     break;
 
                 case MSG_SET_FORCE_USE:
@@ -5575,6 +5181,7 @@
 
     /**
      * @return true if there is currently a registered dynamic mixing policy that affects media
+     * and is not a render + loopback policy
      */
     /*package*/ boolean hasMediaDynamicPolicy() {
         synchronized (mAudioPolicies) {
@@ -5583,7 +5190,8 @@
             }
             final Collection<AudioPolicyProxy> appColl = mAudioPolicies.values();
             for (AudioPolicyProxy app : appColl) {
-                if (app.hasMixAffectingUsage(AudioAttributes.USAGE_MEDIA)) {
+                if (app.hasMixAffectingUsage(AudioAttributes.USAGE_MEDIA,
+                        AudioMix.ROUTE_FLAG_LOOP_BACK_RENDER)) {
                     return true;
                 }
             }
@@ -6422,6 +6030,8 @@
 
         pw.println("\nAudioDeviceBroker:");
         mDeviceBroker.dump(pw, "  ");
+        pw.println("\nSoundEffects:");
+        mSfxHelper.dump(pw, "  ");
 
         pw.println("\n");
         pw.println("\nEvent logs:");
@@ -7353,9 +6963,10 @@
             Binder.restoreCallingIdentity(identity);
         }
 
-        boolean hasMixAffectingUsage(int usage) {
+        boolean hasMixAffectingUsage(int usage, int excludedFlags) {
             for (AudioMix mix : mMixes) {
-                if (mix.isAffectingUsage(usage)) {
+                if (mix.isAffectingUsage(usage)
+                        && ((mix.getRouteFlags() & excludedFlags) != excludedFlags)) {
                     return true;
                 }
             }
diff --git a/services/core/java/com/android/server/audio/SoundEffectsHelper.java b/services/core/java/com/android/server/audio/SoundEffectsHelper.java
new file mode 100644
index 0000000..cf5bc8d
--- /dev/null
+++ b/services/core/java/com/android/server/audio/SoundEffectsHelper.java
@@ -0,0 +1,521 @@
+/*
+ * 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.audio;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.SoundPool;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.util.PrintWriterPrinter;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class for managing sound effects loading / unloading
+ * used by AudioService. As its methods are called on the message handler thread
+ * of AudioService, the actual work is offloaded to a dedicated thread.
+ * This helps keeping AudioService responsive.
+ * @hide
+ */
+class SoundEffectsHelper {
+    private static final String TAG = "AS.SfxHelper";
+
+    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
+
+    /* Sound effect file names  */
+    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
+
+    private static final int EFFECT_NOT_IN_SOUND_POOL = 0; // SoundPool sample IDs > 0
+
+    private static final int MSG_LOAD_EFFECTS = 0;
+    private static final int MSG_UNLOAD_EFFECTS = 1;
+    private static final int MSG_PLAY_EFFECT = 2;
+    private static final int MSG_LOAD_EFFECTS_TIMEOUT = 3;
+
+    interface OnEffectsLoadCompleteHandler {
+        void run(boolean success);
+    }
+
+    private final AudioEventLogger mSfxLogger = new AudioEventLogger(
+            AudioManager.NUM_SOUND_EFFECTS + 10, "Sound Effects Loading");
+
+    private final Context mContext;
+    // default attenuation applied to sound played with playSoundEffect()
+    private final int mSfxAttenuationDb;
+
+    // thread for doing all work
+    private SfxWorker mSfxWorker;
+    // thread's message handler
+    private SfxHandler mSfxHandler;
+
+    private static final class Resource {
+        final String mFileName;
+        int mSampleId;
+        boolean mLoaded;  // for effects in SoundPool
+        Resource(String fileName) {
+            mFileName = fileName;
+            mSampleId = EFFECT_NOT_IN_SOUND_POOL;
+        }
+    }
+    // All the fields below are accessed by the worker thread exclusively
+    private final List<Resource> mResources = new ArrayList<Resource>();
+    private final int[] mEffects = new int[AudioManager.NUM_SOUND_EFFECTS]; // indexes in mResources
+    private SoundPool mSoundPool;
+    private SoundPoolLoader mSoundPoolLoader;
+
+    SoundEffectsHelper(Context context) {
+        mContext = context;
+        mSfxAttenuationDb = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_soundEffectVolumeDb);
+        startWorker();
+    }
+
+    /*package*/ void loadSoundEffects(OnEffectsLoadCompleteHandler onComplete) {
+        sendMsg(MSG_LOAD_EFFECTS, 0, 0, onComplete, 0);
+    }
+
+    /**
+     *  Unloads samples from the sound pool.
+     *  This method can be called to free some memory when
+     *  sound effects are disabled.
+     */
+    /*package*/ void unloadSoundEffects() {
+        sendMsg(MSG_UNLOAD_EFFECTS, 0, 0, null, 0);
+    }
+
+    /*package*/ void playSoundEffect(int effect, int volume) {
+        sendMsg(MSG_PLAY_EFFECT, effect, volume, null, 0);
+    }
+
+    /*package*/ void dump(PrintWriter pw, String prefix) {
+        if (mSfxHandler != null) {
+            pw.println(prefix + "Message handler (watch for unhandled messages):");
+            mSfxHandler.dump(new PrintWriterPrinter(pw), "  ");
+        } else {
+            pw.println(prefix + "Message handler is null");
+        }
+        pw.println(prefix + "Default attenuation (dB): " + mSfxAttenuationDb);
+        mSfxLogger.dump(pw);
+    }
+
+    private void startWorker() {
+        mSfxWorker = new SfxWorker();
+        mSfxWorker.start();
+        synchronized (this) {
+            while (mSfxHandler == null) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                    Log.w(TAG, "Interrupted while waiting " + mSfxWorker.getName() + " to start");
+                }
+            }
+        }
+    }
+
+    private void sendMsg(int msg, int arg1, int arg2, Object obj, int delayMs) {
+        mSfxHandler.sendMessageDelayed(mSfxHandler.obtainMessage(msg, arg1, arg2, obj), delayMs);
+    }
+
+    private void logEvent(String msg) {
+        mSfxLogger.log(new AudioEventLogger.StringEvent(msg));
+    }
+
+    // All the methods below run on the worker thread
+    private void onLoadSoundEffects(OnEffectsLoadCompleteHandler onComplete) {
+        if (mSoundPoolLoader != null) {
+            // Loading is ongoing.
+            mSoundPoolLoader.addHandler(onComplete);
+            return;
+        }
+        if (mSoundPool != null) {
+            if (onComplete != null) {
+                onComplete.run(true /*success*/);
+            }
+            return;
+        }
+
+        logEvent("effects loading started");
+        mSoundPool = new SoundPool.Builder()
+                .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
+                .setAudioAttributes(new AudioAttributes.Builder()
+                        .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                        .build())
+                .build();
+        loadTouchSoundAssets();
+
+        mSoundPoolLoader = new SoundPoolLoader();
+        mSoundPoolLoader.addHandler(new OnEffectsLoadCompleteHandler() {
+            @Override
+            public void run(boolean success) {
+                mSoundPoolLoader = null;
+                if (!success) {
+                    Log.w(TAG, "onLoadSoundEffects(), Error while loading samples");
+                    onUnloadSoundEffects();
+                }
+            }
+        });
+        mSoundPoolLoader.addHandler(onComplete);
+
+        int resourcesToLoad = 0;
+        for (Resource res : mResources) {
+            String filePath = getResourceFilePath(res);
+            int sampleId = mSoundPool.load(filePath, 0);
+            if (sampleId > 0) {
+                res.mSampleId = sampleId;
+                res.mLoaded = false;
+                resourcesToLoad++;
+            } else {
+                logEvent("effect " + filePath + " rejected by SoundPool");
+                Log.w(TAG, "SoundPool could not load file: " + filePath);
+            }
+        }
+
+        if (resourcesToLoad > 0) {
+            sendMsg(MSG_LOAD_EFFECTS_TIMEOUT, 0, 0, null, SOUND_EFFECTS_LOAD_TIMEOUT_MS);
+        } else {
+            logEvent("effects loading completed, no effects to load");
+            mSoundPoolLoader.onComplete(true /*success*/);
+        }
+    }
+
+    void onUnloadSoundEffects() {
+        if (mSoundPool == null) {
+            return;
+        }
+        if (mSoundPoolLoader != null) {
+            mSoundPoolLoader.addHandler(new OnEffectsLoadCompleteHandler() {
+                @Override
+                public void run(boolean success) {
+                    onUnloadSoundEffects();
+                }
+            });
+        }
+
+        logEvent("effects unloading started");
+        for (Resource res : mResources) {
+            if (res.mSampleId != EFFECT_NOT_IN_SOUND_POOL) {
+                mSoundPool.unload(res.mSampleId);
+            }
+        }
+        mSoundPool.release();
+        mSoundPool = null;
+        logEvent("effects unloading completed");
+    }
+
+    void onPlaySoundEffect(int effect, int volume) {
+        float volFloat;
+        // use default if volume is not specified by caller
+        if (volume < 0) {
+            volFloat = (float) Math.pow(10, (float) mSfxAttenuationDb / 20);
+        } else {
+            volFloat = volume / 1000.0f;
+        }
+
+        Resource res = mResources.get(mEffects[effect]);
+        if (res.mSampleId != EFFECT_NOT_IN_SOUND_POOL && res.mLoaded) {
+            mSoundPool.play(res.mSampleId, volFloat, volFloat, 0, 0, 1.0f);
+        } else {
+            MediaPlayer mediaPlayer = new MediaPlayer();
+            try {
+                String filePath = getResourceFilePath(res);
+                mediaPlayer.setDataSource(filePath);
+                mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
+                mediaPlayer.prepare();
+                mediaPlayer.setVolume(volFloat);
+                mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
+                    public void onCompletion(MediaPlayer mp) {
+                        cleanupPlayer(mp);
+                    }
+                });
+                mediaPlayer.setOnErrorListener(new OnErrorListener() {
+                    public boolean onError(MediaPlayer mp, int what, int extra) {
+                        cleanupPlayer(mp);
+                        return true;
+                    }
+                });
+                mediaPlayer.start();
+            } catch (IOException ex) {
+                Log.w(TAG, "MediaPlayer IOException: " + ex);
+            } catch (IllegalArgumentException ex) {
+                Log.w(TAG, "MediaPlayer IllegalArgumentException: " + ex);
+            } catch (IllegalStateException ex) {
+                Log.w(TAG, "MediaPlayer IllegalStateException: " + ex);
+            }
+        }
+    }
+
+    private static void cleanupPlayer(MediaPlayer mp) {
+        if (mp != null) {
+            try {
+                mp.stop();
+                mp.release();
+            } catch (IllegalStateException ex) {
+                Log.w(TAG, "MediaPlayer IllegalStateException: " + ex);
+            }
+        }
+    }
+
+    private static final String TAG_AUDIO_ASSETS = "audio_assets";
+    private static final String ATTR_VERSION = "version";
+    private static final String TAG_GROUP = "group";
+    private static final String ATTR_GROUP_NAME = "name";
+    private static final String TAG_ASSET = "asset";
+    private static final String ATTR_ASSET_ID = "id";
+    private static final String ATTR_ASSET_FILE = "file";
+
+    private static final String ASSET_FILE_VERSION = "1.0";
+    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
+
+    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 15000;
+
+    private String getResourceFilePath(Resource res) {
+        String filePath = Environment.getProductDirectory() + SOUND_EFFECTS_PATH + res.mFileName;
+        if (!new File(filePath).isFile()) {
+            filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + res.mFileName;
+        }
+        return filePath;
+    }
+
+    private void loadTouchSoundAssetDefaults() {
+        int defaultResourceIdx = mResources.size();
+        mResources.add(new Resource("Effect_Tick.ogg"));
+        for (int i = 0; i < mEffects.length; i++) {
+            mEffects[i] = defaultResourceIdx;
+        }
+    }
+
+    private void loadTouchSoundAssets() {
+        XmlResourceParser parser = null;
+
+        // only load assets once.
+        if (!mResources.isEmpty()) {
+            return;
+        }
+
+        loadTouchSoundAssetDefaults();
+
+        try {
+            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
+
+            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
+            String version = parser.getAttributeValue(null, ATTR_VERSION);
+            boolean inTouchSoundsGroup = false;
+
+            if (ASSET_FILE_VERSION.equals(version)) {
+                while (true) {
+                    XmlUtils.nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (element.equals(TAG_GROUP)) {
+                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
+                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
+                            inTouchSoundsGroup = true;
+                            break;
+                        }
+                    }
+                }
+                while (inTouchSoundsGroup) {
+                    XmlUtils.nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (element.equals(TAG_ASSET)) {
+                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
+                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
+                        int fx;
+
+                        try {
+                            Field field = AudioManager.class.getField(id);
+                            fx = field.getInt(null);
+                        } catch (Exception e) {
+                            Log.w(TAG, "Invalid touch sound ID: " + id);
+                            continue;
+                        }
+
+                        mEffects[fx] = findOrAddResourceByFileName(file);
+                    } else {
+                        break;
+                    }
+                }
+            }
+        } catch (Resources.NotFoundException e) {
+            Log.w(TAG, "audio assets file not found", e);
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "XML parser exception reading touch sound assets", e);
+        } catch (IOException e) {
+            Log.w(TAG, "I/O exception reading touch sound assets", e);
+        } finally {
+            if (parser != null) {
+                parser.close();
+            }
+        }
+    }
+
+    private int findOrAddResourceByFileName(String fileName) {
+        for (int i = 0; i < mResources.size(); i++) {
+            if (mResources.get(i).mFileName.equals(fileName)) {
+                return i;
+            }
+        }
+        int result = mResources.size();
+        mResources.add(new Resource(fileName));
+        return result;
+    }
+
+    private Resource findResourceBySampleId(int sampleId) {
+        for (Resource res : mResources) {
+            if (res.mSampleId == sampleId) {
+                return res;
+            }
+        }
+        return null;
+    }
+
+    private class SfxWorker extends Thread {
+        SfxWorker() {
+            super("AS.SfxWorker");
+        }
+
+        @Override
+        public void run() {
+            Looper.prepare();
+            synchronized (SoundEffectsHelper.this) {
+                mSfxHandler = new SfxHandler();
+                SoundEffectsHelper.this.notify();
+            }
+            Looper.loop();
+        }
+    }
+
+    private class SfxHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_LOAD_EFFECTS:
+                    onLoadSoundEffects((OnEffectsLoadCompleteHandler) msg.obj);
+                    break;
+                case MSG_UNLOAD_EFFECTS:
+                    onUnloadSoundEffects();
+                    break;
+                case MSG_PLAY_EFFECT:
+                    onLoadSoundEffects(new OnEffectsLoadCompleteHandler() {
+                        @Override
+                        public void run(boolean success) {
+                            if (success) {
+                                onPlaySoundEffect(msg.arg1 /*effect*/, msg.arg2 /*volume*/);
+                            }
+                        }
+                    });
+                    break;
+                case MSG_LOAD_EFFECTS_TIMEOUT:
+                    if (mSoundPoolLoader != null) {
+                        mSoundPoolLoader.onTimeout();
+                    }
+                    break;
+            }
+        }
+    }
+
+    private class SoundPoolLoader implements
+            android.media.SoundPool.OnLoadCompleteListener {
+
+        private List<OnEffectsLoadCompleteHandler> mLoadCompleteHandlers =
+                new ArrayList<OnEffectsLoadCompleteHandler>();
+
+        SoundPoolLoader() {
+            // SoundPool use the current Looper when creating its message handler.
+            // Since SoundPoolLoader is created on the SfxWorker thread, SoundPool's
+            // message handler ends up running on it (it's OK to have multiple
+            // handlers on the same Looper). Thus, onLoadComplete gets executed
+            // on the worker thread.
+            mSoundPool.setOnLoadCompleteListener(this);
+        }
+
+        void addHandler(OnEffectsLoadCompleteHandler handler) {
+            if (handler != null) {
+                mLoadCompleteHandlers.add(handler);
+            }
+        }
+
+        @Override
+        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
+            if (status == 0) {
+                int remainingToLoad = 0;
+                for (Resource res : mResources) {
+                    if (res.mSampleId == sampleId && !res.mLoaded) {
+                        logEvent("effect " + res.mFileName + " loaded");
+                        res.mLoaded = true;
+                    }
+                    if (res.mSampleId != EFFECT_NOT_IN_SOUND_POOL && !res.mLoaded) {
+                        remainingToLoad++;
+                    }
+                }
+                if (remainingToLoad == 0) {
+                    onComplete(true);
+                }
+            } else {
+                Resource res = findResourceBySampleId(sampleId);
+                String filePath;
+                if (res != null) {
+                    filePath = getResourceFilePath(res);
+                } else {
+                    filePath = "with unknown sample ID " + sampleId;
+                }
+                logEvent("effect " + filePath + " loading failed, status " + status);
+                Log.w(TAG, "onLoadSoundEffects(), Error " + status + " while loading sample "
+                        + filePath);
+                onComplete(false);
+            }
+        }
+
+        void onTimeout() {
+            onComplete(false);
+        }
+
+        void onComplete(boolean success) {
+            mSoundPool.setOnLoadCompleteListener(null);
+            for (OnEffectsLoadCompleteHandler handler : mLoadCompleteHandlers) {
+                handler.run(success);
+            }
+            logEvent("effects loading " + (success ? "completed" : "failed"));
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index df6f73b..bd3cd54 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -521,8 +521,8 @@
             List<EnabledOnKeyguardCallback> callbacks = mEnabledOnKeyguardCallbacks;
             for (int i = 0; i < callbacks.size(); i++) {
                 callbacks.get(i).notify(BiometricSourceType.FACE,
-                        mFaceEnabledOnKeyguard.getOrDefault(userId,
-                                DEFAULT_KEYGUARD_ENABLED));
+                        mFaceEnabledOnKeyguard.getOrDefault(userId, DEFAULT_KEYGUARD_ENABLED),
+                        userId);
             }
         }
     }
@@ -540,9 +540,9 @@
             }
         }
 
-        void notify(BiometricSourceType sourceType, boolean enabled) {
+        void notify(BiometricSourceType sourceType, boolean enabled, int userId) {
             try {
-                mCallback.onChanged(sourceType, enabled);
+                mCallback.onChanged(sourceType, enabled, userId);
             } catch (DeadObjectException e) {
                 Slog.w(TAG, "Death while invoking notify", e);
                 mEnabledOnKeyguardCallbacks.remove(this);
@@ -796,7 +796,8 @@
             mEnabledOnKeyguardCallbacks.add(new EnabledOnKeyguardCallback(callback));
             try {
                 callback.onChanged(BiometricSourceType.FACE,
-                        mSettingObserver.getFaceEnabledOnKeyguard());
+                        mSettingObserver.getFaceEnabledOnKeyguard(),
+                        UserHandle.getCallingUserId());
             } catch (RemoteException e) {
                 Slog.w(TAG, "Remote exception", e);
             }
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 0c4f0bd..f3f9754 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -282,10 +282,10 @@
         public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
                 IBinder token, ServiceListener listener, int userId, int groupId,
                 byte[] cryptoToken, boolean restricted, String owner,
-                final int[] disabledFeatures) {
+                final int[] disabledFeatures, int timeoutSec) {
             super(context, getConstants(), daemon, halDeviceId, token, listener,
                     userId, groupId, cryptoToken, restricted, owner, getBiometricUtils(),
-                    disabledFeatures);
+                    disabledFeatures, timeoutSec);
         }
 
         @Override
@@ -497,9 +497,9 @@
         }
     }
 
-    private final class BiometricTaskStackListener extends TaskStackListener {
+    private final Runnable mOnTaskStackChangedRunnable = new Runnable() {
         @Override
-        public void onTaskStackChanged() {
+        public void run() {
             try {
                 if (!(mCurrentClient instanceof AuthenticationClient)) {
                     return;
@@ -514,8 +514,8 @@
                     final String topPackage = runningTasks.get(0).topActivity.getPackageName();
                     if (!topPackage.contentEquals(currentClient)
                             && !mCurrentClient.isAlreadyDone()) {
-                        Slog.e(getTag(), "Stopping background authentication, top: " + topPackage
-                                + " currentClient: " + currentClient);
+                        Slog.e(getTag(), "Stopping background authentication, top: "
+                                + topPackage + " currentClient: " + currentClient);
                         mCurrentClient.stop(false /* initiatedByClient */);
                     }
                 }
@@ -523,6 +523,13 @@
                 Slog.e(getTag(), "Unable to get running tasks", e);
             }
         }
+    };
+
+    private final class BiometricTaskStackListener extends TaskStackListener {
+        @Override
+        public void onTaskStackChanged() {
+            mHandler.post(mOnTaskStackChangedRunnable);
+        }
     }
 
     private final class ResetClientStateRunnable implements Runnable {
@@ -658,8 +665,12 @@
         mMetricsLogger.count(getConstants().tagHalDied(), 1);
         mHALDeathCount++;
         mCurrentUserId = UserHandle.USER_NULL;
-        handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
-                0 /*vendorCode */);
+
+        // All client lifecycle must be managed on the handler.
+        mHandler.post(() -> {
+            handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+                    0 /*vendorCode */);
+        });
 
         StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(),
                 BiometricsProtoEnums.ISSUE_HAL_DEATH);
@@ -901,8 +912,12 @@
     }
 
     protected void setActiveUserInternal(int userId) {
-        // Do not put on handler, since it should finish before returning to caller.
-        updateActiveGroup(userId, null /* clientPackage */);
+        mHandler.post(() -> {
+            if (DEBUG) {
+                Slog.d(getTag(), "setActiveUser(" + userId + ")");
+            }
+            updateActiveGroup(userId, null /* clientPackage */);
+        });
     }
 
     protected void removeInternal(RemovalClient client) {
diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
index 854528f..7ebb7c0 100644
--- a/services/core/java/com/android/server/biometrics/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -31,11 +31,11 @@
  * A class to keep track of the enrollment state for a given client.
  */
 public abstract class EnrollClient extends ClientMonitor {
-    private static final long MS_PER_SEC = 1000;
-    private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
     private final byte[] mCryptoToken;
     private final BiometricUtils mBiometricUtils;
     private final int[] mDisabledFeatures;
+    private final int mTimeoutSec;
+
     private long mEnrollmentStartTimeMs;
 
     public abstract boolean shouldVibrate();
@@ -44,12 +44,13 @@
             BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
             BiometricServiceBase.ServiceListener listener, int userId, int groupId,
             byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils,
-            final int[] disabledFeatures) {
+            final int[] disabledFeatures, int timeoutSec) {
         super(context, constants, daemon, halDeviceId, token, listener, userId, groupId, restricted,
                 owner, 0 /* cookie */);
         mBiometricUtils = utils;
         mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length);
         mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
+        mTimeoutSec = timeoutSec;
     }
 
     @Override
@@ -94,14 +95,13 @@
     @Override
     public int start() {
         mEnrollmentStartTimeMs = System.currentTimeMillis();
-        final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
         try {
             final ArrayList<Integer> disabledFeatures = new ArrayList<>();
             for (int i = 0; i < mDisabledFeatures.length; i++) {
                 disabledFeatures.add(mDisabledFeatures[i]);
             }
 
-            final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), timeout,
+            final int result = getDaemonWrapper().enroll(mCryptoToken, getGroupId(), mTimeoutSec,
                     disabledFeatures);
             if (result != 0) {
                 Slog.w(getLogTag(), "startEnroll failed, result=" + result);
diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
index 6c7cbc1..ecf3864 100644
--- a/services/core/java/com/android/server/biometrics/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
@@ -93,7 +93,7 @@
                 statsAction(),
                 statsClient(),
                 acquiredInfo,
-                0 /* vendorCode */, // Don't log vendorCode for now
+                vendorCode,
                 Utils.isDebugEnabled(context, targetUserId));
     }
 
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index a38abdc..9d51abe 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -329,6 +329,7 @@
      * Receives the incoming binder calls from FaceManager.
      */
     private final class FaceServiceWrapper extends IFaceService.Stub {
+        private static final int ENROLL_TIMEOUT_SEC = 75;
 
         /**
          * The following methods contain common code which is shared in biometrics/common.
@@ -368,7 +369,8 @@
             final boolean restricted = isRestricted();
             final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
                     mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId,
-                    0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures) {
+                    0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures,
+                    ENROLL_TIMEOUT_SEC) {
 
                 @Override
                 public int[] getAcquireIgnorelist() {
@@ -609,27 +611,32 @@
         public void resetLockout(byte[] token) {
             checkPermission(MANAGE_BIOMETRIC);
 
-            if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
-                Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
-                return;
-            }
+            mHandler.post(() -> {
+                if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
+                    Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
+                    return;
+                }
 
-            Slog.d(TAG, "Resetting lockout for user: " + mCurrentUserId);
+                Slog.d(TAG, "Resetting lockout for user: " + mCurrentUserId);
 
-            try {
-                mDaemonWrapper.resetLockout(token);
-            } catch (RemoteException e) {
-                Slog.e(getTag(), "Unable to reset lockout", e);
-            }
+                try {
+                    mDaemonWrapper.resetLockout(token);
+                } catch (RemoteException e) {
+                    Slog.e(getTag(), "Unable to reset lockout", e);
+                }
+            });
         }
 
         @Override
         public void setFeature(int userId, int feature, boolean enabled, final byte[] token,
                 IFaceServiceReceiver receiver, final String opPackageName) {
             checkPermission(MANAGE_BIOMETRIC);
-            updateActiveGroup(userId, opPackageName);
 
             mHandler.post(() -> {
+                if (DEBUG) {
+                    Slog.d(TAG, "setFeature for user(" + userId + ")");
+                }
+                updateActiveGroup(userId, opPackageName);
                 if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
                     Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature);
                     return;
@@ -660,9 +667,12 @@
         public void getFeature(int userId, int feature, IFaceServiceReceiver receiver,
                 final String opPackageName) {
             checkPermission(MANAGE_BIOMETRIC);
-            updateActiveGroup(userId, opPackageName);
 
             mHandler.post(() -> {
+                if (DEBUG) {
+                    Slog.d(TAG, "getFeature for user(" + userId + ")");
+                }
+                updateActiveGroup(userId, opPackageName);
                 // This should ideally return tri-state, but the user isn't shown settings unless
                 // they are enrolled so it's fine for now.
                 if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 28336f4..320e102 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -176,6 +176,7 @@
      * Receives the incoming binder calls from FingerprintManager.
      */
     private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+        private static final int ENROLL_TIMEOUT_SEC = 60;
 
         /**
          * The following methods contain common code which is shared in biometrics/common.
@@ -203,7 +204,8 @@
             final int groupId = userId; // default group for fingerprint enrollment
             final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
                     mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
-                    cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */) {
+                    cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */,
+                    ENROLL_TIMEOUT_SEC) {
                 @Override
                 public boolean shouldVibrate() {
                     return true;
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 9730c9a..1a1845a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -28,7 +28,6 @@
 import android.hardware.broadcastradio.V2_0.ProgramFilter;
 import android.hardware.broadcastradio.V2_0.ProgramIdentifier;
 import android.hardware.broadcastradio.V2_0.ProgramInfo;
-import android.hardware.broadcastradio.V2_0.ProgramInfoFlags;
 import android.hardware.broadcastradio.V2_0.ProgramListChunk;
 import android.hardware.broadcastradio.V2_0.Properties;
 import android.hardware.broadcastradio.V2_0.Result;
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
index b1bd395..8c93891 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
@@ -48,6 +48,10 @@
     private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mProgramInfoMap =
             new HashMap<>();
 
+    // Flag indicating whether mProgramInfoMap is considered complete based upon the received
+    // updates.
+    private boolean mComplete = true;
+
     // Optional filter used in filterAndUpdateFrom(). Usually this field is null for a HAL-side
     // cache and non-null for an AIDL-side cache.
     private final ProgramList.Filter mFilter;
@@ -58,9 +62,10 @@
 
     // Constructor for testing.
     @VisibleForTesting
-    ProgramInfoCache(@Nullable ProgramList.Filter filter,
+    ProgramInfoCache(@Nullable ProgramList.Filter filter, boolean complete,
             RadioManager.ProgramInfo... programInfos) {
         mFilter = filter;
+        mComplete = complete;
         for (RadioManager.ProgramInfo programInfo : programInfos) {
             mProgramInfoMap.put(programInfo.getSelector().getPrimaryId(), programInfo);
         }
@@ -77,15 +82,23 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("ProgramInfoCache(");
+        StringBuilder sb = new StringBuilder("ProgramInfoCache(mComplete = ");
+        sb.append(mComplete);
+        sb.append(", mFilter = ");
+        sb.append(mFilter);
+        sb.append(", mProgramInfoMap = [");
         mProgramInfoMap.forEach((id, programInfo) -> {
             sb.append("\n");
             sb.append(programInfo.toString());
         });
-        sb.append(")");
+        sb.append("]");
         return sb.toString();
     }
 
+    public boolean isComplete() {
+        return mComplete;
+    }
+
     public @Nullable ProgramList.Filter getFilter() {
         return mFilter;
     }
@@ -102,6 +115,7 @@
         for (android.hardware.broadcastradio.V2_0.ProgramIdentifier halProgramId : chunk.removed) {
             mProgramInfoMap.remove(Convert.programIdentifierFromHal(halProgramId));
         }
+        mComplete = chunk.complete;
     }
 
     @NonNull List<ProgramList.Chunk> filterAndUpdateFrom(@NonNull ProgramInfoCache other,
@@ -122,26 +136,18 @@
             purge = true;
         }
 
-        Set<Integer> idTypes = mFilter != null ? mFilter.getIdentifierTypes() : null;
-        Set<ProgramSelector.Identifier> ids = mFilter != null ? mFilter.getIdentifiers() : null;
-        boolean includeCategories = mFilter != null ? mFilter.areCategoriesIncluded() : true;
-        boolean includeModifications = mFilter != null ? !mFilter.areModificationsExcluded() : true;
-
         Set<RadioManager.ProgramInfo> modified = new HashSet<>();
         Set<ProgramSelector.Identifier> removed = new HashSet<>(mProgramInfoMap.keySet());
         for (Map.Entry<ProgramSelector.Identifier, RadioManager.ProgramInfo> entry
                 : other.mProgramInfoMap.entrySet()) {
             ProgramSelector.Identifier id = entry.getKey();
-            if ((idTypes != null && !idTypes.isEmpty() && !idTypes.contains(id.getType()))
-                    || (ids != null && !ids.isEmpty() && !ids.contains(id))
-                    || (!includeCategories && id.isCategoryType())) {
+            if (!passesFilter(id)) {
                 continue;
             }
-
             removed.remove(id);
-            RadioManager.ProgramInfo oldInfo = mProgramInfoMap.get(id);
+
             RadioManager.ProgramInfo newInfo = entry.getValue();
-            if (oldInfo != null && (!includeModifications || oldInfo.equals(newInfo))) {
+            if (!shouldIncludeInModified(newInfo)) {
                 continue;
             }
             mProgramInfoMap.put(id, newInfo);
@@ -150,14 +156,81 @@
         for (ProgramSelector.Identifier rem : removed) {
             mProgramInfoMap.remove(rem);
         }
-        return buildChunks(purge, modified, maxNumModifiedPerChunk, removed, maxNumRemovedPerChunk);
+        mComplete = other.mComplete;
+        return buildChunks(purge, mComplete, modified, maxNumModifiedPerChunk, removed,
+                maxNumRemovedPerChunk);
+    }
+
+    @Nullable List<ProgramList.Chunk> filterAndApplyChunk(@NonNull ProgramList.Chunk chunk) {
+        return filterAndApplyChunkInternal(chunk, MAX_NUM_MODIFIED_PER_CHUNK,
+                MAX_NUM_REMOVED_PER_CHUNK);
+    }
+
+    @VisibleForTesting
+    @Nullable List<ProgramList.Chunk> filterAndApplyChunkInternal(@NonNull ProgramList.Chunk chunk,
+            int maxNumModifiedPerChunk, int maxNumRemovedPerChunk) {
+        if (chunk.isPurge()) {
+            mProgramInfoMap.clear();
+        }
+
+        Set<RadioManager.ProgramInfo> modified = new HashSet<>();
+        Set<ProgramSelector.Identifier> removed = new HashSet<>();
+        for (RadioManager.ProgramInfo info : chunk.getModified()) {
+            ProgramSelector.Identifier id = info.getSelector().getPrimaryId();
+            if (!passesFilter(id) || !shouldIncludeInModified(info)) {
+                continue;
+            }
+            mProgramInfoMap.put(id, info);
+            modified.add(info);
+        }
+        for (ProgramSelector.Identifier id : chunk.getRemoved()) {
+            if (mProgramInfoMap.containsKey(id)) {
+                mProgramInfoMap.remove(id);
+                removed.add(id);
+            }
+        }
+        if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.isComplete()) {
+            return null;
+        }
+        mComplete = chunk.isComplete();
+        return buildChunks(chunk.isPurge(), mComplete, modified, maxNumModifiedPerChunk, removed,
+                maxNumRemovedPerChunk);
+    }
+
+    private boolean passesFilter(ProgramSelector.Identifier id) {
+        if (mFilter == null) {
+            return true;
+        }
+        if (!mFilter.getIdentifierTypes().isEmpty()
+                && !mFilter.getIdentifierTypes().contains(id.getType())) {
+            return false;
+        }
+        if (!mFilter.getIdentifiers().isEmpty() && !mFilter.getIdentifiers().contains(id)) {
+            return false;
+        }
+        if (!mFilter.areCategoriesIncluded() && id.isCategoryType()) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean shouldIncludeInModified(RadioManager.ProgramInfo newInfo) {
+        RadioManager.ProgramInfo oldInfo = mProgramInfoMap.get(
+                newInfo.getSelector().getPrimaryId());
+        if (oldInfo == null) {
+            return true;
+        }
+        if (mFilter != null && mFilter.areModificationsExcluded()) {
+            return false;
+        }
+        return !oldInfo.equals(newInfo);
     }
 
     private static int roundUpFraction(int numerator, int denominator) {
         return (numerator / denominator) + (numerator % denominator > 0 ? 1 : 0);
     }
 
-    private @NonNull List<ProgramList.Chunk> buildChunks(boolean purge,
+    private static @NonNull List<ProgramList.Chunk> buildChunks(boolean purge, boolean complete,
             @Nullable Collection<RadioManager.ProgramInfo> modified, int maxNumModifiedPerChunk,
             @Nullable Collection<ProgramSelector.Identifier> removed, int maxNumRemovedPerChunk) {
         // Communication protocol requires that if purge is set, removed is empty.
@@ -205,8 +278,8 @@
                     removedChunk.add(removedIter.next());
                 }
             }
-            chunks.add(new ProgramList.Chunk(purge && i == 0, i == numChunks - 1, modifiedChunk,
-                      removedChunk));
+            chunks.add(new ProgramList.Chunk(purge && i == 0, complete && (i == numChunks - 1),
+                      modifiedChunk, removedChunk));
         }
         return chunks;
     }
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index acb0207..53890a4 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -40,6 +40,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -64,7 +65,13 @@
     private Boolean mAntennaConnected = null;
 
     @GuardedBy("mLock")
-    private RadioManager.ProgramInfo mProgramInfo = null;
+    private RadioManager.ProgramInfo mCurrentProgramInfo = null;
+
+    @GuardedBy("mLock")
+    private final ProgramInfoCache mProgramInfoCache = new ProgramInfoCache(null);
+
+    @GuardedBy("mLock")
+    private android.hardware.radio.ProgramList.Filter mUnionOfAidlProgramFilters = null;
 
     // Callback registered with the HAL to relay callbacks to AIDL clients.
     private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() {
@@ -78,17 +85,22 @@
         public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
             RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo);
             synchronized (mLock) {
-                mProgramInfo = programInfo;
+                mCurrentProgramInfo = programInfo;
                 fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo));
             }
         }
 
         @Override
         public void onProgramListUpdated(ProgramListChunk programListChunk) {
-            // TODO: Cache per-AIDL client filters, send union of filters to HAL, use filters to fan
-            // back out to clients.
-            fanoutAidlCallback(cb -> cb.onProgramListUpdated(Convert.programListChunkFromHal(
-                    programListChunk)));
+            synchronized (mLock) {
+                android.hardware.radio.ProgramList.Chunk chunk =
+                        Convert.programListChunkFromHal(programListChunk);
+                mProgramInfoCache.filterAndApplyChunk(chunk);
+
+                for (TunerSession tunerSession : mAidlTunerSessions) {
+                    tunerSession.onMergedProgramListUpdateFromHal(chunk);
+                }
+            }
         }
 
         @Override
@@ -109,8 +121,9 @@
     @GuardedBy("mLock")
     private final Set<TunerSession> mAidlTunerSessions = new HashSet<>();
 
-    private RadioModule(@NonNull IBroadcastRadio service,
-            @NonNull RadioManager.ModuleProperties properties) throws RemoteException {
+    @VisibleForTesting
+    RadioModule(@NonNull IBroadcastRadio service,
+            @NonNull RadioManager.ModuleProperties properties) {
         mProperties = Objects.requireNonNull(properties);
         mService = Objects.requireNonNull(service);
     }
@@ -163,8 +176,8 @@
             if (mAntennaConnected != null) {
                 userCb.onAntennaState(mAntennaConnected);
             }
-            if (mProgramInfo != null) {
-                userCb.onCurrentProgramInfoChanged(mProgramInfo);
+            if (mCurrentProgramInfo != null) {
+                userCb.onCurrentProgramInfoChanged(mCurrentProgramInfo);
             }
 
             return tunerSession;
@@ -186,18 +199,114 @@
         }
     }
 
+    private @Nullable android.hardware.radio.ProgramList.Filter
+            buildUnionOfTunerSessionFiltersLocked() {
+        Set<Integer> idTypes = null;
+        Set<android.hardware.radio.ProgramSelector.Identifier> ids = null;
+        boolean includeCategories = false;
+        boolean excludeModifications = true;
+
+        for (TunerSession tunerSession : mAidlTunerSessions) {
+            android.hardware.radio.ProgramList.Filter filter =
+                    tunerSession.getProgramListFilter();
+            if (filter == null) {
+                continue;
+            }
+
+            if (idTypes == null) {
+                idTypes = new HashSet<>(filter.getIdentifierTypes());
+                ids = new HashSet<>(filter.getIdentifiers());
+                includeCategories = filter.areCategoriesIncluded();
+                excludeModifications = filter.areModificationsExcluded();
+                continue;
+            }
+            if (!idTypes.isEmpty()) {
+                if (filter.getIdentifierTypes().isEmpty()) {
+                    idTypes.clear();
+                } else {
+                    idTypes.addAll(filter.getIdentifierTypes());
+                }
+            }
+
+            if (!ids.isEmpty()) {
+                if (filter.getIdentifiers().isEmpty()) {
+                    ids.clear();
+                } else {
+                    ids.addAll(filter.getIdentifiers());
+                }
+            }
+
+            includeCategories |= filter.areCategoriesIncluded();
+            excludeModifications &= filter.areModificationsExcluded();
+        }
+
+        return idTypes == null ? null : new android.hardware.radio.ProgramList.Filter(idTypes, ids,
+                includeCategories, excludeModifications);
+    }
+
+    void onTunerSessionProgramListFilterChanged(@Nullable TunerSession session) {
+        synchronized (mLock) {
+            onTunerSessionProgramListFilterChangedLocked(session);
+        }
+    }
+
+    private void onTunerSessionProgramListFilterChangedLocked(@Nullable TunerSession session) {
+        android.hardware.radio.ProgramList.Filter newFilter =
+                buildUnionOfTunerSessionFiltersLocked();
+        if (newFilter == null) {
+            // If there are no AIDL clients remaining, we can stop updates from the HAL as well.
+            if (mUnionOfAidlProgramFilters == null) {
+                return;
+            }
+            mUnionOfAidlProgramFilters = null;
+            try {
+                mHalTunerSession.stopProgramListUpdates();
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "mHalTunerSession.stopProgramListUpdates() failed: ", ex);
+            }
+            return;
+        }
+
+        // If the HAL filter doesn't change, we can immediately send an update to the AIDL
+        // client.
+        if (newFilter.equals(mUnionOfAidlProgramFilters)) {
+            if (session != null) {
+                session.updateProgramInfoFromHalCache(mProgramInfoCache);
+            }
+            return;
+        }
+
+        // Otherwise, update the HAL's filter, and AIDL clients will be updated when
+        // mHalTunerCallback.onProgramListUpdated() is called.
+        mUnionOfAidlProgramFilters = newFilter;
+        try {
+            int halResult = mHalTunerSession.startProgramListUpdates(Convert.programFilterToHal(
+                    newFilter));
+            Convert.throwOnError("startProgramListUpdates", halResult);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "mHalTunerSession.startProgramListUpdates() failed: ", ex);
+        }
+    }
+
     void onTunerSessionClosed(TunerSession tunerSession) {
         synchronized (mLock) {
+            onTunerSessionsClosedLocked(tunerSession);
+        }
+    }
+
+    private void onTunerSessionsClosedLocked(TunerSession... tunerSessions) {
+        for (TunerSession tunerSession : tunerSessions) {
             mAidlTunerSessions.remove(tunerSession);
-            if (mAidlTunerSessions.isEmpty() && mHalTunerSession != null) {
-                Slog.v(TAG, "closing HAL tuner session");
-                try {
-                    mHalTunerSession.close();
-                } catch (RemoteException ex) {
-                    Slog.e(TAG, "mHalTunerSession.close() failed: ", ex);
-                }
-                mHalTunerSession = null;
+        }
+        onTunerSessionProgramListFilterChanged(null);
+        if (mAidlTunerSessions.isEmpty() && mHalTunerSession != null) {
+            Slog.v(TAG, "closing HAL tuner session");
+            try {
+                mHalTunerSession.close();
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "mHalTunerSession.close() failed: ", ex);
             }
+            mHalTunerSession = null;
         }
     }
 
@@ -213,18 +322,25 @@
     }
 
     private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
+        List<TunerSession> deadSessions = null;
         for (TunerSession tunerSession : mAidlTunerSessions) {
             try {
                 runnable.run(tunerSession.mCallback);
             } catch (DeadObjectException ex) {
-                // The other side died without calling close(), so just purge it from our
-                // records.
+                // The other side died without calling close(), so just purge it from our records.
                 Slog.e(TAG, "Removing dead TunerSession");
-                mAidlTunerSessions.remove(tunerSession);
+                if (deadSessions == null) {
+                    deadSessions = new ArrayList<>();
+                }
+                deadSessions.add(tunerSession);
             } catch (RemoteException ex) {
                 Slog.e(TAG, "Failed to invoke ITunerCallback: ", ex);
             }
         }
+        if (deadSessions != null) {
+            onTunerSessionsClosedLocked(deadSessions.toArray(
+                    new TunerSession[deadSessions.size()]));
+        }
     }
 
     public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 008fea5..764fca9 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -46,6 +46,7 @@
     final android.hardware.radio.ITunerCallback mCallback;
     private boolean mIsClosed = false;
     private boolean mIsMuted = false;
+    private ProgramInfoCache mProgramInfoCache = null;
 
     // necessary only for older APIs compatibility
     private RadioManager.BandConfig mDummyConfig = null;
@@ -187,8 +188,51 @@
     public void startProgramListUpdates(ProgramList.Filter filter) throws RemoteException {
         synchronized (mLock) {
             checkNotClosedLocked();
-            int halResult = mHwSession.startProgramListUpdates(Convert.programFilterToHal(filter));
-            Convert.throwOnError("startProgramListUpdates", halResult);
+            mProgramInfoCache = new ProgramInfoCache(filter);
+        }
+        // Note: RadioModule.onTunerSessionProgramListFilterChanged() must be called without mLock
+        // held since it can call getProgramListFilter() and onHalProgramInfoUpdated().
+        mModule.onTunerSessionProgramListFilterChanged(this);
+    }
+
+    ProgramList.Filter getProgramListFilter() {
+        synchronized (mLock) {
+            return mProgramInfoCache == null ? null : mProgramInfoCache.getFilter();
+        }
+    }
+
+    void onMergedProgramListUpdateFromHal(ProgramList.Chunk mergedChunk) {
+        List<ProgramList.Chunk> clientUpdateChunks = null;
+        synchronized (mLock) {
+            if (mProgramInfoCache == null) {
+                return;
+            }
+            clientUpdateChunks = mProgramInfoCache.filterAndApplyChunk(mergedChunk);
+        }
+        dispatchClientUpdateChunks(clientUpdateChunks);
+    }
+
+    void updateProgramInfoFromHalCache(ProgramInfoCache halCache) {
+        List<ProgramList.Chunk> clientUpdateChunks = null;
+        synchronized (mLock) {
+            if (mProgramInfoCache == null) {
+                return;
+            }
+            clientUpdateChunks = mProgramInfoCache.filterAndUpdateFrom(halCache, true);
+        }
+        dispatchClientUpdateChunks(clientUpdateChunks);
+    }
+
+    private void dispatchClientUpdateChunks(@Nullable List<ProgramList.Chunk> chunks) {
+        if (chunks == null) {
+            return;
+        }
+        for (ProgramList.Chunk chunk : chunks) {
+            try {
+                mCallback.onProgramListUpdated(chunk);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "mCallback.onProgramListUpdated() failed: ", ex);
+            }
         }
     }
 
@@ -196,8 +240,11 @@
     public void stopProgramListUpdates() throws RemoteException {
         synchronized (mLock) {
             checkNotClosedLocked();
-            mHwSession.stopProgramListUpdates();
+            mProgramInfoCache = null;
         }
+        // Note: RadioModule.onTunerSessionProgramListFilterChanged() must be called without mLock
+        // held since it can call getProgramListFilter() and onHalProgramInfoUpdated().
+        mModule.onTunerSessionProgramListFilterChanged(this);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index bb3b9be..2a866f3 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -106,6 +106,12 @@
      * @return {@code true} if the change should be enabled for the package.
      */
     boolean isEnabled(ApplicationInfo app) {
+        if (app.isSystemApp()) {
+            // All changes are enabled for system apps, and we do not support overrides.
+            // Compatibility issues for system apps should be addressed in the app itself when
+            // the compatibility change is made.
+            return true;
+        }
         if (mPackageOverrides != null && mPackageOverrides.containsKey(app.packageName)) {
             return mPackageOverrides.get(app.packageName);
         }
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index fea5d83..c59b065 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -24,6 +24,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.PrintWriter;
 /**
  * This class maintains state relating to platform compatibility changes.
  *
@@ -128,20 +129,24 @@
      * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
      *
      * @param changeId The ID of the change to be overridden. Note, this call will succeed even if
-     *                 this change is not known; it will only have any affect if any code in the
+     *                 this change is not known; it will only have any effect if any code in the
      *                 platform is gated on the ID given.
      * @param packageName The app package name to override the change for.
      * @param enabled If the change should be enabled or disabled.
+     * @return {@code true} if the change existed before adding the override.
      */
-    public void addOverride(long changeId, String packageName, boolean enabled) {
+    public boolean addOverride(long changeId, String packageName, boolean enabled) {
+        boolean alreadyKnown = true;
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
             if (c == null) {
+                alreadyKnown = false;
                 c = new CompatChange(changeId);
                 addChange(c);
             }
             c.addPackageOverride(packageName, enabled);
         }
+        return alreadyKnown;
     }
 
     /**
@@ -151,14 +156,36 @@
      *
      * @param changeId The ID of the change that was overridden.
      * @param packageName The app package name that was overridden.
+     * @return {@code true} if an override existed;
      */
-    public void removeOverride(long changeId, String packageName) {
+    public boolean removeOverride(long changeId, String packageName) {
+        boolean overrideExists = false;
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
             if (c != null) {
+                overrideExists = true;
                 c.removePackageOverride(packageName);
             }
         }
+        return overrideExists;
+    }
+
+    /**
+    * Dumps the current list of compatibility config information.
+    *
+    * @param pw The {@link PrintWriter} instance to which the information will be dumped.
+    */
+    public void dumpConfig(PrintWriter pw) {
+        synchronized (mChanges) {
+            if (mChanges.size() == 0) {
+                pw.println("No compat overrides.");
+                return;
+            }
+            for (int i = 0; i < mChanges.size(); ++i) {
+                CompatChange c = mChanges.valueAt(i);
+                pw.println(c.toString());
+            }
+        }
     }
 
 }
diff --git a/services/core/java/com/android/server/compat/IPlatformCompat.aidl b/services/core/java/com/android/server/compat/IPlatformCompat.aidl
new file mode 100644
index 0000000..8ab08f9
--- /dev/null
+++ b/services/core/java/com/android/server/compat/IPlatformCompat.aidl
@@ -0,0 +1,57 @@
+/*
+ * 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.compat;
+
+import android.content.pm.ApplicationInfo;
+
+/**
+ * System private API for talking with the PlatformCompat service.
+ * {@hide}
+ */
+interface IPlatformCompat
+{
+
+    /**
+     * Reports that a compatibility change is affecting an app process now.
+     *
+     * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
+     * you do not need to call this API directly. The change will be reported for you in the case
+     * that {@link #isChangeEnabled(long, ApplicationInfo)} returns {@code true}.
+     *
+     * @param changeId The ID of the compatibility change taking effect.
+     * @param appInfo Representing the affected app.
+     */
+    void reportChange(long changeId, in ApplicationInfo appInfo);
+
+    /**
+     * Query if a given compatibility change is enabled for an app process. This method should
+     * be called when implementing functionality on behalf of the affected app.
+     *
+     * <p>If this method returns {@code true}, the calling code should implement the compatibility
+     * change, resulting in differing behaviour compared to earlier releases. If this method returns
+     * {@code false}, the calling code should behave as it did in earlier releases.
+     *
+     * <p>When this method returns {@code true}, it will also report the change as
+     * {@link #reportChange(long, ApplicationInfo)} would, so there is no need to call that method
+     * directly.
+     *
+     * @param changeId The ID of the compatibility change in question.
+     * @param appInfo Representing the app in question.
+     * @return {@code true} if the change is enabled for the current app.
+     */
+    boolean isChangeEnabled(long changeId, in ApplicationInfo appInfo);
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 456d15e..3eea194 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -16,52 +16,46 @@
 
 package com.android.server.compat;
 
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.util.Slog;
 
+import com.android.internal.util.DumpUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * System server internal API for gating and reporting compatibility changes.
  */
-public class PlatformCompat {
+public class PlatformCompat extends IPlatformCompat.Stub {
 
     private static final String TAG = "Compatibility";
 
-    /**
-     * Reports that a compatibility change is affecting an app process now.
-     *
-     * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
-     * you do not need to call this API directly. The change will be reported for you in the case
-     * that {@link #isChangeEnabled(long, ApplicationInfo)} returns {@code true}.
-     *
-     * @param changeId The ID of the compatibility change taking effect.
-     * @param appInfo Representing the affected app.
-     */
-    public static void reportChange(long changeId, ApplicationInfo appInfo) {
+    private final Context mContext;
+
+    public PlatformCompat(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void reportChange(long changeId, ApplicationInfo appInfo) {
         Slog.d(TAG, "Compat change reported: " + changeId + "; UID " + appInfo.uid);
         // TODO log via StatsLog
     }
 
-    /**
-     * Query if a given compatibility change is enabled for an app process. This method should
-     * be called when implementing functionality on behalf of the affected app.
-     *
-     * <p>If this method returns {@code true}, the calling code should implement the compatibility
-     * change, resulting in differing behaviour compared to earlier releases. If this method returns
-     * {@code false}, the calling code should behave as it did in earlier releases.
-     *
-     * <p>When this method returns {@code true}, it will also report the change as
-     * {@link #reportChange(long, ApplicationInfo)} would, so there is no need to call that method
-     * directly.
-     *
-     * @param changeId The ID of the compatibility change in question.
-     * @param appInfo Representing the app in question.
-     * @return {@code true} if the change is enabled for the current app.
-     */
-    public static boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
+    @Override
+    public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
         if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
             reportChange(changeId, appInfo);
             return true;
         }
         return false;
     }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
+        CompatConfig.get().dumpConfig(pw);
+    }
 }
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 7824a0a..3e1817b 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -40,7 +40,6 @@
 import android.content.SyncRequest;
 import android.content.SyncStatusInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.content.pm.ProviderInfo;
 import android.database.IContentObserver;
 import android.database.sqlite.SQLiteException;
@@ -71,6 +70,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -280,15 +280,11 @@
 
         // Let the package manager query for the sync adapters for a given authority
         // as we grant default permissions to sync adapters for specific authorities.
-        PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
-        packageManagerInternal.setSyncAdapterPackagesprovider(
-                new PackageManagerInternal.SyncAdapterPackagesProvider() {
-                    @Override
-                    public String[] getPackages(String authority, int userId) {
-                        return getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
-                    }
-                });
+        final PermissionManagerServiceInternal permissionManagerInternal =
+                LocalServices.getService(PermissionManagerServiceInternal.class);
+        permissionManagerInternal.setSyncAdapterPackagesProvider((authority, userId) -> {
+            return getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
+        });
 
         final IntentFilter packageFilter = new IntentFilter();
         packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 64a05c9..f6c49ed 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -86,7 +86,7 @@
 import android.os.UserManager;
 import android.os.WorkSource;
 import android.provider.Settings;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
@@ -1993,9 +1993,7 @@
         if (time == 0) {
             return "N/A";
         }
-        Time tobj = new Time();
-        tobj.set(time);
-        return tobj.format("%Y-%m-%d %H:%M:%S");
+        return TimeMigrationUtils.formatMillisWithFixedFormat(time);
     }
 
     private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> {
@@ -2561,9 +2559,7 @@
                     accountKey = "Unknown";
                 }
                 final long elapsedTime = item.elapsedTime;
-                final Time time = new Time();
                 final long eventTime = item.eventTime;
-                time.set(eventTime);
 
                 final String key = authorityName + "/" + accountKey;
                 final Long lastEventTime = lastTimeMap.get(key);
@@ -2628,9 +2624,7 @@
                     authorityName = "Unknown";
                     accountKey = "Unknown";
                 }
-                final Time time = new Time();
                 final long eventTime = item.eventTime;
-                time.set(eventTime);
 
                 pw.printf("  #%-3d: %s %8s ",
                         i + 1,
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 99341d1..4f33ebb0 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -303,6 +303,8 @@
     private final Spline mMinimumBrightnessSpline;
     private final ColorSpace mWideColorSpace;
 
+    private SensorManager mSensorManager;
+
     public DisplayManagerService(Context context) {
         this(context, new Injector());
     }
@@ -430,7 +432,7 @@
         }
 
         mDisplayModeDirector.setListener(new AllowedDisplayModeObserver());
-        mDisplayModeDirector.start();
+        mDisplayModeDirector.start(mSensorManager);
 
         mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
     }
@@ -2358,6 +2360,7 @@
                 };
                 mDisplayPowerController = new DisplayPowerController(
                         mContext, callbacks, handler, sensorManager, blanker);
+                mSensorManager = sensorManager;
             }
 
             mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 14bd2d8..78a48da 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -18,26 +18,41 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManager;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.UserHandle;
+import android.os.PowerManager;
+import android.os.SystemClock;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 
 import com.android.internal.R;
+import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
+import com.android.server.display.whitebalance.AmbientFilter;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -74,7 +89,7 @@
     private final AppRequestObserver mAppRequestObserver;
     private final SettingsObserver mSettingsObserver;
     private final DisplayObserver mDisplayObserver;
-
+    private final BrightnessObserver mBrightnessObserver;
 
     private Listener mListener;
 
@@ -87,6 +102,8 @@
         mAppRequestObserver = new AppRequestObserver();
         mSettingsObserver = new SettingsObserver(context, handler);
         mDisplayObserver = new DisplayObserver(context, handler);
+        mBrightnessObserver = new BrightnessObserver(context, handler);
+
     }
 
     /**
@@ -96,15 +113,17 @@
      * This has to be deferred because the object may be constructed before the rest of the system
      * is ready.
      */
-    public void start() {
+    public void start(SensorManager sensorManager) {
         mSettingsObserver.observe();
         mDisplayObserver.observe();
         mSettingsObserver.observe();
+        mBrightnessObserver.observe(sensorManager);
         synchronized (mLock) {
             // We may have a listener already registered before the call to start, so go ahead and
             // notify them to pick up our newly initialized state.
             notifyAllowedModesChangedLocked();
         }
+
     }
 
     /**
@@ -315,6 +334,7 @@
             }
             mSettingsObserver.dumpLocked(pw);
             mAppRequestObserver.dumpLocked(pw);
+            mBrightnessObserver.dumpLocked(pw);
         }
     }
 
@@ -486,20 +506,15 @@
                 Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
         private final Uri mLowPowerModeSetting =
                 Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);
-        private final Uri mBrightnessSetting =
-                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
 
         private final Context mContext;
         private final float mDefaultPeakRefreshRate;
-        private final int mBrightnessThreshold;
 
         SettingsObserver(@NonNull Context context, @NonNull Handler handler) {
             super(handler);
             mContext = context;
             mDefaultPeakRefreshRate = (float) context.getResources().getInteger(
                     R.integer.config_defaultPeakRefreshRate);
-            mBrightnessThreshold = context.getResources().getInteger(
-                    R.integer.config_brightnessThresholdOfPeakRefreshRate);
         }
 
         public void observe() {
@@ -508,14 +523,9 @@
                     UserHandle.USER_SYSTEM);
             cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
                     UserHandle.USER_SYSTEM);
-            if (mBrightnessThreshold >= 0) {
-                cr.registerContentObserver(mBrightnessSetting, false /*notifyDescendants*/, this,
-                    UserHandle.USER_SYSTEM);
-            }
             synchronized (mLock) {
                 updateRefreshRateSettingLocked();
                 updateLowPowerModeSettingLocked();
-                updateBrightnessSettingLocked();
             }
         }
 
@@ -526,8 +536,6 @@
                     updateRefreshRateSettingLocked();
                 } else if (mLowPowerModeSetting.equals(uri)) {
                     updateLowPowerModeSettingLocked();
-                } else if (mBrightnessThreshold >=0 && mBrightnessSetting.equals(uri)) {
-                    updateBrightnessSettingLocked();
                 }
             }
         }
@@ -542,6 +550,7 @@
                 vote = null;
             }
             updateVoteLocked(Vote.PRIORITY_LOW_POWER_MODE, vote);
+            mBrightnessObserver.onLowPowerModeEnabled(inLowPowerMode);
         }
 
         private void updateRefreshRateSettingLocked() {
@@ -549,23 +558,7 @@
                     Settings.System.PEAK_REFRESH_RATE, mDefaultPeakRefreshRate);
             Vote vote = Vote.forRefreshRates(0f, peakRefreshRate);
             updateVoteLocked(Vote.PRIORITY_USER_SETTING_REFRESH_RATE, vote);
-        }
-
-        private void updateBrightnessSettingLocked() {
-            int brightness = Settings.System.getInt(mContext.getContentResolver(),
-                    Settings.System.SCREEN_BRIGHTNESS, -1);
-
-            if (brightness < 0) {
-                return;
-            }
-
-            final Vote vote;
-            if (brightness <= mBrightnessThreshold) {
-                vote = Vote.forRefreshRates(0f, 60f);
-            } else {
-                vote = null;
-            }
-            updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
+            mBrightnessObserver.onPeakRefreshRateEnabled(peakRefreshRate > 60f);
         }
 
         public void dumpLocked(PrintWriter pw) {
@@ -715,4 +708,240 @@
             }
         }
     }
+
+    /**
+     * This class manages brightness threshold for switching between 60 hz and higher refresh rate.
+     * See more information at the definition of
+     * {@link R.array#config_brightnessThresholdsOfPeakRefreshRate} and
+     * {@link R.array#config_ambientThresholdsOfPeakRefreshRate}.
+     */
+    private class BrightnessObserver extends ContentObserver {
+        private final Uri mDisplayBrightnessSetting =
+                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+
+        private final static int LIGHT_SENSOR_RATE_MS = 250;
+        private final int[] mDisplayBrightnessThresholds;
+        private final int[] mAmbientBrightnessThresholds;
+        // valid threshold if any item from the array >= 0
+        private boolean mShouldObserveDisplayChange;
+        private boolean mShouldObserveAmbientChange;
+
+        private SensorManager mSensorManager;
+        private Sensor mLightSensor;
+        // Take it as low brightness before valid sensor data comes
+        private float mAmbientLux = -1.0f;
+        private AmbientFilter mAmbientFilter;
+
+        private final Context mContext;
+        private ScreenStateReceiver mScreenStateReceiver;
+
+        // Enable light sensor only when screen is on, peak refresh rate enabled and low power mode
+        // off. After initialization, these states will be updated from the same handler thread.
+        private boolean mScreenOn = false;
+        private boolean mPeakRefreshRateEnabled = false;
+        private boolean mLowPowerModeEnabled = false;
+
+        BrightnessObserver(Context context, Handler handler) {
+            super(handler);
+            mContext = context;
+            mDisplayBrightnessThresholds = context.getResources().getIntArray(
+                    R.array.config_brightnessThresholdsOfPeakRefreshRate);
+            mAmbientBrightnessThresholds = context.getResources().getIntArray(
+                    R.array.config_ambientThresholdsOfPeakRefreshRate);
+            if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) {
+                throw new RuntimeException("display brightness threshold array and ambient "
+                        + "brightness threshold array have different length");
+            }
+
+            mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds);
+            mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds);
+        }
+
+        public void observe(SensorManager sensorManager) {
+            if (mShouldObserveDisplayChange) {
+                final ContentResolver cr = mContext.getContentResolver();
+                cr.registerContentObserver(mDisplayBrightnessSetting,
+                        false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM);
+            }
+
+            if (mShouldObserveAmbientChange) {
+                Resources resources = mContext.getResources();
+                String lightSensorType = resources.getString(
+                        com.android.internal.R.string.config_displayLightSensorType);
+
+                Sensor lightSensor = null;
+                if (!TextUtils.isEmpty(lightSensorType)) {
+                    List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
+                    for (int i = 0; i < sensors.size(); i++) {
+                        Sensor sensor = sensors.get(i);
+                        if (lightSensorType.equals(sensor.getStringType())) {
+                            lightSensor = sensor;
+                            break;
+                        }
+                    }
+                }
+
+                if (lightSensor == null) {
+                    lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+                }
+
+                if (lightSensor != null) {
+                    final Resources res = mContext.getResources();
+
+                    mAmbientFilter = DisplayWhiteBalanceFactory.createBrightnessFilter(res);
+                    mSensorManager = sensorManager;
+                    mLightSensor = lightSensor;
+
+                    // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status.
+                    if (mContext.getSystemService(PowerManager.class).isInteractive()) {
+                        onScreenOn(true);
+                    }
+                    mScreenStateReceiver = new ScreenStateReceiver(mContext);
+                }
+            }
+
+            if (mShouldObserveDisplayChange || mShouldObserveAmbientChange) {
+                synchronized (mLock) {
+                    onBrightnessChangedLocked();
+                }
+            }
+        }
+
+        public void onPeakRefreshRateEnabled(boolean b) {
+            if (mShouldObserveAmbientChange && mPeakRefreshRateEnabled != b) {
+                mPeakRefreshRateEnabled = b;
+                updateSensorStatus();
+            }
+        }
+
+        public void onLowPowerModeEnabled(boolean b) {
+            if (mShouldObserveAmbientChange && mLowPowerModeEnabled != b) {
+                mLowPowerModeEnabled = b;
+                updateSensorStatus();
+            }
+        }
+
+        public void dumpLocked(PrintWriter pw) {
+            pw.println("  BrightnessObserver");
+
+            for (int d: mDisplayBrightnessThresholds) {
+                pw.println("    mDisplayBrightnessThreshold: " + d);
+            }
+
+            for (int d: mAmbientBrightnessThresholds) {
+                pw.println("    mAmbientBrightnessThreshold: " + d);
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            synchronized (mLock) {
+                onBrightnessChangedLocked();
+            }
+        }
+
+        /**
+         * Checks to see if at least one value is positive, in which case it is necessary to listen
+         * to value changes.
+         */
+        private boolean checkShouldObserve(int[] a) {
+            for (int d: a) {
+                if (d >= 0) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private void onBrightnessChangedLocked() {
+            int brightness = Settings.System.getInt(mContext.getContentResolver(),
+                    Settings.System.SCREEN_BRIGHTNESS, -1);
+
+            Vote vote = null;
+            for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) {
+                int disp = mDisplayBrightnessThresholds[i];
+                int ambi = mAmbientBrightnessThresholds[i];
+
+                if (disp >= 0 && ambi >= 0) {
+                    if (brightness <= disp && mAmbientLux <= ambi) {
+                        vote = Vote.forRefreshRates(0f, 60f);
+                    }
+                } else if (disp >= 0) {
+                    if (brightness <= disp) {
+                        vote = Vote.forRefreshRates(0f, 60f);
+                    }
+                } else if (ambi >= 0) {
+                    if (mAmbientLux <= ambi) {
+                        vote = Vote.forRefreshRates(0f, 60f);
+                    }
+                }
+
+                if (vote != null) {
+                    break;
+                }
+            }
+
+            if (DEBUG) {
+                Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " +  mAmbientLux +
+                        (vote != null ? " 60hz only" : " no refresh rate limit"));
+            }
+            updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
+        }
+
+        private void onScreenOn(boolean on) {
+            // Not check mShouldObserveAmbientChange because Screen status receiver is registered
+            // only when it is true.
+            if (mScreenOn != on) {
+                mScreenOn = on;
+                updateSensorStatus();
+            }
+        }
+
+        private void updateSensorStatus() {
+            if (mSensorManager == null || mLightSensorListener == null) {
+                return;
+            }
+
+            if (mScreenOn && !mLowPowerModeEnabled && mPeakRefreshRateEnabled) {
+                mSensorManager.registerListener(mLightSensorListener,
+                        mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
+            } else {
+                mSensorManager.unregisterListener(mLightSensorListener);
+            }
+        }
+
+        private final SensorEventListener mLightSensorListener = new SensorEventListener() {
+            @Override
+            public void onSensorChanged(SensorEvent event) {
+                long now = SystemClock.uptimeMillis();
+                mAmbientFilter.addValue(now, event.values[0]);
+                mAmbientLux = mAmbientFilter.getEstimate(now);
+
+                synchronized (mLock) {
+                    onBrightnessChangedLocked();
+                }
+            }
+
+            @Override
+            public void onAccuracyChanged(Sensor sensor, int accuracy) {
+                // Not used.
+            }
+        };
+
+        private final class ScreenStateReceiver extends BroadcastReceiver {
+            public ScreenStateReceiver(Context context) {
+                IntentFilter filter = new IntentFilter();
+                filter.addAction(Intent.ACTION_SCREEN_OFF);
+                filter.addAction(Intent.ACTION_SCREEN_ON);
+                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+                context.registerReceiver(this, filter, null, mHandler);
+            }
+
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 2e5aafe..7fb5b19 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -63,6 +63,8 @@
 import android.provider.Settings.System;
 import android.util.MathUtils;
 import android.util.Slog;
+import android.util.SparseIntArray;
+import android.view.Display;
 import android.view.SurfaceControl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AnimationUtils;
@@ -171,6 +173,11 @@
 
     private NightDisplayAutoMode mNightDisplayAutoMode;
 
+    /**
+     * Map of color modes -> display composition colorspace
+     */
+    private SparseIntArray mColorModeCompositionColorSpaces = null;
+
     public ColorDisplayService(Context context) {
         super(context);
         mHandler = new TintHandler(DisplayThread.get().getLooper());
@@ -267,6 +274,30 @@
         return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
     }
 
+    private void setUpDisplayCompositionColorSpaces(Resources res) {
+        mColorModeCompositionColorSpaces = null;
+
+        final int[] colorModes = res.getIntArray(R.array.config_displayCompositionColorModes);
+        if (colorModes == null) {
+            return;
+        }
+
+        final int[] compSpaces = res.getIntArray(R.array.config_displayCompositionColorSpaces);
+        if (compSpaces == null) {
+            return;
+        }
+
+        if (colorModes.length != compSpaces.length) {
+            Slog.e(TAG, "Number of composition color spaces doesn't match specified color modes");
+            return;
+        }
+
+        mColorModeCompositionColorSpaces = new SparseIntArray(colorModes.length);
+        for (int i = 0; i < colorModes.length; i++) {
+            mColorModeCompositionColorSpaces.put(colorModes[i], compSpaces[i]);
+        }
+    }
+
     private void setUp() {
         Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
 
@@ -359,6 +390,8 @@
         onAccessibilityInversionChanged();
         onAccessibilityDaltonizerChanged();
 
+        setUpDisplayCompositionColorSpaces(getContext().getResources());
+
         // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
         // existing activated state. This ensures consistency of tint across the color mode change.
         onDisplayColorModeChanged(getColorModeInternal());
@@ -450,6 +483,14 @@
         }
     }
 
+    private int getCompositionColorSpace(int mode) {
+        if (mColorModeCompositionColorSpaces == null) {
+            return Display.COLOR_MODE_INVALID;
+        }
+
+        return mColorModeCompositionColorSpaces.get(mode, Display.COLOR_MODE_INVALID);
+    }
+
     private void onDisplayColorModeChanged(int mode) {
         if (mode == NOT_SET) {
             return;
@@ -470,7 +511,8 @@
         // DisplayTransformManager.needsLinearColorMatrix(), therefore it is dependent
         // on the state of DisplayTransformManager.
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
-        dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
+        dtm.setColorMode(mode, mNightDisplayTintController.getMatrix(),
+                getCompositionColorSpace(mode));
 
         if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
             updateDisplayWhiteBalanceStatus();
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index 5ff45a9..d5706a5 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -26,6 +26,7 @@
 import android.os.SystemProperties;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.Display;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -77,6 +78,8 @@
     @VisibleForTesting
     static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
     @VisibleForTesting
+    static final String PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE = "persist.sys.sf.color_mode";
+    @VisibleForTesting
     static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
 
     private static final float COLOR_SATURATION_NATURAL = 1.0f;
@@ -251,23 +254,24 @@
     /**
      * Sets color mode and updates night display transform values.
      */
-    public boolean setColorMode(int colorMode, float[] nightDisplayMatrix) {
+    public boolean setColorMode(int colorMode, float[] nightDisplayMatrix,
+            int compositionColorMode) {
         if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {
             applySaturation(COLOR_SATURATION_NATURAL);
-            setDisplayColor(DISPLAY_COLOR_MANAGED);
+            setDisplayColor(DISPLAY_COLOR_MANAGED, compositionColorMode);
         } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
             applySaturation(COLOR_SATURATION_BOOSTED);
-            setDisplayColor(DISPLAY_COLOR_MANAGED);
+            setDisplayColor(DISPLAY_COLOR_MANAGED, compositionColorMode);
         } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
             applySaturation(COLOR_SATURATION_NATURAL);
-            setDisplayColor(DISPLAY_COLOR_UNMANAGED);
+            setDisplayColor(DISPLAY_COLOR_UNMANAGED, compositionColorMode);
         } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
             applySaturation(COLOR_SATURATION_NATURAL);
-            setDisplayColor(DISPLAY_COLOR_ENHANCED);
+            setDisplayColor(DISPLAY_COLOR_ENHANCED, compositionColorMode);
         } else if (colorMode >= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN
                 && colorMode <= ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MAX) {
             applySaturation(COLOR_SATURATION_NATURAL);
-            setDisplayColor(colorMode);
+            setDisplayColor(colorMode, compositionColorMode);
         }
 
         setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix);
@@ -323,13 +327,21 @@
     /**
      * Toggles native mode on/off in SurfaceFlinger.
      */
-    private void setDisplayColor(int color) {
+    private void setDisplayColor(int color, int compositionColorMode) {
         SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, Integer.toString(color));
+        if (compositionColorMode != Display.COLOR_MODE_INVALID) {
+            SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE,
+                Integer.toString(compositionColorMode));
+        }
+
         final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
         if (flinger != null) {
             final Parcel data = Parcel.obtain();
             data.writeInterfaceToken("android.ui.ISurfaceComposer");
             data.writeInt(color);
+            if (compositionColorMode != Display.COLOR_MODE_INVALID) {
+                data.writeInt(compositionColorMode);
+            }
             try {
                 flinger.transact(SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR, data, null, 0);
             } catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java b/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java
index 123cd73..3580897 100644
--- a/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java
+++ b/services/core/java/com/android/server/display/whitebalance/AmbientFilter.java
@@ -36,7 +36,7 @@
  * - {@link WeightedMovingAverageAmbientFilter}
  *   A weighted average prioritising recent changes.
  */
-abstract class AmbientFilter {
+abstract public class AmbientFilter {
 
     protected static final boolean DEBUG = false; // Enable for verbose logs.
 
@@ -156,8 +156,7 @@
     /**
      * A weighted average prioritising recent changes.
      */
-    @VisibleForTesting
-    public static class WeightedMovingAverageAmbientFilter extends AmbientFilter {
+    static class WeightedMovingAverageAmbientFilter extends AmbientFilter {
 
         // How long the latest ambient value change is predicted to last.
         private static final int PREDICTION_TIME = 100; // Milliseconds
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
index 4df7d6b..bf0a1d1 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
@@ -115,8 +115,7 @@
      * Creates a BrightnessFilter which functions as a weighted moving average buffer for recent
      * brightness values.
      */
-    @VisibleForTesting
-    static AmbientFilter createBrightnessFilter(Resources resources) {
+    public static AmbientFilter createBrightnessFilter(Resources resources) {
         final int horizon = resources.getInteger(
                 com.android.internal.R.integer.config_displayWhiteBalanceBrightnessFilterHorizon);
         final float intercept = getFloat(resources,
@@ -129,7 +128,6 @@
                 + "expected config_displayWhiteBalanceBrightnessFilterIntercept");
     }
 
-
     /**
      * Creates an ambient color sensor instance to redirect sensor data to callbacks.
      */
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index d73c253..6f2b334 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -28,7 +28,7 @@
 import android.net.Uri;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
 import android.util.ArraySet;
 import android.util.Pair;
 import android.util.Slog;
@@ -1660,17 +1660,13 @@
         if (numFailures != 0) {
             pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
         }
-        final Time t = new Time();
-        final String format = "%Y-%m-%d %H:%M:%S";
         if (mLastSuccessfulRunTime != 0) {
             pw.print(prefix); pw.print("Last successful run: ");
-            t.set(mLastSuccessfulRunTime);
-            pw.println(t.format(format));
+            pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastSuccessfulRunTime));
         }
         if (mLastFailedRunTime != 0) {
             pw.print(prefix); pw.print("Last failed run: ");
-            t.set(mLastFailedRunTime);
-            pw.println(t.format(format));
+            pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastFailedRunTime));
         }
     }
 
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index ababad9..4c11947 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -18,20 +18,13 @@
 
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.AlarmManager.OnAlarmListener;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.WorkSource;
-import android.provider.Settings;
-import android.util.KeyValueListParser;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -39,7 +32,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.job.ConstantsProto;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.StateControllerProto;
 
@@ -63,9 +55,6 @@
     /** Delay alarm tag for logging purposes */
     private final String DELAY_TAG = "*job.delay*";
 
-    private final Handler mHandler;
-    private final TcConstants mTcConstants;
-
     private long mNextJobExpiredElapsedMillis;
     private long mNextDelayExpiredElapsedMillis;
 
@@ -81,14 +70,6 @@
         mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
         mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
         mChainedAttributionEnabled = mService.isChainedAttributionEnabled();
-
-        mHandler = new Handler(mContext.getMainLooper());
-        mTcConstants = new TcConstants(mHandler);
-    }
-
-    @Override
-    public void onSystemServicesReady() {
-        mTcConstants.start(mContext.getContentResolver());
     }
 
     /**
@@ -133,20 +114,16 @@
 
             job.setTrackingController(JobStatus.TRACKING_TIME);
             WorkSource ws = deriveWorkSource(job.getSourceUid(), job.getSourcePackageName());
-            final long deadlineExpiredElapsed =
-                    job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE;
-            final long delayExpiredElapsed =
-                    job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE;
-            if (mTcConstants.SKIP_NOT_READY_JOBS) {
-                if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
-                    maybeUpdateDelayAlarmLocked(delayExpiredElapsed, ws);
-                }
-                if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) {
-                    maybeUpdateDeadlineAlarmLocked(deadlineExpiredElapsed, ws);
-                }
-            } else {
-                maybeUpdateDelayAlarmLocked(delayExpiredElapsed, ws);
-                maybeUpdateDeadlineAlarmLocked(deadlineExpiredElapsed, ws);
+
+            // Only update alarms if the job would be ready with the relevant timing constraint
+            // satisfied.
+            if (job.hasTimingDelayConstraint()
+                    && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
+                maybeUpdateDelayAlarmLocked(job.getEarliestRunTime(), ws);
+            }
+            if (job.hasDeadlineConstraint()
+                    && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) {
+                maybeUpdateDeadlineAlarmLocked(job.getLatestRunTimeElapsed(), ws);
             }
         }
     }
@@ -168,10 +145,6 @@
 
     @Override
     public void evaluateStateLocked(JobStatus job) {
-        if (!mTcConstants.SKIP_NOT_READY_JOBS) {
-            return;
-        }
-
         final long nowElapsedMillis = sElapsedRealtimeClock.millis();
 
         // Check deadline constraint first because if it's satisfied, we avoid a little bit of
@@ -261,9 +234,7 @@
                     }
                     it.remove();
                 } else {  // Sorted by expiry time, so take the next one and stop.
-                    if (mTcConstants.SKIP_NOT_READY_JOBS
-                            && !wouldBeReadyWithConstraintLocked(
-                            job, JobStatus.CONSTRAINT_DEADLINE)) {
+                    if (!wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) {
                         if (DEBUG) {
                             Slog.i(TAG,
                                     "Skipping " + job + " because deadline won't make it ready.");
@@ -321,9 +292,7 @@
                         ready = true;
                     }
                 } else {
-                    if (mTcConstants.SKIP_NOT_READY_JOBS
-                            && !wouldBeReadyWithConstraintLocked(
-                            job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
+                    if (!wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
                         if (DEBUG) {
                             Slog.i(TAG,
                                     "Skipping " + job + " because delay won't make it ready.");
@@ -458,81 +427,6 @@
         checkExpiredDelaysAndResetAlarm();
     }
 
-    @VisibleForTesting
-    class TcConstants extends ContentObserver {
-        private ContentResolver mResolver;
-        private final KeyValueListParser mParser = new KeyValueListParser(',');
-
-        private static final String KEY_SKIP_NOT_READY_JOBS = "skip_not_ready_jobs";
-
-        private static final boolean DEFAULT_SKIP_NOT_READY_JOBS = true;
-
-        /**
-         * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
-         * ready now.
-         */
-        public boolean SKIP_NOT_READY_JOBS = DEFAULT_SKIP_NOT_READY_JOBS;
-
-        /**
-         * Creates a content observer.
-         *
-         * @param handler The handler to run {@link #onChange} on, or null if none.
-         */
-        TcConstants(Handler handler) {
-            super(handler);
-        }
-
-        private void start(ContentResolver resolver) {
-            mResolver = resolver;
-            mResolver.registerContentObserver(Settings.Global.getUriFor(
-                    Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS), false, this);
-            onChange(true, null);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            final String constants = Settings.Global.getString(
-                    mResolver, Settings.Global.JOB_SCHEDULER_TIME_CONTROLLER_CONSTANTS);
-
-            try {
-                mParser.setString(constants);
-            } catch (Exception e) {
-                // Failed to parse the settings string, log this and move on with defaults.
-                Slog.e(TAG, "Bad jobscheduler time controller settings", e);
-            }
-
-            final boolean oldVal = SKIP_NOT_READY_JOBS;
-            SKIP_NOT_READY_JOBS = mParser.getBoolean(
-                    KEY_SKIP_NOT_READY_JOBS, DEFAULT_SKIP_NOT_READY_JOBS);
-
-            if (oldVal != SKIP_NOT_READY_JOBS) {
-                synchronized (mLock) {
-                    recheckAlarmsLocked();
-                }
-            }
-        }
-
-        private void dump(IndentingPrintWriter pw) {
-            pw.println();
-            pw.println("TimeController:");
-            pw.increaseIndent();
-            pw.printPair(KEY_SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS).println();
-            pw.decreaseIndent();
-        }
-
-        private void dump(ProtoOutputStream proto) {
-            final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER);
-            proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS);
-            proto.end(tcToken);
-        }
-    }
-
-    @VisibleForTesting
-    @NonNull
-    TcConstants getTcConstants() {
-        return mTcConstants;
-    }
-
     @Override
     public void dumpControllerStateLocked(IndentingPrintWriter pw,
             Predicate<JobStatus> predicate) {
@@ -607,14 +501,4 @@
         proto.end(mToken);
         proto.end(token);
     }
-
-    @Override
-    public void dumpConstants(IndentingPrintWriter pw) {
-        mTcConstants.dump(pw);
-    }
-
-    @Override
-    public void dumpConstants(ProtoOutputStream proto) {
-        mTcConstants.dump(proto);
-    }
 }
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 6911b7c..461f19b 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1608,13 +1608,11 @@
         if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
         mHandler.post(() -> {
             setupNativeGnssService(/* reinitializeGnssServiceHandle = */ true);
+            // resend configuration into the restarted HAL service.
+            reloadGpsProperties();
             if (isGpsEnabled()) {
                 setGpsEnabled(false);
-
                 updateEnabled();
-
-                // resend configuration into the restarted HAL service.
-                reloadGpsProperties();
             }
         });
     }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index f0e431e..84ae7c7 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -48,6 +48,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -390,6 +392,17 @@
         return stored;
     }
 
+    private void fsyncDirectory(File directory) {
+        try {
+            try (FileChannel file = FileChannel.open(directory.toPath(),
+                    StandardOpenOption.READ)) {
+                file.force(true);
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Error syncing directory: " + directory, e);
+        }
+    }
+
     private void writeFile(String name, byte[] hash) {
         synchronized (mFileWriteLock) {
             RandomAccessFile raf = null;
@@ -406,6 +419,7 @@
                     raf.write(hash, 0, hash.length);
                 }
                 raf.close();
+                fsyncDirectory((new File(name)).getAbsoluteFile().getParentFile());
             } catch (IOException e) {
                 Slog.e(TAG, "Error writing to file " + e);
             } finally {
diff --git a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java
index 5cbd237..4ef63c0 100644
--- a/services/core/java/com/android/server/locksettings/PasswordSlotManager.java
+++ b/services/core/java/com/android/server/locksettings/PasswordSlotManager.java
@@ -122,7 +122,7 @@
      */
     public void markSlotDeleted(int slot) throws RuntimeException {
         ensureSlotMapLoaded();
-        if (mSlotMap.containsKey(slot) && mSlotMap.get(slot) != getMode()) {
+        if (mSlotMap.containsKey(slot) && !mSlotMap.get(slot).equals(getMode())) {
             throw new RuntimeException("password slot " + slot + " cannot be deleted");
         }
         mSlotMap.remove(slot);
diff --git a/services/core/java/com/android/server/locksettings/TEST_MAPPING b/services/core/java/com/android/server/locksettings/TEST_MAPPING
new file mode 100644
index 0000000..c1cba5f
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+    "presubmit": [
+        {
+            "name": "CtsDevicePolicyManagerTestCases",
+            "options": [
+                {
+                    "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
+                },
+                {
+                    "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                }
+            ]
+        }
+    ]
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index c54bfc0..0ad6c2a 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -19,6 +19,7 @@
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.security.GateKeeper;
 import android.security.keystore.AndroidKeyStoreSecretKey;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
@@ -437,25 +438,31 @@
         // so it may live in memory for some time.
         SecretKey secretKey = generateAesKey();
 
-        long secureUserId = getGateKeeperService().getSecureUserId(userId);
-        // TODO(b/124095438): Propagate this failure instead of silently failing.
-        if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
-            Log.e(TAG, "No SID available for user " + userId);
-            return;
-        }
-
-        // Store decryption key first since it is more likely to fail.
-        mKeyStore.setEntry(
-                decryptAlias,
-                new KeyStore.SecretKeyEntry(secretKey),
+        KeyProtection.Builder decryptionKeyProtection =
                 new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
                     .setUserAuthenticationRequired(true)
                     .setUserAuthenticationValidityDurationSeconds(
                             USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS)
                     .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
-                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
+        if (userId != UserHandle.USER_SYSTEM) {
+            // Bind decryption key to secondary profile lock screen secret.
+            long secureUserId = getGateKeeperService().getSecureUserId(userId);
+            // TODO(b/124095438): Propagate this failure instead of silently failing.
+            if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
+                Log.e(TAG, "No SID available for user " + userId);
+                return;
+            }
+            decryptionKeyProtection
                     .setBoundToSpecificSecureUserId(secureUserId)
-                    .build());
+                    // Ignore caller uid which always belongs to the primary profile.
+                    .setCriticalToDeviceEncryption(true);
+        }
+        // Store decryption key first since it is more likely to fail.
+        mKeyStore.setEntry(
+                decryptAlias,
+                new KeyStore.SecretKeyEntry(secretKey),
+                decryptionKeyProtection.build());
         mKeyStore.setEntry(
                 encryptAlias,
                 new KeyStore.SecretKeyEntry(secretKey),
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 01936c9..12137fe 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -32,16 +32,15 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.Message;
 import android.os.RemoteException;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -204,13 +203,15 @@
 
                 UserRecord oldUser = mUserRecords.get(oldUserId);
                 if (oldUser != null) {
-                    oldUser.mHandler.sendEmptyMessage(MediaRouterService.UserHandler.MSG_STOP);
+                    oldUser.mHandler.sendMessage(
+                            obtainMessage(UserHandler::stop, oldUser.mHandler));
                     disposeUserIfNeededLocked(oldUser); // since no longer current user
                 }
 
                 UserRecord newUser = mUserRecords.get(userId);
                 if (newUser != null) {
-                    newUser.mHandler.sendEmptyMessage(MediaRouterService.UserHandler.MSG_START);
+                    newUser.mHandler.sendMessage(
+                            obtainMessage(UserHandler::start, newUser.mHandler));
                 }
             }
         }
@@ -296,8 +297,9 @@
         if (clientRecord != null) {
             clientRecord.mControlCategories = categories;
 
-            clientRecord.mUserRecord.mHandler.obtainMessage(
-                    UserHandler.MSG_UPDATE_CLIENT_USAGE, clientRecord).sendToTarget();
+            clientRecord.mUserRecord.mHandler.sendMessage(
+                    obtainMessage(UserHandler::updateClientUsage,
+                            clientRecord.mUserRecord.mHandler, clientRecord));
         }
     }
 
@@ -307,9 +309,9 @@
         ClientRecord clientRecord = mAllClientRecords.get(binder);
 
         if (clientRecord != null) {
-            Pair<MediaRoute2Info, Intent> obj = new Pair<>(route, request);
-            clientRecord.mUserRecord.mHandler.obtainMessage(
-                    UserHandler.MSG_SEND_CONTROL_REQUEST, obj).sendToTarget();
+            clientRecord.mUserRecord.mHandler.sendMessage(
+                    obtainMessage(UserHandler::sendControlRequest,
+                            clientRecord.mUserRecord.mHandler, route, request));
         }
     }
 
@@ -346,8 +348,9 @@
             final int count = userRecord.mClientRecords.size();
             for (int i = 0; i < count; i++) {
                 ClientRecord clientRecord = userRecord.mClientRecords.get(i);
-                clientRecord.mUserRecord.mHandler.obtainMessage(
-                        UserHandler.MSG_UPDATE_CLIENT_USAGE, clientRecord).sendToTarget();
+                clientRecord.mUserRecord.mHandler.sendMessage(
+                        obtainMessage(UserHandler::updateClientUsage,
+                            clientRecord.mUserRecord.mHandler, clientRecord));
             }
         }
     }
@@ -381,7 +384,8 @@
             Slog.d(TAG, userRecord + ": Initialized");
         }
         if (userRecord.mUserId == mCurrentUserId) {
-            userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START);
+            userRecord.mHandler.sendMessage(
+                    obtainMessage(UserHandler::start, userRecord.mHandler));
         }
     }
 
@@ -497,13 +501,6 @@
             MediaRoute2ProviderWatcher.Callback,
             MediaRoute2ProviderProxy.Callback {
 
-        //TODO: Use PooledLambda instead.
-        static final int MSG_START = 1;
-        static final int MSG_STOP = 2;
-
-        static final int MSG_UPDATE_CLIENT_USAGE = 11;
-        static final int MSG_SEND_CONTROL_REQUEST = 12;
-
         private final WeakReference<MediaRouter2ServiceImpl> mServiceRef;
         private final UserRecord mUserRecord;
         private final MediaRoute2ProviderWatcher mWatcher;
@@ -524,28 +521,6 @@
                     this, mUserRecord.mUserId);
         }
 
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_START: {
-                    start();
-                    break;
-                }
-                case MSG_STOP: {
-                    stop();
-                    break;
-                }
-                case MSG_UPDATE_CLIENT_USAGE: {
-                    updateClientUsage((ClientRecord) msg.obj);
-                    break;
-                }
-                case MSG_SEND_CONTROL_REQUEST: {
-                    Pair<MediaRoute2Info, Intent> obj = (Pair<MediaRoute2Info, Intent>) msg.obj;
-                    sendControlRequest(obj.first, obj.second);
-                }
-            }
-        }
-
         private void start() {
             if (!mRunning) {
                 mRunning = true;
@@ -613,7 +588,7 @@
         private void scheduleUpdateManagerState() {
             if (!mManagerStateUpdateScheduled) {
                 mManagerStateUpdateScheduled = true;
-                post(this::updateManagerState);
+                sendMessage(PooledLambda.obtainMessage(UserHandler::updateManagerState, this));
             }
         }
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 6c34e13..b4a8099 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -217,7 +217,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.os.RoSystemProperties;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ConcurrentUtils;
@@ -232,7 +231,6 @@
 import com.android.server.SystemConfig;
 
 import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
@@ -404,8 +402,10 @@
     private IConnectivityManager mConnManager;
     private PowerManagerInternal mPowerManagerInternal;
     private IDeviceIdleController mDeviceIdleController;
+
+    /** Current cached value of the current Battery Saver mode's setting for restrict background. */
     @GuardedBy("mUidRulesFirstLock")
-    private PowerSaveState mRestrictBackgroundPowerState;
+    private boolean mRestrictBackgroundLowPowerMode;
 
     // Store the status of restrict background before turning on battery saver.
     // Used to restore mRestrictBackground when battery saver is turned off.
@@ -540,7 +540,7 @@
     private final SparseArray<String> mSubIdToSubscriberId = new SparseArray<>();
     /** Set of all merged subscriberId as of last update */
     @GuardedBy("mNetworkPoliciesSecondLock")
-    private String[] mMergedSubscriberIds = EmptyArray.STRING;
+    private List<String[]> mMergedSubscriberIds = new ArrayList<>();
 
     /**
      * Indicates the uids restricted by admin from accessing metered data. It's a mapping from
@@ -772,11 +772,9 @@
 
                     // Update the restrictBackground if battery saver is turned on
                     mRestrictBackgroundBeforeBsm = mLoadedRestrictBackground;
-                    mRestrictBackgroundPowerState = mPowerManagerInternal
-                            .getLowPowerState(ServiceType.DATA_SAVER);
-                    final boolean localRestrictBackground =
-                            mRestrictBackgroundPowerState.batterySaverEnabled;
-                    if (localRestrictBackground && !mLoadedRestrictBackground) {
+                    mRestrictBackgroundLowPowerMode = mPowerManagerInternal
+                            .getLowPowerState(ServiceType.DATA_SAVER).batterySaverEnabled;
+                    if (mRestrictBackgroundLowPowerMode && !mLoadedRestrictBackground) {
                         mLoadedRestrictBackground = true;
                     }
                     mPowerManagerInternal.registerLowPowerModeObserver(
@@ -1355,7 +1353,7 @@
 
                 final Intent viewIntent = buildViewDataUsageIntent(res, policy.template);
                 // TODO: Resolve to single code path.
-                if (isHeadlessSystemUserBuild()) {
+                if (UserManager.isHeadlessSystemUserMode()) {
                     builder.setContentIntent(PendingIntent.getActivityAsUser(
                             mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT,
                             /* options= */ null, UserHandle.CURRENT));
@@ -1383,7 +1381,7 @@
 
                 final Intent intent = buildNetworkOverLimitIntent(res, policy.template);
                 // TODO: Resolve to single code path.
-                if (isHeadlessSystemUserBuild()) {
+                if (UserManager.isHeadlessSystemUserMode()) {
                     builder.setContentIntent(PendingIntent.getActivityAsUser(
                             mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT,
                             /* options= */ null, UserHandle.CURRENT));
@@ -1414,7 +1412,7 @@
 
                 final Intent intent = buildViewDataUsageIntent(res, policy.template);
                 // TODO: Resolve to single code path.
-                if (isHeadlessSystemUserBuild()) {
+                if (UserManager.isHeadlessSystemUserMode()) {
                     builder.setContentIntent(PendingIntent.getActivityAsUser(
                             mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT,
                             /* options= */ null, UserHandle.CURRENT));
@@ -1441,7 +1439,7 @@
 
                 final Intent viewIntent = buildViewDataUsageIntent(res, policy.template);
                 // TODO: Resolve to single code path.
-                if (isHeadlessSystemUserBuild()) {
+                if (UserManager.isHeadlessSystemUserMode()) {
                     builder.setContentIntent(PendingIntent.getActivityAsUser(
                             mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT,
                             /* options= */ null, UserHandle.CURRENT));
@@ -1801,7 +1799,7 @@
         final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
 
         final int[] subIds = ArrayUtils.defeatNullable(sm.getActiveSubscriptionIdList());
-        final String[] mergedSubscriberIds = ArrayUtils.defeatNullable(tm.getMergedSubscriberIds());
+        final List<String[]> mergedSubscriberIdsList = new ArrayList();
 
         final SparseArray<String> subIdToSubscriberId = new SparseArray<>(subIds.length);
         for (int subId : subIds) {
@@ -1811,6 +1809,10 @@
             } else {
                 Slog.wtf(TAG, "Missing subscriberId for subId " + subId);
             }
+
+            String[] mergedSubscriberId = ArrayUtils.defeatNullable(
+                    tm.createForSubscriptionId(subId).getMergedSubscriberIdsFromGroup());
+            mergedSubscriberIdsList.add(mergedSubscriberId);
         }
 
         synchronized (mNetworkPoliciesSecondLock) {
@@ -1820,7 +1822,7 @@
                         subIdToSubscriberId.valueAt(i));
             }
 
-            mMergedSubscriberIds = mergedSubscriberIds;
+            mMergedSubscriberIds = mergedSubscriberIdsList;
         }
 
         Trace.traceEnd(TRACE_TAG_NETWORK);
@@ -2897,7 +2899,7 @@
             sendRestrictBackgroundChangedMsg();
             mLogger.restrictBackgroundChanged(oldRestrictBackground, mRestrictBackground);
 
-            if (mRestrictBackgroundPowerState.globalBatterySaverEnabled) {
+            if (mRestrictBackgroundLowPowerMode) {
                 mRestrictBackgroundChangedInBsm = true;
             }
             synchronized (mNetworkPoliciesSecondLock) {
@@ -3373,8 +3375,10 @@
                 fout.decreaseIndent();
 
                 fout.println();
-                fout.println("Merged subscriptions: "
-                        + Arrays.toString(NetworkIdentity.scrubSubscriberId(mMergedSubscriberIds)));
+                for (String[] mergedSubscribers : mMergedSubscriberIds) {
+                    fout.println("Merged subscriptions: " + Arrays.toString(
+                            NetworkIdentity.scrubSubscriberId(mergedSubscribers)));
+                }
 
                 fout.println();
                 fout.println("Policy for UIDs:");
@@ -4902,17 +4906,21 @@
     @GuardedBy("mUidRulesFirstLock")
     @VisibleForTesting
     void updateRestrictBackgroundByLowPowerModeUL(final PowerSaveState result) {
-        mRestrictBackgroundPowerState = result;
+        if (mRestrictBackgroundLowPowerMode == result.batterySaverEnabled) {
+            // Nothing changed. Nothing to do.
+            return;
+        }
+        mRestrictBackgroundLowPowerMode = result.batterySaverEnabled;
 
-        boolean restrictBackground = result.batterySaverEnabled;
+        boolean restrictBackground = mRestrictBackgroundLowPowerMode;
         boolean shouldInvokeRestrictBackground;
-        // store the temporary mRestrictBackgroundChangedInBsm and update it at last
+        // store the temporary mRestrictBackgroundChangedInBsm and update it at the end.
         boolean localRestrictBgChangedInBsm = mRestrictBackgroundChangedInBsm;
 
-        if (result.globalBatterySaverEnabled) {
+        if (mRestrictBackgroundLowPowerMode) {
             // Try to turn on restrictBackground if (1) it is off and (2) batter saver need to
             // turn it on.
-            shouldInvokeRestrictBackground = !mRestrictBackground && result.batterySaverEnabled;
+            shouldInvokeRestrictBackground = !mRestrictBackground;
             mRestrictBackgroundBeforeBsm = mRestrictBackground;
             localRestrictBgChangedInBsm = false;
         } else {
@@ -5292,10 +5300,6 @@
         return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
     }
 
-    private static boolean isHeadlessSystemUserBuild() {
-        return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER;
-    }
-
     private class NotificationId {
         private final String mTag;
         private final int mId;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 4a6eb27..4828bbf 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -196,18 +196,20 @@
 
     public void dump(PrintWriter pw, DumpFilter filter) {
         pw.println("    Allowed " + getCaption() + "s:");
-        final int N = mApproved.size();
-        for (int i = 0 ; i < N; i++) {
-            final int userId = mApproved.keyAt(i);
-            final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
-            if (approvedByType != null) {
-                final int M = approvedByType.size();
-                for (int j = 0; j < M; j++) {
-                    final boolean isPrimary = approvedByType.keyAt(j);
-                    final ArraySet<String> approved = approvedByType.valueAt(j);
-                    if (approvedByType != null && approvedByType.size() > 0) {
-                        pw.println("      " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
-                                + " (user: " + userId + " isPrimary: " + isPrimary + ")");
+        synchronized (mApproved) {
+            final int N = mApproved.size();
+            for (int i = 0; i < N; i++) {
+                final int userId = mApproved.keyAt(i);
+                final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+                if (approvedByType != null) {
+                    final int M = approvedByType.size();
+                    for (int j = 0; j < M; j++) {
+                        final boolean isPrimary = approvedByType.keyAt(j);
+                        final ArraySet<String> approved = approvedByType.valueAt(j);
+                        if (approvedByType != null && approvedByType.size() > 0) {
+                            pw.println("      " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
+                                    + " (user: " + userId + " isPrimary: " + isPrimary + ")");
+                        }
                     }
                 }
             }
@@ -240,23 +242,25 @@
 
     public void dump(ProtoOutputStream proto, DumpFilter filter) {
         proto.write(ManagedServicesProto.CAPTION, getCaption());
-        final int N = mApproved.size();
-        for (int i = 0 ; i < N; i++) {
-            final int userId = mApproved.keyAt(i);
-            final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
-            if (approvedByType != null) {
-                final int M = approvedByType.size();
-                for (int j = 0; j < M; j++) {
-                    final boolean isPrimary = approvedByType.keyAt(j);
-                    final ArraySet<String> approved = approvedByType.valueAt(j);
-                    if (approvedByType != null && approvedByType.size() > 0) {
-                        final long sToken = proto.start(ManagedServicesProto.APPROVED);
-                        for (String s : approved) {
-                            proto.write(ServiceProto.NAME, s);
+        synchronized (mApproved) {
+            final int N = mApproved.size();
+            for (int i = 0; i < N; i++) {
+                final int userId = mApproved.keyAt(i);
+                final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+                if (approvedByType != null) {
+                    final int M = approvedByType.size();
+                    for (int j = 0; j < M; j++) {
+                        final boolean isPrimary = approvedByType.keyAt(j);
+                        final ArraySet<String> approved = approvedByType.valueAt(j);
+                        if (approvedByType != null && approvedByType.size() > 0) {
+                            final long sToken = proto.start(ManagedServicesProto.APPROVED);
+                            for (String s : approved) {
+                                proto.write(ServiceProto.NAME, s);
+                            }
+                            proto.write(ServiceProto.USER_ID, userId);
+                            proto.write(ServiceProto.IS_PRIMARY, isPrimary);
+                            proto.end(sToken);
                         }
-                        proto.write(ServiceProto.USER_ID, userId);
-                        proto.write(ServiceProto.IS_PRIMARY, isPrimary);
-                        proto.end(sToken);
                     }
                 }
             }
@@ -315,33 +319,36 @@
             trimApprovedListsAccordingToInstalledServices(userId);
         }
 
-        final int N = mApproved.size();
-        for (int i = 0 ; i < N; i++) {
-            final int approvedUserId = mApproved.keyAt(i);
-            if (forBackup && approvedUserId != userId) {
-                continue;
-            }
-            final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
-            if (approvedByType != null) {
-                final int M = approvedByType.size();
-                for (int j = 0; j < M; j++) {
-                    final boolean isPrimary = approvedByType.keyAt(j);
-                    final Set<String> approved = approvedByType.valueAt(j);
-                    if (approved != null) {
-                        String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
-                        out.startTag(null, TAG_MANAGED_SERVICES);
-                        out.attribute(null, ATT_APPROVED_LIST, allowedItems);
-                        out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
-                        out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
-                        writeExtraAttributes(out, approvedUserId);
-                        out.endTag(null, TAG_MANAGED_SERVICES);
+        synchronized (mApproved) {
+            final int N = mApproved.size();
+            for (int i = 0; i < N; i++) {
+                final int approvedUserId = mApproved.keyAt(i);
+                if (forBackup && approvedUserId != userId) {
+                    continue;
+                }
+                final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+                if (approvedByType != null) {
+                    final int M = approvedByType.size();
+                    for (int j = 0; j < M; j++) {
+                        final boolean isPrimary = approvedByType.keyAt(j);
+                        final Set<String> approved = approvedByType.valueAt(j);
+                        if (approved != null) {
+                            String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
+                            out.startTag(null, TAG_MANAGED_SERVICES);
+                            out.attribute(null, ATT_APPROVED_LIST, allowedItems);
+                            out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
+                            out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
+                            writeExtraAttributes(out, approvedUserId);
+                            out.endTag(null, TAG_MANAGED_SERVICES);
 
-                        if (!forBackup && isPrimary) {
-                            // Also write values to settings, for observers who haven't migrated yet
-                            Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                                    getConfig().secureSettingName, allowedItems, approvedUserId);
+                            if (!forBackup && isPrimary) {
+                                // Also write values to settings, for observers who haven't migrated yet
+                                Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                                        getConfig().secureSettingName, allowedItems,
+                                        approvedUserId);
+                            }
+
                         }
-
                     }
                 }
             }
@@ -440,23 +447,25 @@
         if (TextUtils.isEmpty(approved)) {
             approved = "";
         }
-        ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
-        if (approvedByType == null) {
-            approvedByType = new ArrayMap<>();
-            mApproved.put(userId, approvedByType);
-        }
+        synchronized (mApproved) {
+            ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+            if (approvedByType == null) {
+                approvedByType = new ArrayMap<>();
+                mApproved.put(userId, approvedByType);
+            }
 
-        ArraySet<String> approvedList = approvedByType.get(isPrimary);
-        if (approvedList == null) {
-            approvedList = new ArraySet<>();
-            approvedByType.put(isPrimary, approvedList);
-        }
+            ArraySet<String> approvedList = approvedByType.get(isPrimary);
+            if (approvedList == null) {
+                approvedList = new ArraySet<>();
+                approvedByType.put(isPrimary, approvedList);
+            }
 
-        String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
-        for (String pkgOrComponent : approvedArray) {
-            String approvedItem = getApprovedValue(pkgOrComponent);
-            if (approvedItem != null) {
-                approvedList.add(approvedItem);
+            String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
+            for (String pkgOrComponent : approvedArray) {
+                String approvedItem = getApprovedValue(pkgOrComponent);
+                if (approvedItem != null) {
+                    approvedList.add(approvedItem);
+                }
             }
         }
     }
@@ -469,23 +478,25 @@
             boolean isPrimary, boolean enabled) {
         Slog.i(TAG,
                 (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
-        ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
-        if (allowedByType == null) {
-            allowedByType = new ArrayMap<>();
-            mApproved.put(userId, allowedByType);
-        }
-        ArraySet<String> approved = allowedByType.get(isPrimary);
-        if (approved == null) {
-            approved = new ArraySet<>();
-            allowedByType.put(isPrimary, approved);
-        }
-        String approvedItem = getApprovedValue(pkgOrComponent);
+        synchronized (mApproved) {
+            ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
+            if (allowedByType == null) {
+                allowedByType = new ArrayMap<>();
+                mApproved.put(userId, allowedByType);
+            }
+            ArraySet<String> approved = allowedByType.get(isPrimary);
+            if (approved == null) {
+                approved = new ArraySet<>();
+                allowedByType.put(isPrimary, approved);
+            }
+            String approvedItem = getApprovedValue(pkgOrComponent);
 
-        if (approvedItem != null) {
-            if (enabled) {
-                approved.add(approvedItem);
-            } else {
-                approved.remove(approvedItem);
+            if (approvedItem != null) {
+                if (enabled) {
+                    approved.add(approvedItem);
+                } else {
+                    approved.remove(approvedItem);
+                }
             }
         }
 
@@ -504,22 +515,26 @@
     }
 
     protected String getApproved(int userId, boolean primary) {
-        final ArrayMap<Boolean, ArraySet<String>> allowedByType =
-                mApproved.getOrDefault(userId, new ArrayMap<>());
-        ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
-        return String.join(ENABLED_SERVICES_SEPARATOR, approved);
+        synchronized (mApproved) {
+            final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+                    mApproved.getOrDefault(userId, new ArrayMap<>());
+            ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
+            return String.join(ENABLED_SERVICES_SEPARATOR, approved);
+        }
     }
 
     protected List<ComponentName> getAllowedComponents(int userId) {
         final List<ComponentName> allowedComponents = new ArrayList<>();
-        final ArrayMap<Boolean, ArraySet<String>> allowedByType =
-                mApproved.getOrDefault(userId, new ArrayMap<>());
-        for (int i = 0; i < allowedByType.size(); i++) {
-            final ArraySet<String> allowed = allowedByType.valueAt(i);
-            for (int j = 0; j < allowed.size(); j++) {
-                ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
-                if (cn != null) {
-                    allowedComponents.add(cn);
+        synchronized (mApproved) {
+            final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+                    mApproved.getOrDefault(userId, new ArrayMap<>());
+            for (int i = 0; i < allowedByType.size(); i++) {
+                final ArraySet<String> allowed = allowedByType.valueAt(i);
+                for (int j = 0; j < allowed.size(); j++) {
+                    ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
+                    if (cn != null) {
+                        allowedComponents.add(cn);
+                    }
                 }
             }
         }
@@ -528,14 +543,16 @@
 
     protected List<String> getAllowedPackages(int userId) {
         final List<String> allowedPackages = new ArrayList<>();
-        final ArrayMap<Boolean, ArraySet<String>> allowedByType =
-                mApproved.getOrDefault(userId, new ArrayMap<>());
-        for (int i = 0; i < allowedByType.size(); i++) {
-            final ArraySet<String> allowed = allowedByType.valueAt(i);
-            for (int j = 0; j < allowed.size(); j++) {
-                String pkgName = getPackageName(allowed.valueAt(j));
-                if (!TextUtils.isEmpty(pkgName)) {
-                    allowedPackages.add(pkgName);
+        synchronized (mApproved) {
+            final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+                    mApproved.getOrDefault(userId, new ArrayMap<>());
+            for (int i = 0; i < allowedByType.size(); i++) {
+                final ArraySet<String> allowed = allowedByType.valueAt(i);
+                for (int j = 0; j < allowed.size(); j++) {
+                    String pkgName = getPackageName(allowed.valueAt(j));
+                    if (!TextUtils.isEmpty(pkgName)) {
+                        allowedPackages.add(pkgName);
+                    }
                 }
             }
         }
@@ -543,12 +560,14 @@
     }
 
     protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
-        ArrayMap<Boolean, ArraySet<String>> allowedByType =
-                mApproved.getOrDefault(userId, new ArrayMap<>());
-        for (int i = 0; i < allowedByType.size(); i++) {
-            ArraySet<String> allowed = allowedByType.valueAt(i);
-            if (allowed.contains(pkgOrComponent)) {
-                return true;
+        synchronized (mApproved) {
+            ArrayMap<Boolean, ArraySet<String>> allowedByType =
+                    mApproved.getOrDefault(userId, new ArrayMap<>());
+            for (int i = 0; i < allowedByType.size(); i++) {
+                ArraySet<String> allowed = allowedByType.valueAt(i);
+                if (allowed.contains(pkgOrComponent)) {
+                    return true;
+                }
             }
         }
         return false;
@@ -558,19 +577,21 @@
         if (pkg == null) {
             return false;
         }
-        ArrayMap<Boolean, ArraySet<String>> allowedByType =
-                mApproved.getOrDefault(userId, new ArrayMap<>());
-        for (int i = 0; i < allowedByType.size(); i++) {
-            ArraySet<String> allowed = allowedByType.valueAt(i);
-            for (String allowedEntry : allowed) {
-                ComponentName component = ComponentName.unflattenFromString(allowedEntry);
-                if (component != null) {
-                    if (pkg.equals(component.getPackageName())) {
-                        return true;
-                    }
-                } else {
-                    if (pkg.equals(allowedEntry)) {
-                        return true;
+        synchronized (mApproved) {
+            ArrayMap<Boolean, ArraySet<String>> allowedByType =
+                    mApproved.getOrDefault(userId, new ArrayMap<>());
+            for (int i = 0; i < allowedByType.size(); i++) {
+                ArraySet<String> allowed = allowedByType.valueAt(i);
+                for (String allowedEntry : allowed) {
+                    ComponentName component = ComponentName.unflattenFromString(allowedEntry);
+                    if (component != null) {
+                        if (pkg.equals(component.getPackageName())) {
+                            return true;
+                        }
+                    } else {
+                        if (pkg.equals(allowedEntry)) {
+                            return true;
+                        }
                     }
                 }
             }
@@ -616,7 +637,9 @@
 
     public void onUserRemoved(int user) {
         Slog.i(TAG, "Removing approved services for removed user " + user);
-        mApproved.remove(user);
+        synchronized (mApproved) {
+            mApproved.remove(user);
+        }
         rebindServices(true, user);
     }
 
@@ -797,14 +820,16 @@
 
     protected Set<String> getAllowedPackages() {
         final Set<String> allowedPackages = new ArraySet<>();
-        for (int k = 0; k < mApproved.size(); k++) {
-            ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
-            for (int i = 0; i < allowedByType.size(); i++) {
-                final ArraySet<String> allowed = allowedByType.valueAt(i);
-                for (int j = 0; j < allowed.size(); j++) {
-                    String pkgName = getPackageName(allowed.valueAt(j));
-                    if (!TextUtils.isEmpty(pkgName)) {
-                        allowedPackages.add(pkgName);
+        synchronized (mApproved) {
+            for (int k = 0; k < mApproved.size(); k++) {
+                ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
+                for (int i = 0; i < allowedByType.size(); i++) {
+                    final ArraySet<String> allowed = allowedByType.valueAt(i);
+                    for (int j = 0; j < allowed.size(); j++) {
+                        String pkgName = getPackageName(allowed.valueAt(j));
+                        if (!TextUtils.isEmpty(pkgName)) {
+                            allowedPackages.add(pkgName);
+                        }
                     }
                 }
             }
@@ -813,22 +838,24 @@
     }
 
     private void trimApprovedListsAccordingToInstalledServices(int userId) {
-        final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
-        if (approvedByType == null) {
-            return;
-        }
-        for (int i = 0; i < approvedByType.size(); i++) {
-            final ArraySet<String> approved = approvedByType.valueAt(i);
-            for (int j = approved.size() - 1; j >= 0; j--) {
-                final String approvedPackageOrComponent = approved.valueAt(j);
-                if (!isValidEntry(approvedPackageOrComponent, userId)){
-                    approved.removeAt(j);
-                    Slog.v(TAG, "Removing " + approvedPackageOrComponent
-                            + " from approved list; no matching services found");
-                } else {
-                    if (DEBUG) {
-                        Slog.v(TAG, "Keeping " + approvedPackageOrComponent
-                                + " on approved list; matching services found");
+        synchronized (mApproved) {
+            final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+            if (approvedByType == null) {
+                return;
+            }
+            for (int i = 0; i < approvedByType.size(); i++) {
+                final ArraySet<String> approved = approvedByType.valueAt(i);
+                for (int j = approved.size() - 1; j >= 0; j--) {
+                    final String approvedPackageOrComponent = approved.valueAt(j);
+                    if (!isValidEntry(approvedPackageOrComponent, userId)) {
+                        approved.removeAt(j);
+                        Slog.v(TAG, "Removing " + approvedPackageOrComponent
+                                + " from approved list; no matching services found");
+                    } else {
+                        if (DEBUG) {
+                            Slog.v(TAG, "Keeping " + approvedPackageOrComponent
+                                    + " on approved list; matching services found");
+                        }
                     }
                 }
             }
@@ -837,20 +864,23 @@
 
     private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
         boolean removed = false;
-        final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId);
-        if (approvedByType != null) {
-            int M = approvedByType.size();
-            for (int j = 0; j < M; j++) {
-                final ArraySet<String> approved = approvedByType.valueAt(j);
-                int O = approved.size();
-                for (int k = O - 1; k >= 0; k--) {
-                    final String packageOrComponent = approved.valueAt(k);
-                    final String packageName = getPackageName(packageOrComponent);
-                    if (TextUtils.equals(pkg, packageName)) {
-                        approved.removeAt(k);
-                        if (DEBUG) {
-                            Slog.v(TAG, "Removing " + packageOrComponent
-                                    + " from approved list; uninstalled");
+        synchronized (mApproved) {
+            final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(
+                    uninstalledUserId);
+            if (approvedByType != null) {
+                int M = approvedByType.size();
+                for (int j = 0; j < M; j++) {
+                    final ArraySet<String> approved = approvedByType.valueAt(j);
+                    int O = approved.size();
+                    for (int k = O - 1; k >= 0; k--) {
+                        final String packageOrComponent = approved.valueAt(k);
+                        final String packageName = getPackageName(packageOrComponent);
+                        if (TextUtils.equals(pkg, packageName)) {
+                            approved.removeAt(k);
+                            if (DEBUG) {
+                                Slog.v(TAG, "Removing " + packageOrComponent
+                                        + " from approved list; uninstalled");
+                            }
                         }
                     }
                 }
@@ -887,17 +917,19 @@
 
         for (int i = 0; i < nUserIds; ++i) {
             final int userId = userIds.get(i);
-            final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
-            if (approvedLists != null) {
-                final int N = approvedLists.size();
-                for (int j = 0; j < N; j++) {
-                    ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
-                    if (approvedByUser == null) {
-                        approvedByUser = new ArraySet<>();
-                        componentsByUser.put(userId, approvedByUser);
+            synchronized (mApproved) {
+                final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
+                if (approvedLists != null) {
+                    final int N = approvedLists.size();
+                    for (int j = 0; j < N; j++) {
+                        ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
+                        if (approvedByUser == null) {
+                            approvedByUser = new ArraySet<>();
+                            componentsByUser.put(userId, approvedByUser);
+                        }
+                        approvedByUser.addAll(
+                                loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
                     }
-                    approvedByUser.addAll(
-                            loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
                 }
             }
         }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 976931c..d30895e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -25,9 +25,12 @@
 import static android.app.Notification.FLAG_ONGOING_EVENT;
 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
 import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
+import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED;
 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
 import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
 import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED;
+import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID;
+import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
@@ -398,7 +401,7 @@
 
     // for enabling and disabling notification pulse behavior
     boolean mScreenOn = true;
-    protected boolean mInCall = false;
+    protected boolean mInCallStateOffHook = false;
     boolean mNotificationPulseEnabled;
 
     private Uri mInCallNotificationUri;
@@ -1296,7 +1299,7 @@
                 mScreenOn = false;
                 updateNotificationPulse();
             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
-                mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
+                mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK
                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
                 updateNotificationPulse();
             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
@@ -1645,6 +1648,15 @@
                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
                 mRankingHandler.requestSort();
             }
+
+            @Override
+            void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {
+                Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED);
+                intent.setPackage(pkg);
+                intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id);
+                intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status);
+                getContext().sendBroadcastAsUser(intent, UserHandle.of(userId));
+            }
         });
         mPreferencesHelper = new PreferencesHelper(getContext(),
                 mPackageManagerClient,
@@ -5812,7 +5824,7 @@
                     }
                     if (DBG) Slog.v(TAG, "Interrupting!");
                     if (hasValidSound) {
-                        if (mInCall) {
+                        if (isInCall()) {
                             playInCallNotification();
                             beep = true;
                         } else {
@@ -5826,7 +5838,7 @@
                     final boolean ringerModeSilent =
                             mAudioManager.getRingerModeInternal()
                                     == AudioManager.RINGER_MODE_SILENT;
-                    if (!mInCall && hasValidVibrate && !ringerModeSilent) {
+                    if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
                         buzz = playVibration(record, vibration, hasValidSound);
                         if(buzz) {
                             mVibrateNotificationKey = key;
@@ -5914,7 +5926,7 @@
             return false;
         }
         // not if in call or the screen's on
-        if (mInCall || mScreenOn) {
+        if (isInCall() || mScreenOn) {
             return false;
         }
 
@@ -7015,7 +7027,7 @@
         }
 
         // Don't flash while we are in a call or screen is on
-        if (ledNotification == null || mInCall || mScreenOn) {
+        if (ledNotification == null || isInCall() || mScreenOn) {
             mNotificationLight.turnOff();
         } else {
             NotificationRecord.Light light = ledNotification.getLight();
@@ -7483,6 +7495,18 @@
         }
     }
 
+    private boolean isInCall() {
+        if (mInCallStateOffHook) {
+            return true;
+        }
+        int audioMode = mAudioManager.getMode();
+        if (audioMode == AudioManager.MODE_IN_CALL
+                || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
+            return true;
+        }
+        return false;
+    }
+
     public class NotificationAssistants extends ManagedServices {
         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
 
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index f81015d..ee948b2 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -16,6 +16,10 @@
 
 package com.android.server.notification;
 
+import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED;
+import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
+import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
+
 import android.app.AppOpsManager;
 import android.app.AutomaticZenRule;
 import android.app.Notification;
@@ -351,6 +355,12 @@
                             "Cannot update rules not owned by your condition provider");
                 }
             }
+            if (rule.enabled != automaticZenRule.isEnabled()) {
+                dispatchOnAutomaticRuleStatusChanged(mConfig.user, rule.pkg, ruleId,
+                        automaticZenRule.isEnabled()
+                                ? AUTOMATIC_RULE_STATUS_ENABLED : AUTOMATIC_RULE_STATUS_DISABLED);
+            }
+
             populateZenRule(automaticZenRule, rule, false);
             return setConfigLocked(newConfig, reason, rule.component, true);
         }
@@ -370,6 +380,8 @@
                 throw new SecurityException(
                         "Cannot delete rules not owned by your condition provider");
             }
+            dispatchOnAutomaticRuleStatusChanged(
+                    mConfig.user, rule.pkg, id, AUTOMATIC_RULE_STATUS_REMOVED);
             return setConfigLocked(newConfig, reason, null, true);
         }
     }
@@ -1120,6 +1132,13 @@
         }
     }
 
+    private void dispatchOnAutomaticRuleStatusChanged(int userId, String pkg, String id,
+            int status) {
+        for (Callback callback : mCallbacks) {
+            callback.onAutomaticRuleStatusChanged(userId, pkg, id, status);
+        }
+    }
+
     private ZenModeConfig readDefaultConfig(Resources resources) {
         XmlResourceParser parser = null;
         try {
@@ -1509,5 +1528,6 @@
         void onZenModeChanged() {}
         void onPolicyChanged() {}
         void onConsolidatedPolicyChanged() {}
+        void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {}
     }
 }
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index b604aa8..1f20968 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -237,14 +237,9 @@
             return fulfilledPolicies | IIdmap2.POLICY_OEM_PARTITION;
         }
 
-        // Check partitions for which there exists no policy so overlays on these partitions will
-        // not fulfill the system policy.
-        if (ai.isProductServices()) {
-            return fulfilledPolicies;
-        }
-
+        // System_ext partition (/system_ext) is considered as system
         // Check this last since every partition except for data is scanned as system in the PMS.
-        if (ai.isSystemApp()) {
+        if (ai.isSystemApp() || ai.isSystemExt()) {
             return fulfilledPolicies | IIdmap2.POLICY_SYSTEM_PARTITION;
         }
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 6f28675..934511b 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -296,22 +296,12 @@
      */
     private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName,
             final int userId, final int flags) {
-        final List<OverlayInfo> ois = new ArrayList<>();
+        final List<OverlayInfo> targetOverlays = mSettings.getOverlaysForTarget(targetPackageName,
+                userId);
 
-        // Framework overlays added first because order matters when resolving a resource
-        if (!"android".equals(targetPackageName)) {
-            ois.addAll(mSettings.getOverlaysForTarget("android", userId));
-        }
-
-        // Then add the targeted, non-framework overlays which have higher priority
-        ois.addAll(mSettings.getOverlaysForTarget(targetPackageName, userId));
-
-        final List<String> enabledBaseCodePaths = new ArrayList<>(ois.size());
-
+        // Update the state for any overlay that targets this package.
         boolean modified = false;
-        final int n = ois.size();
-        for (int i = 0; i < n; i++) {
-            final OverlayInfo oi = ois.get(i);
+        for (final OverlayInfo oi : targetOverlays) {
             final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName,
                     userId);
             if (overlayPackage == null) {
@@ -324,25 +314,39 @@
                     Slog.e(TAG, "failed to update settings", e);
                     modified |= mSettings.remove(oi.packageName, userId);
                 }
-
-                if (oi.isEnabled() && overlayPackage.applicationInfo != null) {
-                    enabledBaseCodePaths.add(overlayPackage.applicationInfo.getBaseCodePath());
-                }
             }
         }
 
         if (!modified) {
+            // Update the overlay paths of the target within package manager if necessary.
+            final List<String> enabledOverlayPaths = new ArrayList<>(targetOverlays.size());
+
+            // Framework overlays are first in the overlay paths of a package within PackageManager.
+            for (final OverlayInfo oi : mSettings.getOverlaysForTarget("android", userId)) {
+                if (oi.isEnabled()) {
+                    enabledOverlayPaths.add(oi.baseCodePath);
+                }
+            }
+
+            for (final OverlayInfo oi : targetOverlays) {
+                if (oi.isEnabled()) {
+                    enabledOverlayPaths.add(oi.baseCodePath);
+                }
+            }
+
+            // TODO(): Use getEnabledOverlayPaths(userId, targetPackageName) instead of
+            // resourceDirs if in the future resourceDirs contains APKs other than overlays
             PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, userId);
             ApplicationInfo appInfo = packageInfo == null ? null : packageInfo.applicationInfo;
             String[] resourceDirs = appInfo == null ? null : appInfo.resourceDirs;
 
             // If the lists aren't the same length, the enabled overlays have changed
-            if (ArrayUtils.size(resourceDirs) != enabledBaseCodePaths.size()) {
+            if (ArrayUtils.size(resourceDirs) != enabledOverlayPaths.size()) {
                 modified = true;
             } else if (resourceDirs != null) {
                 // If any element isn't equal, an overlay or the order of overlays has changed
                 for (int index = 0; index < resourceDirs.length; index++) {
-                    if (!resourceDirs[index].equals(enabledBaseCodePaths.get(index))) {
+                    if (!resourceDirs[index].equals(enabledOverlayPaths.get(index))) {
                         modified = true;
                         break;
                     }
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 9094e1b..e5a2e77 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -376,12 +376,12 @@
                 continue;
             }
 
-            // If the path is in /system, /vendor, /product or /product_services, ignore. It will
+            // If the path is in /system, /vendor, /product or /system_ext, ignore. It will
             // have been ota-dexopted into /data/ota and moved into the dalvik-cache already.
             if (pkg.codePath.startsWith("/system")
                     || pkg.codePath.startsWith("/vendor")
                     || pkg.codePath.startsWith("/product")
-                    || pkg.codePath.startsWith("/product_services")) {
+                    || pkg.codePath.startsWith("/system_ext")) {
                 continue;
             }
 
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
new file mode 100644
index 0000000..da45582
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -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.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+
+@VisibleForTesting
+interface PackageAbiHelper {
+    /**
+     * Derive and set 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);
+
+    /**
+     * 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
+     */
+    void setBundledAppAbisAndRoots(PackageParser.Package pkg,
+            PackageSetting pkgSetting);
+
+    /**
+     * 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}.
+     *
+     * 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)
+            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.
+     *
+     * 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.
+     *
+     * WARNING: This API enables modifying of the package.
+     * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
+     */
+    @Nullable
+    List<String> adjustCpuAbisForSharedUser(
+            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
+}
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
new file mode 100644
index 0000000..4ecc888
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -0,0 +1,542 @@
+/*
+ * 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 android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageParser.isApkFile;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
+import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
+import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
+import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
+
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.os.Build;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Trace;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.util.ArrayUtils;
+
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+
+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;
+        if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
+            codeRoot = Environment.getRootDirectory();
+        } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
+            codeRoot = Environment.getOemDirectory();
+        } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
+            codeRoot = Environment.getVendorDirectory();
+        } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+            codeRoot = Environment.getOdmDirectory();
+        } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
+            codeRoot = Environment.getProductDirectory();
+        } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
+            codeRoot = Environment.getSystemExtDirectory();
+        } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+            codeRoot = Environment.getOdmDirectory();
+        } else {
+            // Unrecognized code path; take its top real segment as the apk root:
+            // e.g. /something/app/blah.apk => /something
+            try {
+                File f = codePath.getCanonicalFile();
+                File parent = f.getParentFile();    // non-null because codePath is a file
+                File tmp;
+                while ((tmp = parent.getParentFile()) != null) {
+                    f = parent;
+                    parent = tmp;
+                }
+                codeRoot = f;
+                Slog.w(PackageManagerService.TAG, "Unrecognized code path "
+                        + codePath + " - using " + codeRoot);
+            } catch (IOException e) {
+                // Can't canonicalize the code path -- shenanigans?
+                Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
+                return Environment.getRootDirectory().getPath();
+            }
+        }
+        return codeRoot.getPath();
+    }
+
+    // Utility method that returns the relative package path with respect
+    // to the installation directory. Like say for /data/data/com.test-1.apk
+    // string com.test-1 is returned.
+    private static String deriveCodePathName(String codePath) {
+        if (codePath == null) {
+            return null;
+        }
+        final File codeFile = new File(codePath);
+        final String name = codeFile.getName();
+        if (codeFile.isDirectory()) {
+            return name;
+        } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
+            final int lastDot = name.lastIndexOf('.');
+            return name.substring(0, lastDot);
+        } else {
+            Slog.w(PackageManagerService.TAG, "Odd, " + codePath + " doesn't look like an APK");
+            return null;
+        }
+    }
+
+    private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
+            PackageManagerException {
+        if (copyRet < 0) {
+            if (copyRet != PackageManager.NO_NATIVE_LIBRARIES
+                    && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
+                throw new PackageManagerException(copyRet, message);
+            }
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6f9a918..4eddb930 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -23,6 +23,7 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
 import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
+import static android.content.pm.PackageParser.APEX_FILE_EXTENSION;
 import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
@@ -1484,7 +1485,29 @@
                     "Too many files for apex install");
         }
 
-        mResolvedBaseFile = addedFiles[0];
+        try {
+            resolveStageDirLocked();
+        } catch (IOException e) {
+            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
+                    "Failed to resolve stage location", e);
+        }
+
+        File addedFile = addedFiles[0]; // there is only one file
+
+        // Ensure file name has proper suffix
+        final String sourceName = addedFile.getName();
+        final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION)
+                ? sourceName
+                : sourceName + APEX_FILE_EXTENSION;
+        if (!FileUtils.isValidExtFilename(targetName)) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                    "Invalid filename: " + targetName);
+        }
+
+        final File targetFile = new File(mResolvedStageDir, targetName);
+        resolveAndStageFile(addedFile, targetFile);
+
+        mResolvedBaseFile = targetFile;
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5ab8ec3..ebbb193 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -37,11 +37,11 @@
 import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
@@ -90,17 +90,16 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
+import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
 
 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.LIB64_DIR_NAME;
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
 import static com.android.server.pm.ComponentResolver.RESOLVE_PRIORITY_SORTER;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
 import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
@@ -144,7 +143,6 @@
 import android.content.pm.FallbackCategoryProvider;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IDexModuleRegisterCallback;
-import android.content.pm.IOnPermissionsChangeListener;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageDeleteObserver2;
@@ -168,9 +166,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
 import android.content.pm.PackageManager.ModuleInfoFlags;
-import android.content.pm.PackageManager.PermissionWhitelistFlags;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageManagerInternal.CheckPermissionDelegate;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ActivityIntentInfo;
@@ -279,6 +275,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
@@ -291,7 +288,6 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.IntPair;
 import com.android.internal.util.Preconditions;
 import com.android.server.AttributeCache;
 import com.android.server.DeviceIdleController;
@@ -314,10 +310,8 @@
 import com.android.server.pm.dex.PackageDexUsage;
 import com.android.server.pm.dex.ViewCompiler;
 import com.android.server.pm.permission.BasePermission;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionsState;
 import com.android.server.security.VerityUtils;
 import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -434,7 +428,7 @@
     // user, but by default initialize to this.
     public static final boolean DEBUG_DEXOPT = false;
 
-    private static final boolean DEBUG_ABI_SELECTION = false;
+    static final boolean DEBUG_ABI_SELECTION = false;
     private static final boolean DEBUG_INSTANT = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_APP_DATA = false;
 
@@ -476,7 +470,7 @@
     static final int SCAN_AS_OEM = 1 << 19;
     static final int SCAN_AS_VENDOR = 1 << 20;
     static final int SCAN_AS_PRODUCT = 1 << 21;
-    static final int SCAN_AS_PRODUCT_SERVICES = 1 << 22;
+    static final int SCAN_AS_SYSTEM_EXT = 1 << 22;
     static final int SCAN_AS_ODM = 1 << 23;
 
     @IntDef(flag = true, prefix = { "SCAN_" }, value = {
@@ -580,12 +574,6 @@
 
     public static final String PLATFORM_PACKAGE_NAME = "android";
 
-    private static final String KILL_APP_REASON_GIDS_CHANGED =
-            "permission grant or revoke changed gids";
-
-    private static final String KILL_APP_REASON_PERMISSIONS_REVOKED =
-            "permissions revoked";
-
     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
 
     private static final String PACKAGE_SCHEME = "package";
@@ -594,7 +582,7 @@
 
     private static final String PRODUCT_OVERLAY_DIR = "/product/overlay";
 
-    private static final String PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay";
+    private static final String SYSTEM_EXT_OVERLAY_DIR = "/system_ext/overlay";
 
     private static final String ODM_OVERLAY_DIR = "/odm/overlay";
 
@@ -664,7 +652,8 @@
     private static final File sAppInstallDir =
             new File(Environment.getDataDirectory(), "app");
     /** Directory where installed application's 32-bit native libraries are copied. */
-    private static final File sAppLib32InstallDir =
+    @VisibleForTesting
+    static final File sAppLib32InstallDir =
             new File(Environment.getDataDirectory(), "app-lib");
 
     // ----------------------------------------------------------------
@@ -755,6 +744,30 @@
 
     private final ApexManager mApexManager;
 
+    private final Injector mInjector;
+
+    /**
+     * Unit tests will instantiate and / or extend to mock dependencies / behaviors.
+     */
+    @VisibleForTesting
+    static class Injector {
+        private final UserManagerInternal mUserManager;
+        private final PackageAbiHelper mAbiHelper;
+
+        Injector(UserManagerInternal userManager, PackageAbiHelper abiHelper) {
+            mUserManager = userManager;
+            mAbiHelper = abiHelper;
+        }
+
+        public UserManagerInternal getUserManager() {
+            return mUserManager;
+        }
+
+        public PackageAbiHelper getAbiHelper() {
+            return mAbiHelper;
+        }
+    }
+
     class PackageParserCallback implements PackageParser.Callback {
         @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -915,8 +928,6 @@
     private AtomicInteger mNextMoveId = new AtomicInteger();
     private final MoveCallbacks mMoveCallbacks;
 
-    private final OnPermissionChangeListeners mOnPermissionChangeListeners;
-
     // Cache of users who need badging.
     private final SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
 
@@ -960,8 +971,6 @@
     final SparseArray<IntentFilterVerificationState> mIntentFilterVerificationStates
             = new SparseArray<>();
 
-    // TODO remove this and go through mPermissonManager directly
-    final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
     // Internal interface for permission manager
     private final PermissionManagerServiceInternal mPermissionManager;
     // Public interface for permission manager
@@ -1004,18 +1013,6 @@
         void receiveVerificationResponse(int verificationId);
     }
 
-    @GuardedBy("mPackages")
-    private CheckPermissionDelegate mCheckPermissionDelegate;
-
-    @GuardedBy("mPackages")
-    private PackageManagerInternal.DefaultBrowserProvider mDefaultBrowserProvider;
-
-    @GuardedBy("mPackages")
-    private PackageManagerInternal.DefaultDialerProvider mDefaultDialerProvider;
-
-    @GuardedBy("mPackages")
-    private PackageManagerInternal.DefaultHomeProvider mDefaultHomeProvider;
-
     private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
         private Context mContext;
         private ComponentName mIntentFilterVerifierComponent;
@@ -1766,86 +1763,6 @@
         }
     }
 
-    private PermissionCallback mPermissionCallback = new PermissionCallback() {
-        @Override
-        public void onGidsChanged(int appId, @UserIdInt int userId) {
-            mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED));
-        }
-
-        @Override
-        public void onPermissionGranted(int uid, @UserIdInt int userId) {
-            mOnPermissionChangeListeners.onPermissionsChanged(uid);
-
-            // Not critical; if this is lost, the application has to request again.
-            synchronized (mPackages) {
-                mSettings.writeRuntimePermissionsForUserLPr(userId, false);
-            }
-        }
-
-        @Override
-        public void onInstallPermissionGranted() {
-            synchronized (mPackages) {
-                scheduleWriteSettingsLocked();
-            }
-        }
-
-        @Override
-        public void onPermissionRevoked(int uid, @UserIdInt int userId) {
-            mOnPermissionChangeListeners.onPermissionsChanged(uid);
-
-            synchronized (mPackages) {
-                // Critical; after this call the application should never have the permission
-                mSettings.writeRuntimePermissionsForUserLPr(userId, true);
-            }
-
-            final int appId = UserHandle.getAppId(uid);
-            killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
-        }
-
-        @Override
-        public void onInstallPermissionRevoked() {
-            synchronized (mPackages) {
-                scheduleWriteSettingsLocked();
-            }
-        }
-
-        @Override
-        public void onPermissionUpdated(@UserIdInt int[] updatedUserIds, boolean sync) {
-            synchronized (mPackages) {
-                for (int userId : updatedUserIds) {
-                    mSettings.writeRuntimePermissionsForUserLPr(userId, sync);
-                }
-            }
-        }
-
-        @Override
-        public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
-                int uid) {
-            onPermissionUpdated(updatedUserIds, sync);
-            mOnPermissionChangeListeners.onPermissionsChanged(uid);
-        }
-
-        @Override
-        public void onInstallPermissionUpdated() {
-            synchronized (mPackages) {
-                scheduleWriteSettingsLocked();
-            }
-        }
-
-        @Override
-        public void onInstallPermissionUpdatedNotifyListener(int uid) {
-            onInstallPermissionUpdated();
-            mOnPermissionChangeListeners.onPermissionsChanged(uid);
-        }
-
-        @Override
-        public void onPermissionRemoved() {
-            synchronized (mPackages) {
-                mSettings.writeLPr();
-            }
-        }
-    };
-
     private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
             boolean killApp, boolean virtualPreload,
             String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
@@ -1866,8 +1783,7 @@
                     && !whitelistedRestrictedPermissions.isEmpty()) {
                 mPermissionManager.setWhitelistedRestrictedPermissions(
                         res.pkg, res.newUsers, whitelistedRestrictedPermissions,
-                        Process.myUid(), PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER,
-                        mPermissionCallback);
+                        Process.myUid(), FLAG_PERMISSION_WHITELIST_INSTALLER);
             }
 
             // Now that we successfully installed the package, grant runtime
@@ -1878,8 +1794,7 @@
             if (grantPermissions) {
                 final int callingUid = Binder.getCallingUid();
                 mPermissionManager.grantRequestedRuntimePermissions(
-                        res.pkg, res.newUsers, grantedPermissions, callingUid,
-                        mPermissionCallback);
+                        res.pkg, res.newUsers, grantedPermissions, callingUid);
             }
 
             final String installerPackageName =
@@ -1895,7 +1810,7 @@
             if (res.pkg.parentPackage != null) {
                 final int callingUid = Binder.getCallingUid();
                 mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage(
-                        res.pkg, callingUid, mPermissionCallback);
+                        res.pkg, callingUid);
             }
 
             synchronized (mPackages) {
@@ -2063,7 +1978,7 @@
                             final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
                             if (pkgSetting.getInstallReason(userId)
                                     != PackageManager.INSTALL_REASON_DEVICE_RESTORE) {
-                                setDefaultBrowserAsyncLPw(null, userId);
+                                mPermissionManager.setDefaultBrowser(null, true, true, userId);
                             }
                         }
                     }
@@ -2116,8 +2031,8 @@
             // survive long enough to benefit of background optimizations.
             for (int userId : firstUserIds) {
                 PackageInfo info = getPackageInfo(packageName, /*flags*/ 0, userId);
-                // There's a race currently where some install events may interleave with an uninstall.
-                // This can lead to package info being null (b/36642664).
+                // There's a race currently where some install events may interleave with an
+                // uninstall. This can lead to package info being null (b/36642664).
                 if (info != null) {
                     mDexManager.notifyPackageInstalled(info, userId);
                 }
@@ -2187,6 +2102,7 @@
      * external/removable/unprotected storage.
      * @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
      * corresponding {@link StorageEnum} storage type value if it is.
+     * corresponding {@link StorageEnum} storage type value if it is.
      */
     private static int getPackageExternalStorageType(VolumeInfo packageVolume,
             boolean packageIsExternal) {
@@ -2445,11 +2361,14 @@
                     mPackages /*externalLock*/);
             mPermissionManagerService =
                     (IPermissionManager) ServiceManager.getService("permissionmgr");
-            mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
             mSettings = new Settings(Environment.getDataDirectory(),
                     mPermissionManager.getPermissionSettings(), mPackages);
         }
         }
+
+        // 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());
         // CHECKSTYLE:ON IndentationCheck
         t.traceEnd();
 
@@ -2497,9 +2416,6 @@
 
         mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);
 
-        mOnPermissionChangeListeners = new OnPermissionChangeListeners(
-                FgThread.get().getLooper());
-
         getDefaultDisplayMetrics(context, mMetrics);
 
         t.traceBegin("get system config");
@@ -2640,7 +2556,7 @@
                 scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
             }
 
-            // Collect vendor/product/product_services overlay packages. (Do this before scanning
+            // Collect vendor/product/system_ext overlay packages. (Do this before scanning
             // any apps.)
             // For security and version matching reason, only consider overlay packages if they
             // reside in the right directory.
@@ -2658,12 +2574,12 @@
                     | SCAN_AS_SYSTEM
                     | SCAN_AS_PRODUCT,
                     0);
-            scanDirTracedLI(new File(PRODUCT_SERVICES_OVERLAY_DIR),
+            scanDirTracedLI(new File(SYSTEM_EXT_OVERLAY_DIR),
                     mDefParseFlags
                     | PackageParser.PARSE_IS_SYSTEM_DIR,
                     scanFlags
                     | SCAN_AS_SYSTEM
-                    | SCAN_AS_PRODUCT_SERVICES,
+                    | SCAN_AS_SYSTEM_EXT,
                     0);
             scanDirTracedLI(new File(ODM_OVERLAY_DIR),
                     mDefParseFlags
@@ -2821,37 +2737,37 @@
                     | SCAN_AS_PRODUCT,
                     0);
 
-            // Collected privileged /product_services packages.
-            File privilegedProductServicesAppDir =
-                    new File(Environment.getProductServicesDirectory(), "priv-app");
+            // Collected privileged /system_ext packages.
+            File privilegedSystemExtAppDir =
+                    new File(Environment.getSystemExtDirectory(), "priv-app");
             try {
-                privilegedProductServicesAppDir =
-                        privilegedProductServicesAppDir.getCanonicalFile();
+                privilegedSystemExtAppDir =
+                        privilegedSystemExtAppDir.getCanonicalFile();
             } catch (IOException e) {
                 // failed to look up canonical path, continue with original one
             }
-            scanDirTracedLI(privilegedProductServicesAppDir,
+            scanDirTracedLI(privilegedSystemExtAppDir,
                     mDefParseFlags
                     | PackageParser.PARSE_IS_SYSTEM_DIR,
                     scanFlags
                     | SCAN_AS_SYSTEM
-                    | SCAN_AS_PRODUCT_SERVICES
+                    | SCAN_AS_SYSTEM_EXT
                     | SCAN_AS_PRIVILEGED,
                     0);
 
-            // Collect ordinary /product_services packages.
-            File productServicesAppDir = new File(Environment.getProductServicesDirectory(), "app");
+            // Collect ordinary /system_ext packages.
+            File systemExtAppDir = new File(Environment.getSystemExtDirectory(), "app");
             try {
-                productServicesAppDir = productServicesAppDir.getCanonicalFile();
+                systemExtAppDir = systemExtAppDir.getCanonicalFile();
             } catch (IOException e) {
                 // failed to look up canonical path, continue with original one
             }
-            scanDirTracedLI(productServicesAppDir,
+            scanDirTracedLI(systemExtAppDir,
                     mDefParseFlags
                     | PackageParser.PARSE_IS_SYSTEM_DIR,
                     scanFlags
                     | SCAN_AS_SYSTEM
-                    | SCAN_AS_PRODUCT_SERVICES,
+                    | SCAN_AS_SYSTEM_EXT,
                     0);
 
             // Prune any system packages that no longer exist.
@@ -3081,23 +2997,23 @@
                                     scanFlags
                                     | SCAN_AS_SYSTEM
                                     | SCAN_AS_PRODUCT;
-                        } else if (FileUtils.contains(privilegedProductServicesAppDir, scanFile)) {
+                        } else if (FileUtils.contains(privilegedSystemExtAppDir, scanFile)) {
                             reparseFlags =
                                     mDefParseFlags |
                                     PackageParser.PARSE_IS_SYSTEM_DIR;
                             rescanFlags =
                                     scanFlags
                                     | SCAN_AS_SYSTEM
-                                    | SCAN_AS_PRODUCT_SERVICES
+                                    | SCAN_AS_SYSTEM_EXT
                                     | SCAN_AS_PRIVILEGED;
-                        } else if (FileUtils.contains(productServicesAppDir, scanFile)) {
+                        } else if (FileUtils.contains(systemExtAppDir, scanFile)) {
                             reparseFlags =
                                     mDefParseFlags |
                                     PackageParser.PARSE_IS_SYSTEM_DIR;
                             rescanFlags =
                                     scanFlags
                                     | SCAN_AS_SYSTEM
-                                    | SCAN_AS_PRODUCT_SERVICES;
+                                    | SCAN_AS_SYSTEM_EXT;
                         } else {
                             Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                             continue;
@@ -3161,7 +3077,8 @@
                 // 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 =
-                        adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
+                        mInjector.getAbiHelper().adjustCpuAbisForSharedUser(
+                                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);
@@ -3200,8 +3117,7 @@
                         + mSdkVersion + "; regranting permissions for internal storage");
             }
             mPermissionManager.updateAllPermissions(
-                    StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
-                    mPermissionCallback);
+                    StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated);
             ver.sdkVersion = mSdkVersion;
 
             // If this is the first boot or an update from pre-M, and it is a normal
@@ -3497,8 +3413,7 @@
                     } catch (PackageManagerException e) {
                         Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
                     }
-                    mPermissionManager.updatePermissions(pkg.packageName, pkg, mPackages.values(),
-                            mPermissionCallback);
+                    mPermissionManager.updatePermissions(pkg.packageName, pkg);
                     mSettings.writeLPr();
                 }
             } catch (PackageManagerException e) {
@@ -4569,55 +4484,6 @@
         return -1;
     }
 
-    /**
-     * Check if any package sharing/holding a uid has a low enough target SDK.
-     *
-     * @param uid The uid of the packages
-     * @param higherTargetSDK The target SDK that might be higher than the searched package
-     *
-     * @return {@code true} if there is a package sharing/holding the uid with
-     * {@code package.targetSDK < higherTargetSDK}
-     */
-    private boolean hasTargetSdkInUidLowerThan(int uid, int higherTargetSDK) {
-        int userId = UserHandle.getUserId(uid);
-
-        synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
-            if (obj == null) {
-                return false;
-            }
-
-            if (obj instanceof PackageSetting) {
-                final PackageSetting ps = (PackageSetting) obj;
-
-                if (!ps.getInstalled(userId)) {
-                    return false;
-                }
-
-                return ps.pkg.applicationInfo.targetSdkVersion < higherTargetSDK;
-            } else if (obj instanceof SharedUserSetting) {
-                final SharedUserSetting sus = (SharedUserSetting) obj;
-
-                final int numPkgs = sus.packages.size();
-                for (int i = 0; i < numPkgs; i++) {
-                    final PackageSetting ps = sus.packages.valueAt(i);
-
-                    if (!ps.getInstalled(userId)) {
-                        continue;
-                    }
-
-                    if (ps.pkg.applicationInfo.targetSdkVersion < higherTargetSDK) {
-                        return true;
-                    }
-                }
-
-                return false;
-            } else {
-                return false;
-            }
-        }
-    }
-
     @Override
     public int[] getPackageGids(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
@@ -5627,79 +5493,26 @@
         }
     }
 
+    // NOTE: Can't remove due to unsupported app usage
     @Override
     public int checkPermission(String permName, String pkgName, int userId) {
-        final CheckPermissionDelegate checkPermissionDelegate;
-        synchronized (mPackages) {
-            if (mCheckPermissionDelegate == null)  {
-                return checkPermissionImpl(permName, pkgName, userId);
-            }
-            checkPermissionDelegate = mCheckPermissionDelegate;
-        }
-        return checkPermissionDelegate.checkPermission(permName, pkgName, userId,
-                PackageManagerService.this::checkPermissionImpl);
+        try {
+            // Because this is accessed via the package manager service AIDL,
+            // go through the permission manager service AIDL
+            return mPermissionManagerService.checkPermission(permName, pkgName, userId);
+        } catch (RemoteException ignore) { }
+        return PackageManager.PERMISSION_DENIED;
     }
 
-    private int checkPermissionImpl(String permName, String pkgName, int userId) {
-        return mPermissionManager.checkPermission(permName, pkgName, getCallingUid(), userId);
-    }
-
+    // NOTE: Can't remove without a major refactor. Keep around for now.
     @Override
     public int checkUidPermission(String permName, int uid) {
-        final CheckPermissionDelegate checkPermissionDelegate;
-        synchronized (mPackages) {
-            if (mCheckPermissionDelegate == null)  {
-                return checkUidPermissionImpl(permName, uid);
-            }
-            checkPermissionDelegate = mCheckPermissionDelegate;
-        }
-        return checkPermissionDelegate.checkUidPermission(permName, uid,
-                PackageManagerService.this::checkUidPermissionImpl);
-    }
-
-    private int checkUidPermissionImpl(String permName, int uid) {
-        synchronized (mPackages) {
-            final String[] packageNames = getPackagesForUid(uid);
-            PackageParser.Package pkg = null;
-            final int N = packageNames == null ? 0 : packageNames.length;
-            for (int i = 0; pkg == null && i < N; i++) {
-                pkg = mPackages.get(packageNames[i]);
-            }
-            return mPermissionManager.checkUidPermission(permName, pkg, uid, getCallingUid());
-        }
-    }
-
-    @Override
-    public boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId) {
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "isPermissionRevokedByPolicy for user " + userId);
-        }
-
-        if (checkPermission(permission, packageName, userId)
-                == PackageManager.PERMISSION_GRANTED) {
-            return false;
-        }
-
-        final int callingUid = Binder.getCallingUid();
-        if (getInstantAppPackageName(callingUid) != null) {
-            if (!isCallerSameApp(packageName, callingUid)) {
-                return false;
-            }
-        } else {
-            if (isInstantApp(packageName, userId)) {
-                return false;
-            }
-        }
-
-        final long identity = Binder.clearCallingIdentity();
         try {
-            final int flags = getPermissionFlags(permission, packageName, userId);
-            return (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0;
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
+            // Because this is accessed via the package manager service AIDL,
+            // go through the permission manager service AIDL
+            return mPermissionManagerService.checkUidPermission(permName, uid);
+        } catch (RemoteException ignore) { }
+        return PackageManager.PERMISSION_DENIED;
     }
 
     @Override
@@ -5747,395 +5560,14 @@
         } catch (RemoteException ignore) { }
     }
 
+    // NOTE: Can't remove due to unsupported app usage
     @Override
     public void grantRuntimePermission(String packageName, String permName, final int userId) {
-        boolean overridePolicy = (checkUidPermission(
-                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, Binder.getCallingUid())
-                == PackageManager.PERMISSION_GRANTED);
-
-        mPermissionManager.grantRuntimePermission(permName, packageName, overridePolicy,
-                getCallingUid(), userId, mPermissionCallback);
-    }
-
-    @Override
-    public void revokeRuntimePermission(String packageName, String permName, int userId) {
-        boolean overridePolicy = (checkUidPermission(
-                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, Binder.getCallingUid())
-                == PackageManager.PERMISSION_GRANTED);
-
-        mPermissionManager.revokeRuntimePermission(permName, packageName, overridePolicy,
-                userId, mPermissionCallback);
-    }
-
-    @Override
-    public void resetRuntimePermissions() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
-                "revokeRuntimePermission");
-
-        int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "resetRuntimePermissions");
-        }
-
-        synchronized (mPackages) {
-            mPermissionManager.updateAllPermissions(
-                    StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
-                    mPermissionCallback);
-            for (int userId : UserManagerService.getInstance().getUserIds()) {
-                final int packageCount = mPackages.size();
-                for (int i = 0; i < packageCount; i++) {
-                    PackageParser.Package pkg = mPackages.valueAt(i);
-                    if (!(pkg.mExtras instanceof PackageSetting)) {
-                        continue;
-                    }
-                    PackageSetting ps = (PackageSetting) pkg.mExtras;
-                    resetUserChangesToRuntimePermissionsAndFlagsLPw(ps, userId);
-                }
-            }
-        }
-    }
-
-    @Override
-    public int getPermissionFlags(String permName, String packageName, int userId) {
-        return mPermissionManager.getPermissionFlags(
-                permName, packageName, getCallingUid(), userId);
-    }
-
-    @Override
-    public void updatePermissionFlags(String permName, String packageName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
-        int callingUid = getCallingUid();
-        boolean overridePolicy = false;
-
-        if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) {
-            long callingIdentity = Binder.clearCallingIdentity();
-            try {
-                if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0) {
-                    if (checkAdjustPolicyFlagPermission) {
-                        mContext.enforceCallingOrSelfPermission(
-                                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
-                                "Need " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY
-                                        + " to change policy flags");
-                    } else if (!hasTargetSdkInUidLowerThan(callingUid, Build.VERSION_CODES.Q)) {
-                        throw new IllegalArgumentException(
-                                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " needs "
-                                        + " to be checked for packages targeting "
-                                        + Build.VERSION_CODES.Q + " or later when changing policy "
-                                        + "flags");
-                    }
-
-                    overridePolicy = true;
-                }
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
-            }
-        }
-
-        mPermissionManager.updatePermissionFlags(
-                permName, packageName, flagMask, flagValues, callingUid, userId,
-                overridePolicy, mPermissionCallback);
-    }
-
-    /**
-     * Update the permission flags for all packages and runtime permissions of a user in order
-     * to allow device or profile owner to remove POLICY_FIXED.
-     */
-    @Override
-    public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) {
-        synchronized (mPackages) {
-            final boolean changed = mPermissionManager.updatePermissionFlagsForAllApps(
-                    flagMask, flagValues, getCallingUid(), userId, mPackages.values(),
-                    mPermissionCallback);
-            if (changed) {
-                mSettings.writeRuntimePermissionsForUserLPr(userId, false);
-            }
-        }
-    }
-
-    @Override
-    public @Nullable List<String> getWhitelistedRestrictedPermissions(@NonNull String packageName,
-            @PermissionWhitelistFlags int whitelistFlags, @UserIdInt int userId) {
-        Preconditions.checkNotNull(packageName);
-        Preconditions.checkFlagsArgument(whitelistFlags,
-                PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                        | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
-        Preconditions.checkArgumentNonNegative(userId, null);
-
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS,
-                    "getWhitelistedRestrictedPermissions for user " + userId);
-        }
-
-        final PackageParser.Package pkg;
-
-        synchronized (mPackages) {
-            final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
-            if (packageSetting == null) {
-                Slog.w(TAG, "Unknown package: " + packageName);
-                return null;
-            }
-
-            pkg = packageSetting.pkg;
-
-            final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
-                    Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
-                            == PackageManager.PERMISSION_GRANTED;
-            final PackageSetting installerPackageSetting = mSettings.mPackages.get(
-                    packageSetting.installerPackageName);
-            final boolean isCallerInstallerOnRecord = installerPackageSetting != null
-                    && UserHandle.isSameApp(installerPackageSetting.appId, Binder.getCallingUid());
-
-            if ((whitelistFlags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
-                    && !isCallerPrivileged) {
-                throw new SecurityException("Querying system whitelist requires "
-                        + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
-            }
-
-            if ((whitelistFlags & (PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                    | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) != 0) {
-                if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
-                    throw new SecurityException("Querying upgrade or installer whitelist"
-                            + " requires being installer on record or "
-                            + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
-                }
-            }
-
-            if (filterAppAccessLPr(packageSetting, Binder.getCallingUid(),
-                    UserHandle.getCallingUserId())) {
-                return null;
-            }
-        }
-
-        final long identity = Binder.clearCallingIdentity();
         try {
-            return mPermissionManager.getWhitelistedRestrictedPermissions(
-                    pkg, whitelistFlags, userId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
-            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags,
-            @UserIdInt int userId) {
-        // Other argument checks are done in get/setWhitelistedRestrictedPermissions
-        Preconditions.checkNotNull(permission);
-
-        if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permission)) {
-            return false;
-        }
-
-        List<String> permissions = getWhitelistedRestrictedPermissions(packageName,
-                whitelistFlags, userId);
-        if (permissions == null) {
-            permissions = new ArrayList<>(1);
-        }
-        if (permissions.indexOf(permission) < 0) {
-            permissions.add(permission);
-            return setWhitelistedRestrictedPermissions(packageName, permissions,
-                    whitelistFlags, userId);
-        }
-        return false;
-    }
-
-    private boolean checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(
-            @NonNull String permission) {
-        synchronized (mPackages) {
-            final BasePermission bp = mPermissionManager.getPermissionTEMP(permission);
-            if (bp == null) {
-                Slog.w(TAG, "No such permissions: " + permission);
-                return false;
-            }
-            if (bp.isHardOrSoftRestricted() && bp.isImmutablyRestricted()
-                    && mContext.checkCallingOrSelfPermission(
-                    Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
-                    != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Cannot modify whitelisting of an immutably "
-                        + "restricted permission: " + permission);
-            }
-            return true;
-        }
-    }
-
-    @Override
-    public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
-            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags,
-            @UserIdInt int userId) {
-        // Other argument checks are done in get/setWhitelistedRestrictedPermissions
-        Preconditions.checkNotNull(permission);
-
-        if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permission)) {
-            return false;
-        }
-
-        final List<String> permissions = getWhitelistedRestrictedPermissions(packageName,
-                whitelistFlags, userId);
-        if (permissions != null && permissions.remove(permission)) {
-            return setWhitelistedRestrictedPermissions(packageName, permissions,
-                    whitelistFlags, userId);
-        }
-        return false;
-    }
-
-    private boolean setWhitelistedRestrictedPermissions(@NonNull String packageName,
-            @Nullable List<String> permissions, @PermissionWhitelistFlags int whitelistFlag,
-            @UserIdInt int userId) {
-        Preconditions.checkNotNull(packageName);
-        Preconditions.checkFlagsArgument(whitelistFlag,
-                PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                        | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
-        Preconditions.checkArgument(Integer.bitCount(whitelistFlag) == 1);
-        Preconditions.checkArgumentNonNegative(userId, null);
-
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingOrSelfPermission(
-                    Manifest.permission.INTERACT_ACROSS_USERS,
-                    "setWhitelistedRestrictedPermissions for user " + userId);
-        }
-
-        final PackageParser.Package pkg;
-
-        synchronized (mPackages) {
-            final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
-            if (packageSetting == null) {
-                Slog.w(TAG, "Unknown package: " + packageName);
-                return false;
-            }
-
-            pkg = packageSetting.pkg;
-
-            final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
-                    Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
-                            == PackageManager.PERMISSION_GRANTED;
-            final PackageSetting installerPackageSetting = mSettings.mPackages.get(
-                    packageSetting.installerPackageName);
-            final boolean isCallerInstallerOnRecord = installerPackageSetting != null
-                    && UserHandle.isSameApp(installerPackageSetting.appId, Binder.getCallingUid());
-
-            if ((whitelistFlag & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
-                    && !isCallerPrivileged) {
-                throw new SecurityException("Modifying system whitelist requires "
-                        + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
-            }
-
-            if ((whitelistFlag & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
-                if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
-                    throw new SecurityException("Modifying upgrade whitelist requires"
-                            + " being installer on record or "
-                            + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
-                }
-                final List<String> whitelistedPermissions = getWhitelistedRestrictedPermissions(
-                        packageName, whitelistFlag, userId);
-                if (permissions == null || permissions.isEmpty()) {
-                    if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
-                        return true;
-                    }
-                } else {
-                    // Only the system can add and remove while the installer can only remove.
-                    final int permissionCount = permissions.size();
-                    for (int i = 0; i < permissionCount; i++) {
-                        if ((whitelistedPermissions == null
-                                || !whitelistedPermissions.contains(permissions.get(i)))
-                                && !isCallerPrivileged) {
-                            throw new SecurityException("Adding to upgrade whitelist requires"
-                                    + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
-                        }
-                    }
-                }
-            }
-
-            if ((whitelistFlag & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
-                if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
-                    throw new SecurityException("Modifying installer whitelist requires"
-                            + " being installer on record or "
-                            + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
-                }
-            }
-
-            if (filterAppAccessLPr(packageSetting, Binder.getCallingUid(),
-                    UserHandle.getCallingUserId())) {
-                return false;
-            }
-        }
-
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            mPermissionManager.setWhitelistedRestrictedPermissions(pkg,
-                    new int[]{userId}, permissions, Process.myUid(), whitelistFlag,
-                    mPermissionCallback);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-
-        return true;
-    }
-
-    @Override
-    public boolean shouldShowRequestPermissionRationale(String permissionName,
-            String packageName, int userId) {
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "canShowRequestPermissionRationale for user " + userId);
-        }
-
-        final int uid = getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId);
-        if (UserHandle.getAppId(getCallingUid()) != UserHandle.getAppId(uid)) {
-            return false;
-        }
-
-        if (checkPermission(permissionName, packageName, userId)
-                == PackageManager.PERMISSION_GRANTED) {
-            return false;
-        }
-
-        final int flags;
-
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            flags = getPermissionFlags(permissionName,
-                    packageName, userId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-
-        final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
-                | PackageManager.FLAG_PERMISSION_POLICY_FIXED
-                | PackageManager.FLAG_PERMISSION_USER_FIXED;
-
-        if ((flags & fixedFlags) != 0) {
-            return false;
-        }
-
-        return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
-    }
-
-    @Override
-    public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
-        mContext.enforceCallingOrSelfPermission(
-                Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS,
-                "addOnPermissionsChangeListener");
-
-        synchronized (mPackages) {
-            mOnPermissionChangeListeners.addListenerLocked(listener);
-        }
-    }
-
-    @Override
-    public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
-        if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-            throw new SecurityException("Instant applications don't have access to this method");
-        }
-        synchronized (mPackages) {
-            mOnPermissionChangeListeners.removeListenerLocked(listener);
-        }
+            // Because this is accessed via the package manager service AIDL,
+            // go through the permission manager service AIDL
+            mPermissionManagerService.grantRuntimePermission(packageName, permName, userId);
+        } catch (RemoteException ignore) { }
     }
 
     @Override
@@ -6300,29 +5732,6 @@
     }
 
     /**
-     * This method should typically only be used when granting or revoking
-     * permissions, since the app may immediately restart after this call.
-     * <p>
-     * If you're doing surgery on app code/data, use {@link PackageFreezer} to
-     * guard your work against the app being relaunched.
-     */
-    private void killUid(int appId, int userId, String reason) {
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            IActivityManager am = ActivityManager.getService();
-            if (am != null) {
-                try {
-                    am.killUid(appId, userId, reason);
-                } catch (RemoteException e) {
-                    /* ignore - same process */
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    /**
      * If the database version for this type of package (internal storage or
      * external storage) is less than the version where package signatures
      * were updated, return true.
@@ -7820,7 +7229,8 @@
                 } else {
                     // Browser/generic handling case.  If there's a default browser, go straight
                     // to that (but only if there is no other higher-priority match).
-                    final String defaultBrowserPackageName = getDefaultBrowserPackageName(userId);
+                    final String defaultBrowserPackageName =
+                            mPermissionManager.getDefaultBrowser(userId);
                     int maxMatchPrio = 0;
                     ResolveInfo defaultBrowserMatch = null;
                     final int numCandidates = matchAllList.size();
@@ -9411,7 +8821,8 @@
                             null /* originalPkgSetting */, null, parseFlags, scanFlags,
                             (pkg == mPlatformPackage), user);
                     applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
-                    final ScanResult scanResult = scanPackageOnlyLI(request, mFactoryTest, -1L);
+                    final ScanResult scanResult =
+                            scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
                     if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
                         scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
                     }
@@ -9870,16 +9281,6 @@
     }
 
     @GuardedBy("mPackages")
-    public CheckPermissionDelegate getCheckPermissionDelegateLocked() {
-        return mCheckPermissionDelegate;
-    }
-
-    @GuardedBy("mPackages")
-    public void setCheckPermissionDelegateLocked(CheckPermissionDelegate delegate) {
-        mCheckPermissionDelegate = delegate;
-    }
-
-    @GuardedBy("mPackages")
     private void notifyPackageUseLocked(String packageName, int reason) {
         final PackageParser.Package p = mPackages.get(packageName);
         if (p == null) {
@@ -10781,7 +10182,8 @@
     }
 
     /** The result of a package scan. */
-    private static class ScanResult {
+    @VisibleForTesting
+    static class ScanResult {
         /** The request that initiated the scan that produced this result. */
         public final ScanRequest request;
         /** Whether or not the package scan was successful */
@@ -10820,7 +10222,8 @@
     }
 
     /** A package to be scanned */
-    private static class ScanRequest {
+    @VisibleForTesting
+    static class ScanRequest {
         /** The parsed package */
         @NonNull public final PackageParser.Package pkg;
         /** The package this package replaces */
@@ -10884,7 +10287,7 @@
      * <li>{@link #SCAN_AS_OEM}</li>
      * <li>{@link #SCAN_AS_VENDOR}</li>
      * <li>{@link #SCAN_AS_PRODUCT}</li>
-     * <li>{@link #SCAN_AS_PRODUCT_SERVICES}</li>
+     * <li>{@link #SCAN_AS_SYSTEM_EXT}</li>
      * <li>{@link #SCAN_AS_INSTANT_APP}</li>
      * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li>
      * <li>{@link #SCAN_AS_ODM}</li>
@@ -10921,8 +10324,8 @@
                 scanFlags |= SCAN_AS_PRODUCT;
             }
             if ((systemPkgSetting.pkgPrivateFlags
-                    & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0) {
-                scanFlags |= SCAN_AS_PRODUCT_SERVICES;
+                    & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0) {
+                scanFlags |= SCAN_AS_SYSTEM_EXT;
             }
             if ((systemPkgSetting.pkgPrivateFlags
                     & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) {
@@ -11013,7 +10416,7 @@
                     pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
                     originalPkgSetting, realPkgName, parseFlags, scanFlags,
                     (pkg == mPlatformPackage), user);
-            return scanPackageOnlyLI(request, mFactoryTest, currentTime);
+            return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
         }
     }
 
@@ -11239,15 +10642,21 @@
      * method potentially modifies a live {@link PackageSetting} object representing
      * the package being scanned. This will be resolved in the future.
      *
+     * @param injector injector for acquiring dependencies
      * @param request Information about the package to be scanned
      * @param isUnderFactoryTest Whether or not the device is under factory test
      * @param currentTime The current time, in millis
      * @return The results of the scan
      */
     @GuardedBy("mInstallLock")
-    private static @NonNull ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+    @VisibleForTesting
+    @NonNull
+    static ScanResult scanPackageOnlyLI(@NonNull ScanRequest request,
+            Injector injector,
             boolean isUnderFactoryTest, long currentTime)
-                    throws PackageManagerException {
+            throws PackageManagerException {
+        final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
+        final UserManagerInternal userManager = injector.getUserManager();
         final PackageParser.Package pkg = request.pkg;
         PackageSetting pkgSetting = request.pkgSetting;
         final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
@@ -11353,7 +10762,7 @@
         if (!createNewPackage) {
             final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
             final boolean fullApp = (scanFlags & SCAN_AS_FULL_APP) != 0;
-            setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+            setInstantAppForUser(userManager, pkgSetting, userId, instantApp, fullApp);
         }
         // TODO(patb): see if we can do away with disabled check here.
         if (disabledPkgSetting != null
@@ -11399,7 +10808,7 @@
             if (needToDeriveAbi) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
                 final boolean extractNativeLibs = !pkg.isLibrary();
-                derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
+                packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
                 // Some system apps still use directory structure for native libraries
@@ -11407,8 +10816,8 @@
                 // structure. Try to detect abi based on directory structure.
                 if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
                         pkg.applicationInfo.primaryCpuAbi == null) {
-                    setBundledAppAbisAndRoots(pkg, pkgSetting);
-                    setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                    packageAbiHelper.setBundledAppAbisAndRoots(pkg, pkgSetting);
+                    packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
                 }
             } else {
                 // This is not a first boot or an upgrade, don't bother deriving the
@@ -11417,7 +10826,7 @@
                 pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
                 pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
 
-                setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+                packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
 
                 if (DEBUG_ABI_SELECTION) {
                     Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
@@ -11438,7 +10847,7 @@
             // 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).
-            setNativeLibraryPaths(pkg, sAppLib32InstallDir);
+            packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
         }
 
         // This is a special case for the "system" package, where the ABI is
@@ -11492,8 +10901,8 @@
             // 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 =
-                    adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
+            changedAbiCodePath = packageAbiHelper.adjustCpuAbisForSharedUser(
+                            pkgSetting.sharedUser.packages, pkg);
         }
 
         if (isUnderFactoryTest && pkg.requestedPermissions.contains(
@@ -11700,8 +11109,8 @@
             pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT;
         }
 
-        if ((scanFlags & SCAN_AS_PRODUCT_SERVICES) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES;
+        if ((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) {
+            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT;
         }
 
         if ((scanFlags & SCAN_AS_ODM) != 0) {
@@ -12336,271 +11745,13 @@
 
                 AsyncTask.execute(() ->
                         mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
-                                allPackageNames, mPermissionCallback));
+                                allPackageNames));
             }
         }
 
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
-    /**
-     * 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}.
-     *
-     * If {@code extractLibs} is true, native libraries are extracted from the app if required.
-     */
-    private static 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, sAppLib32InstallDir);
-
-        // We shouldn't attempt to extract libs from system app when it was not updated.
-        if (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 (isMultiArch(pkg.applicationInfo)) {
-                // 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(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(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, 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.
-     */
-    private static @Nullable List<String> adjustCpuAbisForSharedUserLPw(
-            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(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 (DEBUG_ABI_SELECTION) {
-                            Slog.i(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 void setUpCustomResolverActivity(PackageParser.Package pkg) {
         synchronized (mPackages) {
             mResolverReplaced = true;
@@ -12652,207 +11803,6 @@
                 | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
     }
 
-    private static String calculateBundledApkRoot(final String codePathString) {
-        final File codePath = new File(codePathString);
-        final File codeRoot;
-        if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
-            codeRoot = Environment.getRootDirectory();
-        } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
-            codeRoot = Environment.getOemDirectory();
-        } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
-            codeRoot = Environment.getVendorDirectory();
-        } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
-            codeRoot = Environment.getOdmDirectory();
-        } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
-            codeRoot = Environment.getProductDirectory();
-        } else if (FileUtils.contains(Environment.getProductServicesDirectory(), codePath)) {
-            codeRoot = Environment.getProductServicesDirectory();
-        } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
-            codeRoot = Environment.getOdmDirectory();
-        } else {
-            // Unrecognized code path; take its top real segment as the apk root:
-            // e.g. /something/app/blah.apk => /something
-            try {
-                File f = codePath.getCanonicalFile();
-                File parent = f.getParentFile();    // non-null because codePath is a file
-                File tmp;
-                while ((tmp = parent.getParentFile()) != null) {
-                    f = parent;
-                    parent = tmp;
-                }
-                codeRoot = f;
-                Slog.w(TAG, "Unrecognized code path "
-                        + codePath + " - using " + codeRoot);
-            } catch (IOException e) {
-                // Can't canonicalize the code path -- shenanigans?
-                Slog.w(TAG, "Can't canonicalize code path " + codePath);
-                return Environment.getRootDirectory().getPath();
-            }
-        }
-        return codeRoot.getPath();
-    }
-
-    /**
-     * Derive and set the location of native libraries for the given package,
-     * which varies depending on where and how the package was installed.
-     */
-    private static 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();
-            }
-        }
-    }
-
-    /**
-     * 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.
-     */
-    private static 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 static 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(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;
-        }
-    }
-
     private void killApplication(String pkgName, int appId, String reason) {
         killApplication(pkgName, appId, UserHandle.USER_ALL, reason);
     }
@@ -13370,7 +12320,9 @@
 
     @Override
     public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) {
-        enforceSystemOrPhoneCaller("setSystemAppHiddenUntilInstalled");
+        final int callingUid = Binder.getCallingUid();
+        PackageManagerServiceUtils
+                .enforceSystemOrPhoneCaller("setSystemAppHiddenUntilInstalled", callingUid);
         synchronized (mPackages) {
             final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
             if (pkgSetting == null || !pkgSetting.isSystem()) {
@@ -13393,7 +12345,9 @@
 
     @Override
     public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) {
-        enforceSystemOrPhoneCaller("setSystemAppInstallState");
+        final int callingUid = Binder.getCallingUid();
+        PackageManagerServiceUtils
+                .enforceSystemOrPhoneCaller("setSystemAppInstallState", callingUid);
         synchronized (mPackages) {
             final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
             // The target app should always be in system
@@ -13574,7 +12528,8 @@
                     // upgrade app from instant to full; we don't allow app downgrade
                     installed = true;
                 }
-                setInstantAppForUser(pkgSetting, userId, instantApp, fullApp);
+                setInstantAppForUser(
+                        getUserManagerInternal(), pkgSetting, userId, instantApp, fullApp);
             }
 
             if (installed) {
@@ -13582,8 +12537,8 @@
                         != 0 && pkgSetting.pkg != null) {
                     whiteListedPermissions = pkgSetting.pkg.requestedPermissions;
                 }
-                setWhitelistedRestrictedPermissions(packageName, whiteListedPermissions,
-                        PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
+                mPermissionManager.setWhitelistedRestrictedPermissions(packageName,
+                        whiteListedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
 
                 if (pkgSetting.pkg != null) {
                     synchronized (mInstallLock) {
@@ -13622,8 +12577,8 @@
         }
     }
 
-    static void setInstantAppForUser(PackageSetting pkgSetting, int userId,
-            boolean instantApp, boolean fullApp) {
+    static void setInstantAppForUser(UserManagerInternal userManager, PackageSetting pkgSetting,
+            int userId, boolean instantApp, boolean fullApp) {
         // no state specified; do nothing
         if (!instantApp && !fullApp) {
             return;
@@ -13635,7 +12590,7 @@
                 pkgSetting.setInstantApp(false /*instantApp*/, userId);
             }
         } else {
-            for (int currentUserId : sUserManager.getUserIds()) {
+            for (int currentUserId : userManager.getUserIds()) {
                 if (instantApp && !pkgSetting.getInstantApp(currentUserId)) {
                     pkgSetting.setInstantApp(true /*instantApp*/, currentUserId);
                 } else if (fullApp && pkgSetting.getInstantApp(currentUserId)) {
@@ -13965,7 +12920,7 @@
         final long callingId = Binder.clearCallingIdentity();
         try {
             final String activeLauncherPackageName = getActiveLauncherPackageName(userId);
-            final String dialerPackageName = getDefaultDialerPackageName(userId);
+            final String dialerPackageName = mPermissionManager.getDefaultDialer(userId);
             for (int i = 0; i < packageNames.length; i++) {
                 canSuspend[i] = false;
                 final String packageName = packageNames[i];
@@ -14047,19 +13002,6 @@
         return resolveInfo == null ? null : resolveInfo.activityInfo.packageName;
     }
 
-    @Nullable
-    private String getDefaultDialerPackageName(@UserIdInt int userId) {
-        PackageManagerInternal.DefaultDialerProvider provider;
-        synchronized (mPackages) {
-            provider = mDefaultDialerProvider;
-        }
-        if (provider == null) {
-            Slog.e(TAG, "mDefaultDialerProvider is null");
-            return null;
-        }
-        return provider.getDefaultDialer(userId);
-    }
-
     @Override
     public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
         mContext.enforceCallingOrSelfPermission(
@@ -14418,75 +13360,6 @@
         }
     }
 
-    @Override
-    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
-        }
-        if (userId == UserHandle.USER_ALL) {
-            return false;
-        }
-        PackageManagerInternal.DefaultBrowserProvider provider;
-        synchronized (mPackages) {
-            provider = mDefaultBrowserProvider;
-        }
-        if (provider == null) {
-            Slog.e(TAG, "mDefaultBrowserProvider is null");
-            return false;
-        }
-        boolean successful = provider.setDefaultBrowser(packageName, userId);
-        if (!successful) {
-            return false;
-        }
-        if (packageName != null) {
-            synchronized (mPackages) {
-                mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
-                        userId);
-            }
-        }
-        return true;
-    }
-
-    private void setDefaultBrowserAsyncLPw(@Nullable String packageName, @UserIdInt int userId) {
-        if (userId == UserHandle.USER_ALL) {
-            return;
-        }
-        if (mDefaultBrowserProvider == null) {
-            Slog.e(TAG, "mDefaultBrowserProvider is null");
-            return;
-        }
-        mDefaultBrowserProvider.setDefaultBrowserAsync(packageName, userId);
-        if (packageName != null) {
-            synchronized (mPackages) {
-                mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
-                        userId);
-            }
-        }
-    }
-
-    @Override
-    public String getDefaultBrowserPackageName(int userId) {
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
-        }
-        if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
-            return null;
-        }
-        PackageManagerInternal.DefaultBrowserProvider provider;
-        synchronized (mPackages) {
-            provider = mDefaultBrowserProvider;
-        }
-        if (provider == null) {
-            Slog.e(TAG, "mDefaultBrowserProvider is null");
-            return null;
-        }
-        return provider.getDefaultBrowser(userId);
-    }
-
     /**
      * Get the "allow unknown sources" setting.
      *
@@ -15909,16 +14782,6 @@
         }
     }
 
-    private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet) throws
-            PackageManagerException {
-        if (copyRet < 0) {
-            if (copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
-                    copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
-                throw new PackageManagerException(copyRet, message);
-            }
-        }
-    }
-
     /**
      * Logic to handle movement of existing installed applications.
      */
@@ -16045,26 +14908,6 @@
         return result;
     }
 
-    // Utility method that returns the relative package path with respect
-    // to the installation directory. Like say for /data/data/com.test-1.apk
-    // string com.test-1 is returned.
-    static String deriveCodePathName(String codePath) {
-        if (codePath == null) {
-            return null;
-        }
-        final File codeFile = new File(codePath);
-        final String name = codeFile.getName();
-        if (codeFile.isDirectory()) {
-            return name;
-        } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
-            final int lastDot = name.lastIndexOf('.');
-            return name.substring(0, lastDot);
-        } else {
-            Slog.w(TAG, "Odd, " + codePath + " doesn't look like an APK");
-            return null;
-        }
-    }
-
     static class PackageInstalledInfo {
         String name;
         int uid;
@@ -16249,8 +15092,7 @@
         if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
         synchronized (mPackages) {
 // NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
-            mPermissionManager.updatePermissions(pkg.packageName, pkg, mPackages.values(),
-                    mPermissionCallback);
+            mPermissionManager.updatePermissions(pkg.packageName, pkg);
             // For system-bundled packages, we assume that installing an upgraded version
             // of the package implies that the user actually wants to run that new code,
             // so we enable the package.
@@ -16627,13 +15469,13 @@
                                 && compareSignatures(sharedUserSignatures,
                                         pkg.mSigningDetails.signatures)
                                         != PackageManager.SIGNATURE_MATCH) {
-                            if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 28) {
+                            if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
                                 // Mismatched signatures is an error and silently skipping system
                                 // packages will likely break the device in unforeseen ways.
-                                // However,
-                                // we allow the device to boot anyway because, prior to P,
-                                // vendors were
-                                // not expecting the platform to crash in this situation.
+                                // However, we allow the device to boot anyway because, prior to Q,
+                                // vendors were not expecting the platform to crash in this
+                                // situation.
+                                // This WILL be a hard failure on any new API levels after Q.
                                 throw new ReconcileFailure(
                                         INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
                                         "Signature mismatch for shared user: "
@@ -16997,7 +15839,8 @@
                 final PrepareResult prepareResult;
                 try {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
-                    prepareResult = preparePackageLI(request.args, request.installResult);
+                    prepareResult =
+                            preparePackageLI(request.args, request.installResult);
                 } catch (PrepareFailure prepareFailure) {
                     request.installResult.setError(prepareFailure.error,
                             prepareFailure.getMessage());
@@ -17072,11 +15915,6 @@
                     commitPackagesLocked(commitRequest);
                     success = true;
                 } finally {
-                    for (PrepareResult result : prepareResults.values()) {
-                        if (result.freezer != null) {
-                            result.freezer.close();
-                        }
-                    }
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
             }
@@ -17662,7 +16500,7 @@
                 String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
                         args.abiOverride : pkg.cpuAbiOverride);
                 final boolean extractNativeLibs = !pkg.isLibrary();
-                derivePackageAbi(pkg, abiOverride, extractNativeLibs);
+                mInjector.getAbiHelper().derivePackageAbi(pkg, abiOverride, extractNativeLibs);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
                 throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -18191,10 +17029,6 @@
         }
     }
 
-    private static boolean isMultiArch(ApplicationInfo info) {
-        return (info.flags & ApplicationInfo.FLAG_MULTIARCH) != 0;
-    }
-
     private static boolean isExternal(PackageParser.Package pkg) {
         return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
@@ -18203,7 +17037,7 @@
         return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
 
-    private static boolean isSystemApp(PackageParser.Package pkg) {
+    static boolean isSystemApp(PackageParser.Package pkg) {
         return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
@@ -18223,9 +17057,9 @@
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
     }
 
-    private static boolean isProductServicesApp(PackageParser.Package pkg) {
+    private static boolean isSystemExtApp(PackageParser.Package pkg) {
         return (pkg.applicationInfo.privateFlags
-                & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0;
+                & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
     }
 
     private static boolean isOdmApp(PackageParser.Package pkg) {
@@ -18919,8 +17753,7 @@
                     if (outInfo != null) {
                         outInfo.removedAppId = removedAppId;
                     }
-                    mPermissionManager.updatePermissions(
-                            deletedPs.name, null, mPackages.values(), mPermissionCallback);
+                    mPermissionManager.updatePermissions(deletedPs.name, null);
                     if (deletedPs.sharedUser != null) {
                         // Remove permissions associated with package. Since runtime
                         // permissions are per user we have to kill the removed package
@@ -18991,13 +17824,13 @@
             final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
             final File privilegedOdmAppDir = new File(Environment.getOdmDirectory(), "priv-app");
             final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
-            final File privilegedProductServicesAppDir =
-                    new File(Environment.getProductServicesDirectory(), "priv-app");
+            final File privilegedSystemExtAppDir =
+                    new File(Environment.getSystemExtDirectory(), "priv-app");
             return path.startsWith(privilegedAppDir.getCanonicalPath() + "/")
                     || path.startsWith(privilegedVendorAppDir.getCanonicalPath() + "/")
                     || path.startsWith(privilegedOdmAppDir.getCanonicalPath() + "/")
                     || path.startsWith(privilegedProductAppDir.getCanonicalPath() + "/")
-                    || path.startsWith(privilegedProductServicesAppDir.getCanonicalPath() + "/");
+                    || path.startsWith(privilegedSystemExtAppDir.getCanonicalPath() + "/");
         } catch (IOException e) {
             Slog.e(TAG, "Unable to access code path " + path);
         }
@@ -19032,10 +17865,10 @@
         return false;
     }
 
-    static boolean locationIsProductServices(String path) {
+    static boolean locationIsSystemExt(String path) {
         try {
             return path.startsWith(
-              Environment.getProductServicesDirectory().getCanonicalPath() + "/");
+              Environment.getSystemExtDirectory().getCanonicalPath() + "/");
         } catch (IOException e) {
             Slog.e(TAG, "Unable to access code path " + path);
         }
@@ -19168,8 +18001,8 @@
         if (locationIsProduct(codePathString)) {
             scanFlags |= SCAN_AS_PRODUCT;
         }
-        if (locationIsProductServices(codePathString)) {
-            scanFlags |= SCAN_AS_PRODUCT_SERVICES;
+        if (locationIsSystemExt(codePathString)) {
+            scanFlags |= SCAN_AS_SYSTEM_EXT;
         }
         if (locationIsOdm(codePathString)) {
             scanFlags |= SCAN_AS_ODM;
@@ -19198,8 +18031,7 @@
             if (origPermissionState != null) {
                 ps.getPermissionsState().copyFrom(origPermissionState);
             }
-            mPermissionManager.updatePermissions(pkg.packageName, pkg, mPackages.values(),
-                    mPermissionCallback);
+            mPermissionManager.updatePermissions(pkg.packageName, pkg);
 
             final boolean applyUserRestrictions
                     = (allUserHandles != null) && (origUserHandles != null);
@@ -19661,9 +18493,7 @@
                     scheduleWritePackageRestrictionsLocked(nextUserId);
                 }
             }
-            synchronized (mPackages) {
-                resetUserChangesToRuntimePermissionsAndFlagsLPw(ps, nextUserId);
-            }
+            mPermissionManager.resetRuntimePermissions(pkg, nextUserId);
             // Also delete contributed media, when requested
             if ((flags & PackageManager.DELETE_CONTRIBUTED_MEDIA) != 0) {
                 try {
@@ -19774,15 +18604,12 @@
                     pkg = ps.pkg;
                 }
             }
-
-            if (pkg == null) {
-                Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
-                return false;
-            }
-
-            PackageSetting ps = (PackageSetting) pkg.mExtras;
-            resetUserChangesToRuntimePermissionsAndFlagsLPw(ps, userId);
         }
+        if (pkg == null) {
+            Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
+            return false;
+        }
+        mPermissionManager.resetRuntimePermissions(pkg, userId);
 
         clearAppDataLIF(pkg, userId,
                 FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
@@ -19804,201 +18631,11 @@
         return true;
     }
 
-    /**
-     * Reverts user permission state changes (permissions and flags) in
-     * all packages for a given user.
-     *
-     * @param userId The device user for which to do a reset.
-     */
-    @GuardedBy("mPackages")
-    private void resetUserChangesToRuntimePermissionsAndFlagsLPw(int userId) {
-        final int packageCount = mPackages.size();
-        for (int i = 0; i < packageCount; i++) {
-            PackageParser.Package pkg = mPackages.valueAt(i);
-            PackageSetting ps = (PackageSetting) pkg.mExtras;
-            resetUserChangesToRuntimePermissionsAndFlagsLPw(ps, userId);
-        }
-    }
-
     private void resetNetworkPolicies(int userId) {
         LocalServices.getService(NetworkPolicyManagerInternal.class).resetUserState(userId);
     }
 
     /**
-     * Reverts user permission state changes (permissions and flags).
-     *
-     * @param ps The package for which to reset.
-     * @param userId The device user for which to do a reset.
-     */
-    @GuardedBy("mPackages")
-    private void resetUserChangesToRuntimePermissionsAndFlagsLPw(
-            final PackageSetting ps, final int userId) {
-        if (ps.pkg == null) {
-            return;
-        }
-
-        final String packageName = ps.pkg.packageName;
-
-        // These are flags that can change base on user actions.
-        final int userSettableMask = FLAG_PERMISSION_USER_SET
-                | FLAG_PERMISSION_USER_FIXED
-                | FLAG_PERMISSION_REVOKE_ON_UPGRADE
-                | FLAG_PERMISSION_REVIEW_REQUIRED;
-
-        final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
-                | FLAG_PERMISSION_POLICY_FIXED;
-
-        // Delay and combine non-async permission callbacks
-        final boolean[] permissionRemoved = new boolean[1];
-        final ArraySet<Long> revokedPermissions = new ArraySet<>();
-        final SparseBooleanArray updatedUsers = new SparseBooleanArray();
-
-        PermissionCallback delayingPermCallback = new PermissionCallback() {
-            public void onGidsChanged(int appId, int userId) {
-                mPermissionCallback.onGidsChanged(appId, userId);
-            }
-
-            public void onPermissionChanged() {
-                mPermissionCallback.onPermissionChanged();
-            }
-
-            public void onPermissionGranted(int uid, int userId) {
-                mPermissionCallback.onPermissionGranted(uid, userId);
-            }
-
-            public void onInstallPermissionGranted() {
-                mPermissionCallback.onInstallPermissionGranted();
-            }
-
-            public void onPermissionRevoked(int uid, int userId) {
-                revokedPermissions.add(IntPair.of(uid, userId));
-
-                updatedUsers.put(userId, true);
-            }
-
-            public void onInstallPermissionRevoked() {
-                mPermissionCallback.onInstallPermissionRevoked();
-            }
-
-            public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
-                for (int userId : updatedUserIds) {
-                    if (sync) {
-                        updatedUsers.put(userId, true);
-                    } else {
-                        // Don't override sync=true by sync=false
-                        if (!updatedUsers.get(userId)) {
-                            updatedUsers.put(userId, false);
-                        }
-                    }
-                }
-            }
-
-            public void onPermissionRemoved() {
-                permissionRemoved[0] = true;
-            }
-
-            public void onInstallPermissionUpdated() {
-                mPermissionCallback.onInstallPermissionUpdated();
-            }
-        };
-
-        final int permissionCount = ps.pkg.requestedPermissions.size();
-        for (int i = 0; i < permissionCount; i++) {
-            final String permName = ps.pkg.requestedPermissions.get(i);
-            final BasePermission bp =
-                    (BasePermission) mPermissionManager.getPermissionTEMP(permName);
-            if (bp == null) {
-                continue;
-            }
-
-            if (bp.isRemoved()) {
-                continue;
-            }
-
-            // If shared user we just reset the state to which only this app contributed.
-            if (ps.sharedUser != null) {
-                boolean used = false;
-                final int packageCount = ps.sharedUser.packages.size();
-                for (int j = 0; j < packageCount; j++) {
-                    PackageSetting pkg = ps.sharedUser.packages.valueAt(j);
-                    if (pkg.pkg != null && !pkg.pkg.packageName.equals(ps.pkg.packageName)
-                            && pkg.pkg.requestedPermissions.contains(permName)) {
-                        used = true;
-                        break;
-                    }
-                }
-                if (used) {
-                    continue;
-                }
-            }
-
-            final int oldFlags = mPermissionManager.getPermissionFlags(permName, packageName,
-                    Process.SYSTEM_UID, userId);
-
-            // Always clear the user settable flags.
-            // If permission review is enabled and this is a legacy app, mark the
-            // permission as requiring a review as this is the initial state.
-            int flags = 0;
-            if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) {
-                flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-            }
-
-            mPermissionManager.updatePermissionFlags(permName, packageName,
-                    userSettableMask, flags, Process.SYSTEM_UID, userId, false,
-                    delayingPermCallback);
-
-            // Below is only runtime permission handling.
-            if (!bp.isRuntime()) {
-                continue;
-            }
-
-            // Never clobber system or policy.
-            if ((oldFlags & policyOrSystemFlags) != 0) {
-                continue;
-            }
-
-            // If this permission was granted by default, make sure it is.
-            if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
-                mPermissionManager.grantRuntimePermission(permName, packageName, false,
-                        Process.SYSTEM_UID, userId, delayingPermCallback);
-            // If permission review is enabled the permissions for a legacy apps
-            // are represented as constantly granted runtime ones, so don't revoke.
-            } else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
-                // Otherwise, reset the permission.
-                mPermissionManager.revokeRuntimePermission(permName, packageName, false, userId,
-                        delayingPermCallback);
-            }
-        }
-
-        // Execute delayed callbacks
-        if (permissionRemoved[0]) {
-            mPermissionCallback.onPermissionRemoved();
-        }
-
-        // Slight variation on the code in mPermissionCallback.onPermissionRevoked() as we cannot
-        // kill uid while holding mPackages-lock
-        if (!revokedPermissions.isEmpty()) {
-            int numRevokedPermissions = revokedPermissions.size();
-            for (int i = 0; i < numRevokedPermissions; i++) {
-                int revocationUID = IntPair.first(revokedPermissions.valueAt(i));
-                int revocationUserId = IntPair.second(revokedPermissions.valueAt(i));
-
-                mOnPermissionChangeListeners.onPermissionsChanged(revocationUID);
-
-                // Kill app later as we are holding mPackages
-                mHandler.post(() -> killUid(UserHandle.getAppId(revocationUID), revocationUserId,
-                        KILL_APP_REASON_PERMISSIONS_REVOKED));
-            }
-        }
-
-        int numUpdatedUsers = updatedUsers.size();
-        for (int i = 0; i < numUpdatedUsers; i++) {
-            mSettings.writeRuntimePermissionsForUserLPr(updatedUsers.keyAt(i),
-                    updatedUsers.valueAt(i));
-        }
-    }
-
-    /**
      * Remove entries from the keystore daemon. Will only remove it if the
      * {@code appId} is valid.
      */
@@ -20430,10 +19067,10 @@
     }
 
     private void clearDefaultBrowserIfNeededForUser(String packageName, int userId) {
-        final String defaultBrowserPackageName = getDefaultBrowserPackageName(userId);
+        final String defaultBrowserPackageName = mPermissionManager.getDefaultBrowser(userId);
         if (!TextUtils.isEmpty(defaultBrowserPackageName)) {
             if (packageName.equals(defaultBrowserPackageName)) {
-                setDefaultBrowserPackageName(null, userId);
+                mPermissionManager.setDefaultBrowser(null, true, true, userId);
             }
         }
     }
@@ -20454,14 +19091,14 @@
                 mSettings.applyDefaultPreferredAppsLPw(userId);
                 clearIntentFilterVerificationsLPw(userId);
                 primeDomainVerificationsLPw(userId);
-                resetUserChangesToRuntimePermissionsAndFlagsLPw(userId);
             }
+            mPermissionManager.resetAllRuntimePermissions(userId);
             updateDefaultHomeNotLocked(userId);
             // TODO: We have to reset the default SMS and Phone. This requires
             // significant refactoring to keep all default apps in the package
             // manager (cleaner but more work) or have the services provide
             // callbacks to the package manager to request a default app reset.
-            setDefaultBrowserPackageName(null, userId);
+            mPermissionManager.setDefaultBrowser(null, true, true, userId);
             resetNetworkPolicies(userId);
             synchronized (mPackages) {
                 scheduleWritePackageRestrictionsLocked(userId);
@@ -20714,17 +19351,14 @@
             parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
             restoreFromXml(parser, userId, TAG_DEFAULT_APPS,
                     (parser1, userId1) -> {
-                        String defaultBrowser;
+                        final String defaultBrowser;
                         synchronized (mPackages) {
                             mSettings.readDefaultAppsLPw(parser1, userId1);
                             defaultBrowser = mSettings.removeDefaultBrowserPackageNameLPw(userId1);
                         }
                         if (defaultBrowser != null) {
-                            PackageManagerInternal.DefaultBrowserProvider provider;
-                            synchronized (mPackages) {
-                                provider = mDefaultBrowserProvider;
-                            }
-                            provider.setDefaultBrowser(defaultBrowser, userId1);
+                            mPermissionManager
+                                    .setDefaultBrowser(defaultBrowser, false, false, userId1);
                         }
                     });
         } catch (Exception e) {
@@ -20961,15 +19595,7 @@
         }
         allHomeCandidates.addAll(resolveInfos);
 
-        PackageManagerInternal.DefaultHomeProvider provider;
-        synchronized (mPackages) {
-            provider = mDefaultHomeProvider;
-        }
-        if (provider == null) {
-            Slog.e(TAG, "mDefaultHomeProvider is null");
-            return null;
-        }
-        String packageName = provider.getDefaultHome(userId);
+        final String packageName = mPermissionManager.getDefaultHome(userId);
         if (packageName == null) {
             return null;
         }
@@ -21022,15 +19648,7 @@
         final String packageName = preferredResolveInfo != null
                 && preferredResolveInfo.activityInfo != null
                 ? preferredResolveInfo.activityInfo.packageName : null;
-        final PackageManagerInternal.DefaultHomeProvider provider;
-        synchronized (mPackages) {
-            provider = mDefaultHomeProvider;
-        }
-        if (provider == null) {
-            Slog.e(TAG, "Default home provider has not been set");
-            return false;
-        }
-        final String currentPackageName = provider.getDefaultHome(userId);
+        final String currentPackageName = mPermissionManager.getDefaultHome(userId);
         if (TextUtils.equals(currentPackageName, packageName)) {
             return false;
         }
@@ -21040,7 +19658,7 @@
             // PermissionController manages default home directly.
             return false;
         }
-        provider.setDefaultHomeAsync(packageName, userId, (successful) -> {
+        mPermissionManager.setDefaultHome(currentPackageName, userId, (successful) -> {
             if (successful) {
                 postPreferredActivityChangedBroadcast(userId);
             }
@@ -21596,7 +20214,8 @@
         // Disable any carrier apps. We do this very early in boot to prevent the apps from being
         // disabled after already being started.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
-                mContext.getContentResolver(), UserHandle.USER_SYSTEM);
+                mPermissionManagerService, mContext.getContentResolver(),
+                UserHandle.USER_SYSTEM);
 
         disableSkuSpecificApps();
 
@@ -21610,8 +20229,6 @@
             Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
         }
 
-        int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
-
         synchronized (mPackages) {
             // Verify that all of the preferred activity components actually
             // exist.  It is possible for applications to be updated and at
@@ -21641,35 +20258,15 @@
                             mSettings.mPreferredActivities.keyAt(i));
                 }
             }
-
-            for (int userId : UserManagerService.getInstance().getUserIds()) {
-                if (!mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {
-                    grantPermissionsUserIds = ArrayUtils.appendInt(
-                            grantPermissionsUserIds, userId);
-                }
-            }
         }
 
         sUserManager.systemReady();
-        // If we upgraded grant all default permissions before kicking off.
-        for (int userId : grantPermissionsUserIds) {
-            mDefaultPermissionPolicy.grantDefaultPermissions(userId);
-        }
-
-        if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
-            // If we did not grant default permissions, we preload from this the
-            // default permission exceptions lazily to ensure we don't hit the
-            // disk on a new user creation.
-            mDefaultPermissionPolicy.scheduleReadDefaultPermissionExceptions();
-        }
 
         // 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 (mPackages) {
-            mPermissionManager.updateAllPermissions(
-                    StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
-                    mPermissionCallback);
+            mPermissionManager.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL, false);
         }
 
         // Watch for external volumes that come and go over time
@@ -22662,8 +21259,7 @@
                 logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
                         + mSdkVersion + "; regranting permissions for " + volumeUuid);
             }
-            mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated, mPackages.values(),
-                    mPermissionCallback);
+            mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated);
 
             // Yay, everything is now upgraded
             ver.forceCurrent();
@@ -23688,13 +22284,7 @@
     }
 
     void onNewUserCreated(final int userId) {
-        mDefaultPermissionPolicy.grantDefaultPermissions(userId);
-        synchronized(mPackages) {
-            // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
-            mPermissionManager.updateAllPermissions(
-                    StorageManager.UUID_PRIVATE_INTERNAL, true, mPackages.values(),
-                    mPermissionCallback);
-        }
+        mPermissionManager.onNewUserCreated(userId);
     }
 
     @Override
@@ -23709,44 +22299,6 @@
     }
 
     @Override
-    public void setPermissionEnforced(String permission, boolean enforced) {
-        // TODO: Now that we no longer change GID for storage, this should to away.
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
-                "setPermissionEnforced");
-        if (READ_EXTERNAL_STORAGE.equals(permission)) {
-            synchronized (mPackages) {
-                if (mSettings.mReadExternalStorageEnforced == null
-                        || mSettings.mReadExternalStorageEnforced != enforced) {
-                    mSettings.mReadExternalStorageEnforced =
-                            enforced ? Boolean.TRUE : Boolean.FALSE;
-                    mSettings.writeLPr();
-                }
-            }
-            // kill any non-foreground processes so we restart them and
-            // grant/revoke the GID.
-            final IActivityManager am = ActivityManager.getService();
-            if (am != null) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    am.killProcessesBelowForeground("setPermissionEnforcement");
-                } catch (RemoteException e) {
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-        } else {
-            throw new IllegalArgumentException("No selective enforcement for " + permission);
-        }
-    }
-
-    @Override
-    @Deprecated
-    public boolean isPermissionEnforced(String permission) {
-        // allow instant applications
-        return true;
-    }
-
-    @Override
     public boolean isStorageLow() {
         // allow instant applications
         final long token = Binder.clearCallingIdentity();
@@ -24027,59 +22579,6 @@
         }
     }
 
-    private final static class OnPermissionChangeListeners extends Handler {
-        private static final int MSG_ON_PERMISSIONS_CHANGED = 1;
-
-        private final RemoteCallbackList<IOnPermissionsChangeListener> mPermissionListeners =
-                new RemoteCallbackList<>();
-
-        public OnPermissionChangeListeners(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_ON_PERMISSIONS_CHANGED: {
-                    final int uid = msg.arg1;
-                    handleOnPermissionsChanged(uid);
-                } break;
-            }
-        }
-
-        public void addListenerLocked(IOnPermissionsChangeListener listener) {
-            mPermissionListeners.register(listener);
-
-        }
-
-        public void removeListenerLocked(IOnPermissionsChangeListener listener) {
-            mPermissionListeners.unregister(listener);
-        }
-
-        public void onPermissionsChanged(int uid) {
-            if (mPermissionListeners.getRegisteredCallbackCount() > 0) {
-                obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
-            }
-        }
-
-        private void handleOnPermissionsChanged(int uid) {
-            final int count = mPermissionListeners.beginBroadcast();
-            try {
-                for (int i = 0; i < count; i++) {
-                    IOnPermissionsChangeListener callback = mPermissionListeners
-                            .getBroadcastItem(i);
-                    try {
-                        callback.onPermissionsChanged(uid);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Permission listener is dead", e);
-                    }
-                }
-            } finally {
-                mPermissionListeners.finishBroadcast();
-            }
-        }
-    }
-
     private class PackageManagerNative extends IPackageManagerNative.Stub {
         @Override
         public String[] getNamesForUids(int[] uids) throws RemoteException {
@@ -24171,13 +22670,6 @@
 
     private class PackageManagerInternalImpl extends PackageManagerInternal {
         @Override
-        public void updatePermissionFlagsTEMP(String permName, String packageName, int flagMask,
-                int flagValues, int userId) {
-            PackageManagerService.this.updatePermissionFlags(
-                    permName, packageName, flagMask, flagValues, true, userId);
-        }
-
-        @Override
         public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
                 int callingUid) {
             return PackageManagerService.this.getInstalledApplicationsListInternal(flags, userId,
@@ -24258,11 +22750,6 @@
         }
 
         @Override
-        public int getPermissionFlagsTEMP(String permName, String packageName, int userId) {
-            return PackageManagerService.this.getPermissionFlags(permName, packageName, userId);
-        }
-
-        @Override
         public boolean isInstantApp(String packageName, int userId) {
             return PackageManagerService.this.isInstantApp(packageName, userId);
         }
@@ -24275,8 +22762,20 @@
         @Override
         public boolean filterAppAccess(PackageParser.Package pkg, int callingUid, int userId) {
             synchronized (mPackages) {
-                return PackageManagerService.this.filterAppAccessLPr(
-                        (PackageSetting) pkg.mExtras, callingUid, userId);
+                return PackageManagerService.this
+                        .filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid, userId);
+            }
+        }
+
+        @Override
+        public boolean filterAppAccess(String packageName, int callingUid, int userId) {
+            synchronized (mPackages) {
+                final PackageParser.Package pkg = mPackages.get(packageName);
+                if (pkg == null) {
+                    return false;
+                }
+                return PackageManagerService.this
+                        .filterAppAccessLPr((PackageSetting) pkg.mExtras, callingUid, userId);
             }
         }
 
@@ -24290,6 +22789,19 @@
         }
 
         @Override
+        public PackageParser.Package getPackage(int uid) {
+            synchronized (mPackages) {
+                final String[] packageNames = getPackagesForUid(uid);
+                PackageParser.Package pkg = null;
+                final int numPackages = packageNames == null ? 0 : packageNames.length;
+                for (int i = 0; pkg == null && i < numPackages; i++) {
+                    pkg = mPackages.get(packageNames[i]);
+                }
+                return pkg;
+            }
+        }
+
+        @Override
         public PackageList getPackageList(PackageListObserver observer) {
             synchronized (mPackages) {
                 final int N = mPackages.size();
@@ -24330,7 +22842,7 @@
         public String getKnownPackageName(int knownPackage, int userId) {
             switch(knownPackage) {
                 case PackageManagerInternal.PACKAGE_BROWSER:
-                    return getDefaultBrowserPackageName(userId);
+                    return mPermissionManager.getDefaultBrowser(userId);
                 case PackageManagerInternal.PACKAGE_INSTALLER:
                     return mRequiredInstallerPackage;
                 case PackageManagerInternal.PACKAGE_SETUP_WIZARD:
@@ -24364,37 +22876,6 @@
         }
 
         @Override
-        public void setLocationPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setLocationPackagesProvider(provider);
-        }
-
-        @Override
-        public void setLocationExtraPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setLocationExtraPackagesProvider(provider);
-        }
-
-        @Override
-        public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setVoiceInteractionPackagesProvider(provider);
-        }
-
-        @Override
-        public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionPolicy.setUseOpenWifiAppPackagesProvider(provider);
-        }
-
-        @Override
-        public void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider) {
-            mDefaultPermissionPolicy.setSyncAdapterPackagesProvider(provider);
-        }
-
-        @Override
-        public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
-            mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultUseOpenWifiApp(
-                    packageName, userId);
-        }
-
-        @Override
         public void setKeepUninstalledPackages(final List<String> packageList) {
             Preconditions.checkNotNull(packageList);
             List<String> removedFromList = null;
@@ -24595,22 +23076,6 @@
         }
 
         @Override
-        public void grantRuntimePermission(String packageName, String permName, int userId,
-                boolean overridePolicy) {
-            PackageManagerService.this.mPermissionManager.grantRuntimePermission(
-                    permName, packageName, overridePolicy, getCallingUid(), userId,
-                    mPermissionCallback);
-        }
-
-        @Override
-        public void revokeRuntimePermission(String packageName, String permName, int userId,
-                boolean overridePolicy) {
-            mPermissionManager.revokeRuntimePermission(
-                    permName, packageName, overridePolicy, userId,
-                    mPermissionCallback);
-        }
-
-        @Override
         public String getNameForUid(int uid) {
             return PackageManagerService.this.getNameForUid(uid);
         }
@@ -24813,20 +23278,6 @@
         }
 
         @Override
-        public CheckPermissionDelegate getCheckPermissionDelegate() {
-            synchronized (mPackages) {
-                return PackageManagerService.this.getCheckPermissionDelegateLocked();
-            }
-        }
-
-        @Override
-        public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) {
-            synchronized (mPackages) {
-                PackageManagerService.this.setCheckPermissionDelegateLocked(delegate);
-            }
-        }
-
-        @Override
         public SparseArray<String> getAppsWithSharedUserIds() {
             synchronized (mPackages) {
                 return getAppsWithSharedUserIdsLocked();
@@ -24937,27 +23388,6 @@
         }
 
         @Override
-        public void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider) {
-            synchronized (mPackages) {
-                mDefaultBrowserProvider = provider;
-            }
-        }
-
-        @Override
-        public void setDefaultDialerProvider(@NonNull DefaultDialerProvider provider) {
-            synchronized (mPackages) {
-                mDefaultDialerProvider = provider;
-            }
-        }
-
-        @Override
-        public void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider) {
-            synchronized (mPackages) {
-                mDefaultHomeProvider = provider;
-            }
-        }
-
-        @Override
         public boolean isApexPackage(String packageName) {
             return PackageManagerService.this.mApexManager.isApexPackage(packageName);
         }
@@ -25003,13 +23433,6 @@
         }
 
         @Override
-        public boolean wereDefaultPermissionsGrantedSinceBoot(int userId) {
-            synchronized (mPackages) {
-                return mDefaultPermissionPolicy.wereDefaultPermissionsGrantedSinceBoot(userId);
-            }
-        }
-
-        @Override
         public void setRuntimePermissionsFingerPrint(@NonNull String fingerPrint,
                 @UserIdInt int userId) {
             synchronized (mPackages) {
@@ -25036,6 +23459,84 @@
                 }
             }
         }
+
+        @Override
+        public void writePermissionSettings(int[] userIds, boolean async) {
+            synchronized (mPackages) {
+                for (int userId : userIds) {
+                    mSettings.writeRuntimePermissionsForUserLPr(userId, !async);
+                }
+            }
+        }
+
+        @Override
+        public int getTargetSdk(int uid) {
+            int userId = UserHandle.getUserId(uid);
+
+            synchronized (mPackages) {
+                final Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+                if (obj instanceof PackageSetting) {
+                    final PackageSetting ps = (PackageSetting) obj;
+                    if (!ps.getInstalled(userId)) {
+                        return 0;
+                    }
+                    return ps.pkg.applicationInfo.targetSdkVersion;
+                } else if (obj instanceof SharedUserSetting) {
+                    int maxTargetSdk = 0;
+                    final SharedUserSetting sus = (SharedUserSetting) obj;
+                    final int numPkgs = sus.packages.size();
+                    for (int i = 0; i < numPkgs; i++) {
+                        final PackageSetting ps = sus.packages.valueAt(i);
+                        if (!ps.getInstalled(userId)) {
+                            continue;
+                        }
+                        if (ps.pkg.applicationInfo.targetSdkVersion < maxTargetSdk) {
+                            continue;
+                        }
+                        maxTargetSdk = ps.pkg.applicationInfo.targetSdkVersion;
+                    }
+                    return maxTargetSdk;
+                }
+                return 0;
+            }
+        }
+
+        @Override
+        public boolean isCallerInstallerOfRecord(
+                @NonNull PackageParser.Package pkg, int callingUid) {
+            synchronized (mPackages) {
+                if (pkg == null) {
+                    return false;
+                }
+                final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
+                if (packageSetting == null) {
+                    return false;
+                }
+                final PackageSetting installerPackageSetting =
+                        mSettings.mPackages.get(packageSetting.installerPackageName);
+                return installerPackageSetting != null
+                        && UserHandle.isSameApp(installerPackageSetting.appId, callingUid);
+            }
+        }
+
+        @Override
+        public boolean areDefaultRuntimePermissionsGranted(int userId) {
+            synchronized (mPackages) {
+                return mSettings.areDefaultRuntimePermissionsGrantedLPr(userId);
+            }
+        }
+
+        @Override
+        public void setReadExternalStorageEnforced(boolean enforced) {
+            synchronized (mPackages) {
+                if (mSettings.mReadExternalStorageEnforced != null
+                        && mSettings.mReadExternalStorageEnforced == enforced) {
+                    return;
+                }
+                mSettings.mReadExternalStorageEnforced = enforced ? Boolean.TRUE : Boolean.FALSE;
+                mSettings.writeLPr();
+            }
+        }
     }
 
     @GuardedBy("mPackages")
@@ -25104,83 +23605,6 @@
         }
     }
 
-    @Override
-    public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) {
-        enforceSystemOrPhoneCaller("grantPermissionsToEnabledCarrierApps");
-        synchronized (mPackages) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledCarrierApps(
-                        packageNames, userId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    @Override
-    public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) {
-        enforceSystemOrPhoneCaller("grantDefaultPermissionsToEnabledImsServices");
-        synchronized (mPackages) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledImsServices(
-                        packageNames, userId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    @Override
-    public void grantDefaultPermissionsToEnabledTelephonyDataServices(
-            String[] packageNames, int userId) {
-        enforceSystemOrPhoneCaller("grantDefaultPermissionsToEnabledTelephonyDataServices");
-        synchronized (mPackages) {
-            Binder.withCleanCallingIdentity( () -> mDefaultPermissionPolicy.
-                    grantDefaultPermissionsToEnabledTelephonyDataServices(
-                            packageNames, userId));
-        }
-    }
-
-    @Override
-    public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
-            String[] packageNames, int userId) {
-        enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromDisabledTelephonyDataServices");
-        synchronized (mPackages) {
-            Binder.withCleanCallingIdentity( () -> mDefaultPermissionPolicy.
-                    revokeDefaultPermissionsFromDisabledTelephonyDataServices(
-                            packageNames, userId));
-        }
-    }
-
-    @Override
-    public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
-        enforceSystemOrPhoneCaller("grantDefaultPermissionsToActiveLuiApp");
-        synchronized (mPackages) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                mDefaultPermissionPolicy.grantDefaultPermissionsToActiveLuiApp(
-                        packageName, userId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    @Override
-    public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
-        enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromLuiApps");
-        synchronized (mPackages) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                mDefaultPermissionPolicy.revokeDefaultPermissionsFromLuiApps(packageNames, userId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
     void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
         synchronized (mPackages) {
             int numPackages = mPackages.size();
@@ -25205,14 +23629,6 @@
         }
     }
 
-    private static void enforceSystemOrPhoneCaller(String tag) {
-        int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.PHONE_UID && callingUid != Process.SYSTEM_UID) {
-            throw new SecurityException(
-                    "Cannot call " + tag + " from UID " + callingUid);
-        }
-    }
-
     boolean isHistoricalPackageUsageAvailable() {
         return mPackageUsage.isHistoricalPackageUsageAvailable();
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 45b6834..4c7db9a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -62,6 +62,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.PackageDexUsage;
+import com.android.server.pm.permission.PermissionsState;
 
 import dalvik.system.VMRuntime;
 
@@ -389,6 +390,17 @@
     }
 
     /**
+     * Enforces that the caller must be either the system process or the phone process.
+     * If not, throws a {@link SecurityException}.
+     */
+    public static void enforceSystemOrPhoneCaller(String methodName, int callingUid) {
+        if (callingUid != Process.PHONE_UID && callingUid != Process.SYSTEM_UID) {
+            throw new SecurityException(
+                    "Cannot call " + methodName + " from UID " + callingUid);
+        }
+    }
+
+    /**
      * Derive the value of the {@code cpuAbiOverride} based on the provided
      * value and an optional stored value from the package settings.
      */
@@ -885,4 +897,16 @@
             IoUtils.closeQuietly(source);
         }
     }
+
+    /**
+     * Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState}
+     * could not be found, {@code null} will be returned.
+     */
+    public static PermissionsState getPermissionsState(PackageParser.Package pkg) {
+        final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
+        if (packageSetting == null) {
+            return null;
+        }
+        return packageSetting.getPermissionsState();
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a25c68f..85bc9f3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1997,15 +1997,15 @@
         }
 
         if (grant) {
-            mInterface.grantRuntimePermission(pkg, perm, userId);
+            mPermissionManager.grantRuntimePermission(pkg, perm, userId);
         } else {
-            mInterface.revokeRuntimePermission(pkg, perm, userId);
+            mPermissionManager.revokeRuntimePermission(pkg, perm, userId);
         }
         return 0;
     }
 
     private int runResetPermissions() throws RemoteException {
-        mInterface.resetRuntimePermissions();
+        mPermissionManager.resetRuntimePermissions();
         return 0;
     }
 
@@ -2020,7 +2020,7 @@
             getErrPrintWriter().println("Error: no enforcement specified");
             return 1;
         }
-        mInterface.setPermissionEnforced(permission, Boolean.parseBoolean(enforcedRaw));
+        mPermissionManager.setPermissionEnforced(permission, Boolean.parseBoolean(enforcedRaw));
         return 0;
     }
 
@@ -2042,10 +2042,10 @@
         }
     }
 
-    private boolean isProductServicesApp(String pkg) {
+    private boolean isSystemExtApp(String pkg) {
         try {
             final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
-            return info != null && info.applicationInfo.isProductServices();
+            return info != null && info.applicationInfo.isSystemExt();
         } catch (RemoteException e) {
             return false;
         }
@@ -2063,9 +2063,9 @@
             privAppPermissions = SystemConfig.getInstance().getVendorPrivAppPermissions(pkg);
         } else if (isProductApp(pkg)) {
             privAppPermissions = SystemConfig.getInstance().getProductPrivAppPermissions(pkg);
-        } else if (isProductServicesApp(pkg)) {
+        } else if (isSystemExtApp(pkg)) {
             privAppPermissions = SystemConfig.getInstance()
-                    .getProductServicesPrivAppPermissions(pkg);
+                    .getSystemExtPrivAppPermissions(pkg);
         } else {
             privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
         }
@@ -2087,9 +2087,9 @@
             privAppPermissions = SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg);
         } else if (isProductApp(pkg)) {
             privAppPermissions = SystemConfig.getInstance().getProductPrivAppDenyPermissions(pkg);
-        } else if (isProductServicesApp(pkg)) {
+        } else if (isSystemExtApp(pkg)) {
             privAppPermissions = SystemConfig.getInstance()
-                    .getProductServicesPrivAppDenyPermissions(pkg);
+                    .getSystemExtPrivAppDenyPermissions(pkg);
         } else {
             privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
         }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index e859893..4ea8a30 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -148,8 +148,8 @@
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
     }
 
-    public boolean isProductServices() {
-        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0;
+    public boolean isSystemExt() {
+        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
     }
 
     public boolean isOdm() {
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 58f262c..029673f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -270,7 +270,8 @@
         updateAvailable = orig.updateAvailable;
     }
 
-    private PackageUserState modifyUserState(int userId) {
+    @VisibleForTesting
+    PackageUserState modifyUserState(int userId) {
         PackageUserState state = mUserState.get(userId);
         if (state == null) {
             state = new PackageUserState();
@@ -463,6 +464,18 @@
         state.harmfulAppWarning = harmfulAppWarning;
     }
 
+    void setUserState(int userId, PackageUserState otherState) {
+        setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed,
+                otherState.stopped, otherState.notLaunched, otherState.hidden,
+                otherState.distractionFlags, otherState.suspended, otherState.suspendingPackage,
+                otherState.dialogInfo, otherState.suspendedAppExtras,
+                otherState.suspendedLauncherExtras, otherState.instantApp,
+                otherState.virtualPreload, otherState.lastDisableAppCaller,
+                otherState.enabledComponents, otherState.disabledComponents,
+                otherState.domainVerificationStatus, otherState.appLinkGeneration,
+                otherState.installReason, otherState.harmfulAppWarning);
+    }
+
     ArraySet<String> getEnabledComponents(int userId) {
         return readUserState(userId).enabledComponents;
     }
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index a24818f..ec9746d 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -63,7 +63,7 @@
                 | ApplicationInfo.PRIVATE_FLAG_OEM
                 | ApplicationInfo.PRIVATE_FLAG_VENDOR
                 | ApplicationInfo.PRIVATE_FLAG_PRODUCT
-                | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES
+                | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT
                 | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER
                 | ApplicationInfo.PRIVATE_FLAG_ODM);
     }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 11a8f4b..3bc2236 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -774,7 +774,7 @@
                 | ApplicationInfo.PRIVATE_FLAG_OEM
                 | ApplicationInfo.PRIVATE_FLAG_VENDOR
                 | ApplicationInfo.PRIVATE_FLAG_PRODUCT
-                | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES
+                | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT
                 | ApplicationInfo.PRIVATE_FLAG_ODM);
         pkgSetting.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
         pkgSetting.pkgPrivateFlags |=
@@ -786,7 +786,7 @@
         pkgSetting.pkgPrivateFlags |=
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT;
         pkgSetting.pkgPrivateFlags |=
-                pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES;
+                pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT;
         pkgSetting.pkgPrivateFlags |=
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM;
         pkgSetting.primaryCpuAbiString = primaryCpuAbi;
@@ -4413,7 +4413,7 @@
             ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY",
             ApplicationInfo.PRIVATE_FLAG_VENDOR, "VENDOR",
             ApplicationInfo.PRIVATE_FLAG_PRODUCT, "PRODUCT",
-            ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES, "PRODUCT_SERVICES",
+            ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT, "SYSTEM_EXT",
             ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD",
             ApplicationInfo.PRIVATE_FLAG_ODM, "ODM",
     };
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 2d8a2ac..ebba128 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -79,7 +79,7 @@
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.text.TextUtils;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.KeyValueListParser;
@@ -3981,9 +3981,7 @@
     }
 
     static String formatTime(long time) {
-        Time tobj = new Time();
-        tobj.set(time);
-        return tobj.format("%Y-%m-%d %H:%M:%S");
+        return TimeMigrationUtils.formatMillisWithFixedFormat(time);
     }
 
     private void dumpCurrentTime(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 42b65c3..bdeaf02 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -180,6 +180,8 @@
             checkDowngrade(session, activePackage, pkg);
             result.add(pkg);
         }
+        Slog.d(TAG, "Session " + session.sessionId + " has following APEX packages: ["
+                + result.stream().map(p -> p.packageName).collect(Collectors.joining(",")) + "]");
         return result;
     }
 
@@ -206,7 +208,7 @@
             throws PackageManagerException {
         final long activeVersion = activePackage.applicationInfo.longVersionCode;
         final long newVersionCode = newPackage.applicationInfo.longVersionCode;
-        boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
+        final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
                 session.params.installFlags, activePackage.applicationInfo.flags);
         if (activeVersion > newVersionCode && !allowsDowngrade) {
             if (!mApexManager.abortActiveSession()) {
@@ -225,6 +227,7 @@
     }
 
     private void preRebootVerification(@NonNull PackageInstallerSession session) {
+        Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId);
         final boolean hasApex = sessionContainsApex(session);
         // APEX checks. For single-package sessions, check if they contain an APEX. For
         // multi-package sessions, find all the child sessions that contain an APEX.
@@ -242,11 +245,13 @@
         }
 
         if (sessionContainsApk(session)) {
-            if (!installApksInSession(session, /* preReboot */ true)) {
-                session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                        "APK verification failed. Check logcat messages for "
-                                + "more information.");
+            try {
+                Slog.d(TAG, "Running a pre-reboot verification for APKs in session "
+                        + session.sessionId + " by performing a dry-run install");
+                installApksInSession(session, /* preReboot */ true);
                 // TODO(b/118865310): abort the session on apexd.
+            } catch (PackageManagerException e) {
+                session.setStagedSessionFailed(e.error, e.getMessage());
                 return;
             }
         }
@@ -277,6 +282,7 @@
         // On the other hand, if the order of the calls was inverted (first call apexd, then mark
         // session as ready), then if a device gets rebooted right after the call to apexd, only
         // apex part of the train will be applied, leaving device in an inconsistent state.
+        Slog.d(TAG, "Marking session " + session.sessionId + " as ready");
         session.setStagedSessionReady();
         if (!hasApex) {
             // Session doesn't contain apex, nothing to do.
@@ -315,7 +321,8 @@
     }
 
     private void resumeSession(@NonNull PackageInstallerSession session) {
-        boolean hasApex = sessionContainsApex(session);
+        Slog.d(TAG, "Resuming session " + session.sessionId);
+        final boolean hasApex = sessionContainsApex(session);
         if (hasApex) {
             // Check with apexservice whether the apex packages have been activated.
             ApexSessionInfo apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId);
@@ -348,12 +355,15 @@
                         + "retry at next reboot.");
                 return;
             }
+            Slog.i(TAG, "APEX packages in session " + session.sessionId
+                    + " were successfully activated. Proceeding with APK packages, if any");
         }
         // The APEX part of the session is activated, proceed with the installation of APKs.
-        if (!installApksInSession(session, /* preReboot */ false)) {
-            session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
-                    "Staged installation of APKs failed. Check logcat messages for"
-                        + "more information.");
+        try {
+            Slog.d(TAG, "Installing APK packages in session " + session.sessionId);
+            installApksInSession(session, /* preReboot */ false);
+        } catch (PackageManagerException e) {
+            session.setStagedSessionFailed(e.error, e.getMessage());
 
             if (!hasApex) {
                 return;
@@ -370,6 +380,7 @@
             return;
         }
 
+        Slog.d(TAG, "Marking session " + session.sessionId + " as applied");
         session.setStagedSessionApplied();
         if (hasApex) {
             mApexManager.markStagedSessionSuccessful(session.sessionId);
@@ -388,16 +399,22 @@
         return ret;
     }
 
+    @NonNull
     private PackageInstallerSession createAndWriteApkSession(
-            @NonNull PackageInstallerSession originalSession, boolean preReboot) {
+            @NonNull PackageInstallerSession originalSession, boolean preReboot)
+            throws PackageManagerException {
+        final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
+                : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
         if (originalSession.stageDir == null) {
             Slog.wtf(TAG, "Attempting to install a staged APK session with no staging dir");
-            return null;
+            throw new PackageManagerException(errorCode,
+                    "Attempting to install a staged APK session with no staging dir");
         }
         List<String> apkFilePaths = findAPKsInDir(originalSession.stageDir);
         if (apkFilePaths.isEmpty()) {
             Slog.w(TAG, "Can't find staged APK in " + originalSession.stageDir.getAbsolutePath());
-            return null;
+            throw new PackageManagerException(errorCode,
+                    "Can't find staged APK in " + originalSession.stageDir.getAbsolutePath());
         }
 
         PackageInstaller.SessionParams params = originalSession.params.copy();
@@ -424,20 +441,22 @@
                 long sizeBytes = pfd.getStatSize();
                 if (sizeBytes < 0) {
                     Slog.e(TAG, "Unable to get size of: " + apkFilePath);
-                    return null;
+                    throw new PackageManagerException(errorCode,
+                            "Unable to get size of: " + apkFilePath);
                 }
                 apkSession.write(apkFile.getName(), 0, sizeBytes, pfd);
             }
         } catch (IOException e) {
             Slog.e(TAG, "Failure to install APK staged session " + originalSession.sessionId, e);
-            return null;
+            throw new PackageManagerException(errorCode, "Failed to write APK session", e);
         }
         return apkSession;
     }
 
-    private boolean commitApkSession(@NonNull PackageInstallerSession apkSession,
-                                     int originalSessionId, boolean preReboot) {
-
+    private void commitApkSession(@NonNull PackageInstallerSession apkSession,
+            int originalSessionId, boolean preReboot) throws PackageManagerException {
+        final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
+                : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
         if (!preReboot) {
             if ((apkSession.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                 // If rollback is available for this session, notify the rollback
@@ -457,23 +476,24 @@
         final Intent result = receiver.getResult();
         final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                 PackageInstaller.STATUS_FAILURE);
-        if (status == PackageInstaller.STATUS_SUCCESS) {
-            return true;
+        if (status != PackageInstaller.STATUS_SUCCESS) {
+
+            final String errorMessage = result.getStringExtra(
+                    PackageInstaller.EXTRA_STATUS_MESSAGE);
+            Slog.e(TAG, "Failure to install APK staged session " + originalSessionId + " ["
+                    + errorMessage + "]");
+            throw new PackageManagerException(errorCode, errorMessage);
         }
-        Slog.e(TAG, "Failure to install APK staged session " + originalSessionId + " ["
-                + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
-        return false;
     }
 
-    private boolean installApksInSession(@NonNull PackageInstallerSession session,
-                                         boolean preReboot) {
+    private void installApksInSession(@NonNull PackageInstallerSession session,
+                                         boolean preReboot) throws PackageManagerException {
+        final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
+                : SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
         if (!session.isMultiPackage() && !isApexSession(session)) {
             // APK single-packaged staged session. Do a regular install.
             PackageInstallerSession apkSession = createAndWriteApkSession(session, preReboot);
-            if (apkSession == null) {
-                return false;
-            }
-            return commitApkSession(apkSession, session.sessionId, preReboot);
+            commitApkSession(apkSession, session.sessionId, preReboot);
         } else if (session.isMultiPackage()) {
             // For multi-package staged sessions containing APKs, we identify which child sessions
             // contain an APK, and with those then create a new multi-package group of sessions,
@@ -491,7 +511,7 @@
             }
             if (childSessions.isEmpty()) {
                 // APEX-only multi-package staged session, nothing to do.
-                return true;
+                return;
             }
             PackageInstaller.SessionParams params = session.params.copy();
             params.isStaged = false;
@@ -508,26 +528,24 @@
             } catch (IOException e) {
                 Slog.e(TAG, "Unable to prepare multi-package session for staged session "
                         + session.sessionId);
-                return false;
+                throw new PackageManagerException(errorCode,
+                        "Unable to prepare multi-package session for staged session");
             }
 
             for (PackageInstallerSession sessionToClone : childSessions) {
                 PackageInstallerSession apkChildSession =
                         createAndWriteApkSession(sessionToClone, preReboot);
-                if (apkChildSession == null) {
-                    return false;
-                }
                 try {
                     apkParentSession.addChildSessionId(apkChildSession.sessionId);
                 } catch (IllegalStateException e) {
                     Slog.e(TAG, "Failed to add a child session for installing the APK files", e);
-                    return false;
+                    throw new PackageManagerException(errorCode,
+                            "Failed to add a child session " + apkChildSession.sessionId);
                 }
             }
-            return commitApkSession(apkParentSession, session.sessionId, preReboot);
+            commitApkSession(apkParentSession, session.sessionId, preReboot);
         }
         // APEX single-package staged session, nothing to do.
-        return true;
     }
 
     void commitSession(@NonNull PackageInstallerSession session) {
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 15dc6ae..f7b60c2 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -8,6 +8,30 @@
     },
     {
       "name": "CtsCompilationTestCases"
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.pm."
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "CtsPermissionTestCases",
+      "options": [
+        {
+            "include-filter": "android.permission.cts.PermissionUpdateListenerTest"
+        }
+      ]
     }
   ],
   "imports": [
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 db01d77..fe0b3a3 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -34,8 +34,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageManagerInternal.PackagesProvider;
-import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
 import android.content.pm.PermissionInfo;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
@@ -69,6 +67,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.PackagesProvider;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.SyncAdapterPackagesProvider;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -1388,8 +1388,7 @@
         if (dir.isDirectory() && dir.canRead()) {
             Collections.addAll(ret, dir.listFiles());
         }
-        dir = new File(Environment.getProductServicesDirectory(),
-                "etc/default-permissions");
+        dir = new File(Environment.getSystemExtDirectory(), "etc/default-permissions");
         if (dir.isDirectory() && dir.canRead()) {
             Collections.addAll(ret, dir.listFiles());
         }
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 9b00dca..03be8e1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm.permission;
 
+import static android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
@@ -32,13 +33,17 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE;
 import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
+import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;
 
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
 import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.permission.PermissionManagerService.killUid;
 import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
 
 import static java.util.concurrent.TimeUnit.SECONDS;
@@ -48,7 +53,10 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
 import android.app.ApplicationPackageManager;
+import android.app.IActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.PermissionGroupInfoFlags;
@@ -65,7 +73,11 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
 import android.os.Process;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -73,16 +85,19 @@
 import android.os.UserManagerInternal;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
+import android.permission.IOnPermissionsChangeListener;
 import android.permission.IPermissionManager;
 import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
 import android.permission.PermissionManagerInternal;
+import android.permission.PermissionManagerInternal.CheckPermissionDelegate;
 import android.permission.PermissionManagerInternal.OnRuntimePermissionStateChangedListener;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DebugUtils;
 import android.util.EventLog;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -93,6 +108,8 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.RoSystemProperties;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IntPair;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
@@ -103,6 +120,9 @@
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.SharedUserSetting;
 import com.android.server.pm.UserManagerService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultBrowserProvider;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultDialerProvider;
+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.SoftRestrictedPermissionPolicy;
@@ -112,7 +132,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -123,6 +142,7 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
 
 /**
  * Manages all permissions and handles permissions related tasks.
@@ -229,6 +249,79 @@
     final private ArrayList<OnRuntimePermissionStateChangedListener>
             mRuntimePermissionStateChangedListeners = new ArrayList<>();
 
+    @GuardedBy("mLock")
+    private CheckPermissionDelegate mCheckPermissionDelegate;
+
+    @GuardedBy("mLock")
+    private final OnPermissionChangeListeners mOnPermissionChangeListeners;
+
+    @GuardedBy("mLock")
+    private DefaultBrowserProvider mDefaultBrowserProvider;
+
+    @GuardedBy("mLock")
+    private DefaultDialerProvider mDefaultDialerProvider;
+
+    @GuardedBy("mLock")
+    private DefaultHomeProvider mDefaultHomeProvider;
+
+    // TODO: Take a look at the methods defined in the callback.
+    // The callback was initially created to support the split between permission
+    // manager and the package manager. However, it's started to be used for other
+    // purposes. It may make sense to keep as an abstraction, but, the methods
+    // necessary to be overridden may be different than what was initially needed
+    // for the split.
+    private PermissionCallback mDefaultPermissionCallback = new PermissionCallback() {
+        @Override
+        public void onGidsChanged(int appId, int userId) {
+            mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED));
+        }
+        @Override
+        public void onPermissionGranted(int uid, int userId) {
+            mOnPermissionChangeListeners.onPermissionsChanged(uid);
+
+            // Not critical; if this is lost, the application has to request again.
+            mPackageManagerInt.writeSettings(true);
+        }
+        @Override
+        public void onInstallPermissionGranted() {
+            mPackageManagerInt.writeSettings(true);
+        }
+        @Override
+        public void onPermissionRevoked(int uid, int userId) {
+            mOnPermissionChangeListeners.onPermissionsChanged(uid);
+
+            // Critical; after this call the application should never have the permission
+            mPackageManagerInt.writeSettings(false);
+            final int appId = UserHandle.getAppId(uid);
+            killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
+        }
+        @Override
+        public void onInstallPermissionRevoked() {
+            mPackageManagerInt.writeSettings(true);
+        }
+        @Override
+        public void onPermissionUpdated(int[] userIds, boolean sync) {
+            mPackageManagerInt.writePermissionSettings(userIds, !sync);
+        }
+        @Override
+        public void onInstallPermissionUpdated() {
+            mPackageManagerInt.writeSettings(true);
+        }
+        @Override
+        public void onPermissionRemoved() {
+            mPackageManagerInt.writeSettings(false);
+        }
+        public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
+                int uid) {
+            onPermissionUpdated(updatedUserIds, sync);
+            mOnPermissionChangeListeners.onPermissionsChanged(uid);
+        }
+        public void onInstallPermissionUpdatedNotifyListener(int uid) {
+            onInstallPermissionUpdated();
+            mOnPermissionChangeListeners.onPermissionsChanged(uid);
+        }
+    };
+
     PermissionManagerService(Context context,
             @NonNull Object externalLock) {
         mContext = context;
@@ -248,6 +341,7 @@
         SystemConfig systemConfig = SystemConfig.getInstance();
         mSystemPermissions = systemConfig.getSystemPermissions();
         mGlobalGids = systemConfig.getGlobalGids();
+        mOnPermissionChangeListeners = new OnPermissionChangeListeners(FgThread.get().getLooper());
 
         // propagate permission configuration
         final ArrayMap<String, SystemConfig.PermissionEntry> permConfig =
@@ -298,6 +392,29 @@
         return LocalServices.getService(PermissionManagerServiceInternal.class);
     }
 
+    /**
+     * This method should typically only be used when granting or revoking
+     * permissions, since the app may immediately restart after this call.
+     * <p>
+     * If you're doing surgery on app code/data, use {@link PackageFreezer} to
+     * guard your work against the app being relaunched.
+     */
+    public static void killUid(int appId, int userId, String reason) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            IActivityManager am = ActivityManager.getService();
+            if (am != null) {
+                try {
+                    am.killUid(appId, userId, reason);
+                } catch (RemoteException e) {
+                    /* ignore - same process */
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Nullable BasePermission getPermission(String permName) {
         synchronized (mLock) {
             return mSettings.getPermissionLocked(permName);
@@ -456,12 +573,232 @@
         }
     }
 
-    private int checkPermission(String permName, String pkgName, int callingUid, int userId) {
+    @Override
+    public int getPermissionFlags(String permName, String packageName, int userId) {
+        final int callingUid = getCallingUid();
+        return getPermissionFlagsInternal(permName, packageName, callingUid, userId);
+    }
+
+    private int getPermissionFlagsInternal(
+            String permName, String packageName, int callingUid, int userId) {
+        if (!mUserManagerInt.exists(userId)) {
+            return 0;
+        }
+
+        enforceGrantRevokeGetRuntimePermissionPermissions("getPermissionFlags");
+        enforceCrossUserPermission(callingUid, userId,
+                true,  // requireFullPermission
+                false, // checkShell
+                false, // requirePermissionWhenSameUser
+                "getPermissionFlags");
+
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        if (pkg == null || pkg.mExtras == null) {
+            return 0;
+        }
+        synchronized (mLock) {
+            if (mSettings.getPermissionLocked(permName) == null) {
+                return 0;
+            }
+        }
+        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+            return 0;
+        }
+        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        PermissionsState permissionsState = ps.getPermissionsState();
+        return permissionsState.getPermissionFlags(permName, userId);
+    }
+
+    @Override
+    public void updatePermissionFlags(String permName, String packageName, int flagMask,
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
+        final int callingUid = getCallingUid();
+        boolean overridePolicy = false;
+
+        if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) {
+            long callingIdentity = Binder.clearCallingIdentity();
+            try {
+                if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0) {
+                    if (checkAdjustPolicyFlagPermission) {
+                        mContext.enforceCallingOrSelfPermission(
+                                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+                                "Need " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY
+                                        + " to change policy flags");
+                    } else if (mPackageManagerInt.getTargetSdk(callingUid)
+                            >= Build.VERSION_CODES.Q) {
+                        throw new IllegalArgumentException(
+                                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " needs "
+                                        + " to be checked for packages targeting "
+                                        + Build.VERSION_CODES.Q + " or later when changing policy "
+                                        + "flags");
+                    }
+                    overridePolicy = true;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(callingIdentity);
+            }
+        }
+
+        updatePermissionFlagsInternal(
+                permName, packageName, flagMask, flagValues, callingUid, userId,
+                overridePolicy, mDefaultPermissionCallback);
+    }
+
+    private void updatePermissionFlagsInternal(String permName, String packageName, int flagMask,
+            int flagValues, int callingUid, int userId, boolean overridePolicy,
+            PermissionCallback callback) {
+        if (ApplicationPackageManager.DEBUG_TRACE_GRANTS
+                && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) {
+            Log.i(TAG, "System is updating flags for "
+                            + permName + " for user " + userId  + " "
+                            + DebugUtils.flagsToString(
+                                    PackageManager.class, "FLAG_PERMISSION_", flagMask)
+                            + " := "
+                            + DebugUtils.flagsToString(
+                                    PackageManager.class, "FLAG_PERMISSION_", flagValues)
+                            + " on behalf of uid " + callingUid
+                            + " " + mPackageManagerInt.getNameForUid(callingUid),
+                    new RuntimeException());
+        }
+
+        if (!mUserManagerInt.exists(userId)) {
+            return;
+        }
+
+        enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlags");
+
+        enforceCrossUserPermission(callingUid, userId,
+                true,  // requireFullPermission
+                true,  // checkShell
+                false, // requirePermissionWhenSameUser
+                "updatePermissionFlags");
+
+        if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0 && !overridePolicy) {
+            throw new SecurityException("updatePermissionFlags requires "
+                    + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
+        }
+
+        // Only the system can change these flags and nothing else.
+        if (callingUid != Process.SYSTEM_UID) {
+            flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+            flagMask &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
+        }
+
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        if (pkg == null || pkg.mExtras == null) {
+            Log.e(TAG, "Unknown package: " + packageName);
+            return;
+        }
+        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+            throw new IllegalArgumentException("Unknown package: " + packageName);
+        }
+
+        final BasePermission bp;
+        synchronized (mLock) {
+            bp = mSettings.getPermissionLocked(permName);
+        }
+        if (bp == null) {
+            throw new IllegalArgumentException("Unknown permission: " + permName);
+        }
+
+        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        final PermissionsState permissionsState = ps.getPermissionsState();
+        final boolean hadState =
+                permissionsState.getRuntimePermissionState(permName, userId) != null;
+        final boolean permissionUpdated =
+                permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues);
+        if (permissionUpdated && bp.isRuntime()) {
+            notifyRuntimePermissionStateChanged(packageName, userId);
+        }
+        if (permissionUpdated && callback != null) {
+            // Install and runtime permissions are stored in different places,
+            // so figure out what permission changed and persist the change.
+            if (permissionsState.getInstallPermissionState(permName) != null) {
+                callback.onInstallPermissionUpdatedNotifyListener(pkg.applicationInfo.uid);
+            } else if (permissionsState.getRuntimePermissionState(permName, userId) != null
+                    || hadState) {
+                callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
+                        pkg.applicationInfo.uid);
+            }
+        }
+    }
+
+    /**
+     * Update the permission flags for all packages and runtime permissions of a user in order
+     * to allow device or profile owner to remove POLICY_FIXED.
+     */
+    @Override
+    public void updatePermissionFlagsForAllApps(int flagMask, int flagValues,
+            final int userId) {
+        final int callingUid = getCallingUid();
+        if (!mUserManagerInt.exists(userId)) {
+            return;
+        }
+
+        enforceGrantRevokeRuntimePermissionPermissions(
+                "updatePermissionFlagsForAllApps");
+        enforceCrossUserPermission(callingUid, userId,
+                true,  // requireFullPermission
+                true,  // checkShell
+                false, // requirePermissionWhenSameUser
+                "updatePermissionFlagsForAllApps");
+
+        // Only the system can change system fixed flags.
+        final int effectiveFlagMask = (callingUid != Process.SYSTEM_UID)
+                ? flagMask : flagMask & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+        final int effectiveFlagValues = (callingUid != Process.SYSTEM_UID)
+                ? flagValues : flagValues & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+
+        final boolean[] changed = new boolean[1];
+        mPackageManagerInt.forEachPackage(new Consumer<PackageParser.Package>() {
+            @Override
+            public void accept(Package pkg) {
+                final PackageSetting ps = (PackageSetting) pkg.mExtras;
+                if (ps == null) {
+                    return;
+                }
+                final PermissionsState permissionsState = ps.getPermissionsState();
+                changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
+                        userId, effectiveFlagMask, effectiveFlagValues);
+                mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+            }
+        });
+
+        if (changed[0]) {
+            mPackageManagerInt.writePermissionSettings(new int[] { userId }, true);
+        }
+    }
+
+    @Override
+    public int checkPermission(String permName, String pkgName, int userId) {
+        final CheckPermissionDelegate checkPermissionDelegate;
+        synchronized (mLock) {
+            if (mCheckPermissionDelegate == null)  {
+                return checkPermissionImpl(permName, pkgName, userId);
+            }
+            checkPermissionDelegate = mCheckPermissionDelegate;
+        }
+        return checkPermissionDelegate.checkPermission(permName, pkgName, userId,
+                PermissionManagerService.this::checkPermissionImpl);
+    }
+
+    private int checkPermissionImpl(String permName, String pkgName, int userId) {
+        return checkPermissionInternal(permName, pkgName, getCallingUid(), userId);
+    }
+
+    private int checkPermissionInternal(String permName, String packageName, int callingUid,
+            int userId) {
         if (!mUserManagerInt.exists(userId)) {
             return PackageManager.PERMISSION_DENIED;
         }
-
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(pkgName);
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg != null && pkg.mExtras != null) {
             if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
                 return PackageManager.PERMISSION_DENIED;
@@ -485,12 +822,38 @@
                 return PackageManager.PERMISSION_GRANTED;
             }
         }
-
         return PackageManager.PERMISSION_DENIED;
     }
 
-    private int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
-            int callingUid) {
+    @Override
+    public int checkUidPermission(String permName, int uid) {
+        final CheckPermissionDelegate checkPermissionDelegate;
+        synchronized (mLock) {
+            if (mCheckPermissionDelegate == null)  {
+                return checkUidPermissionImpl(permName, uid);
+            }
+            checkPermissionDelegate = mCheckPermissionDelegate;
+        }
+        return checkPermissionDelegate.checkUidPermission(permName, uid,
+                PermissionManagerService.this::checkUidPermissionImpl);
+    }
+
+    private int checkUidPermissionImpl(@NonNull String permName, int uid) {
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid);
+        synchronized (mLock) {
+            return checkUidPermissionInternal(permName, pkg, uid, getCallingUid());
+        }
+    }
+
+    /**
+     * Checks whether or not the given package has been granted the specified
+     * permission. If the given package is {@code null}, we instead check the
+     * system permissions for the given UID.
+     *
+     * @see SystemConfig#getSystemPermissions()
+     */
+    private int checkUidPermissionInternal(@NonNull String permName,
+            @Nullable PackageParser.Package pkg, int uid, int callingUid) {
         final int callingUserId = UserHandle.getUserId(callingUid);
         final boolean isCallerInstantApp =
                 mPackageManagerInt.getInstantAppPackageName(callingUid) != null;
@@ -538,6 +901,957 @@
         return PackageManager.PERMISSION_DENIED;
     }
 
+    @Override
+    public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
+        mContext.enforceCallingOrSelfPermission(
+                Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS,
+                "addOnPermissionsChangeListener");
+
+        synchronized (mLock) {
+            mOnPermissionChangeListeners.addListenerLocked(listener);
+        }
+    }
+
+    @Override
+    public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
+        if (mPackageManagerInt.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+            throw new SecurityException("Instant applications don't have access to this method");
+        }
+        synchronized (mLock) {
+            mOnPermissionChangeListeners.removeListenerLocked(listener);
+        }
+    }
+
+    @Override
+    @Nullable public List<String> getWhitelistedRestrictedPermissions(@NonNull String packageName,
+            @PermissionWhitelistFlags int flags, @UserIdInt int userId) {
+        Preconditions.checkNotNull(packageName);
+        Preconditions.checkFlagsArgument(flags,
+                PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+        Preconditions.checkArgumentNonNegative(userId, null);
+
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS,
+                    "getWhitelistedRestrictedPermissions for user " + userId);
+        }
+
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        if (pkg == null) {
+            return null;
+        }
+
+        final int callingUid = Binder.getCallingUid();
+        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, UserHandle.getCallingUserId())) {
+            return null;
+        }
+        final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
+                Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
+                        == PackageManager.PERMISSION_GRANTED;
+        final boolean isCallerInstallerOnRecord =
+                mPackageManagerInt.isCallerInstallerOfRecord(pkg, callingUid);
+
+        if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
+                && !isCallerPrivileged) {
+            throw new SecurityException("Querying system whitelist requires "
+                    + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+        }
+
+        if ((flags & (PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) != 0) {
+            if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+                throw new SecurityException("Querying upgrade or installer whitelist"
+                        + " requires being installer on record or "
+                        + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+            }
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final PermissionsState permissionsState =
+                    PackageManagerServiceUtils.getPermissionsState(pkg);
+            if (permissionsState == null) {
+                return null;
+            }
+
+            int queryFlags = 0;
+            if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0) {
+                queryFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+            }
+            if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
+                queryFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+            }
+            if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
+                queryFlags |=  PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+            }
+
+            ArrayList<String> whitelistedPermissions = null;
+
+            final int permissionCount = pkg.requestedPermissions.size();
+            for (int i = 0; i < permissionCount; i++) {
+                final String permissionName = pkg.requestedPermissions.get(i);
+                final int currentFlags =
+                        permissionsState.getPermissionFlags(permissionName, userId);
+                if ((currentFlags & queryFlags) != 0) {
+                    if (whitelistedPermissions == null) {
+                        whitelistedPermissions = new ArrayList<>();
+                    }
+                    whitelistedPermissions.add(permissionName);
+                }
+            }
+
+            return whitelistedPermissions;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
+            @NonNull String permName, @PermissionWhitelistFlags int flags,
+            @UserIdInt int userId) {
+        // Other argument checks are done in get/setWhitelistedRestrictedPermissions
+        Preconditions.checkNotNull(permName);
+
+        if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permName)) {
+            return false;
+        }
+
+        List<String> permissions =
+                getWhitelistedRestrictedPermissions(packageName, flags, userId);
+        if (permissions == null) {
+            permissions = new ArrayList<>(1);
+        }
+        if (permissions.indexOf(permName) < 0) {
+            permissions.add(permName);
+            return setWhitelistedRestrictedPermissionsInternal(packageName, permissions,
+                    flags, userId);
+        }
+        return false;
+    }
+
+    private boolean checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(
+            @NonNull String permName) {
+        synchronized (mLock) {
+            final BasePermission bp = mSettings.getPermissionLocked(permName);
+            if (bp == null) {
+                Slog.w(TAG, "No such permissions: " + permName);
+                return false;
+            }
+            if (bp.isHardOrSoftRestricted() && bp.isImmutablyRestricted()
+                    && mContext.checkCallingOrSelfPermission(
+                    Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Cannot modify whitelisting of an immutably "
+                        + "restricted permission: " + permName);
+            }
+            return true;
+        }
+    }
+
+    @Override
+    public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
+            @NonNull String permName, @PermissionWhitelistFlags int flags,
+            @UserIdInt int userId) {
+        // Other argument checks are done in get/setWhitelistedRestrictedPermissions
+        Preconditions.checkNotNull(permName);
+
+        if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permName)) {
+            return false;
+        }
+
+        final List<String> permissions =
+                getWhitelistedRestrictedPermissions(packageName, flags, userId);
+        if (permissions != null && permissions.remove(permName)) {
+            return setWhitelistedRestrictedPermissionsInternal(packageName, permissions,
+                    flags, userId);
+        }
+        return false;
+    }
+
+    private boolean setWhitelistedRestrictedPermissionsInternal(@NonNull String packageName,
+            @Nullable List<String> permissions, @PermissionWhitelistFlags int flags,
+            @UserIdInt int userId) {
+        Preconditions.checkNotNull(packageName);
+        Preconditions.checkFlagsArgument(flags,
+                PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+        Preconditions.checkArgument(Integer.bitCount(flags) == 1);
+        Preconditions.checkArgumentNonNegative(userId, null);
+
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS,
+                    "setWhitelistedRestrictedPermissions for user " + userId);
+        }
+
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        if (pkg == null) {
+            return false;
+        }
+
+        final int callingUid = Binder.getCallingUid();
+        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, UserHandle.getCallingUserId())) {
+            return false;
+        }
+
+        final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
+                Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
+                        == PackageManager.PERMISSION_GRANTED;
+        final boolean isCallerInstallerOnRecord =
+                mPackageManagerInt.isCallerInstallerOfRecord(pkg, callingUid);
+
+        if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
+                && !isCallerPrivileged) {
+            throw new SecurityException("Modifying system whitelist requires "
+                    + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+        }
+
+        if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
+            if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+                throw new SecurityException("Modifying upgrade whitelist requires"
+                        + " being installer on record or "
+                        + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+            }
+            final List<String> whitelistedPermissions =
+                    getWhitelistedRestrictedPermissions(pkg.packageName, flags, userId);
+            if (permissions == null || permissions.isEmpty()) {
+                if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
+                    return true;
+                }
+            } else {
+                // Only the system can add and remove while the installer can only remove.
+                final int permissionCount = permissions.size();
+                for (int i = 0; i < permissionCount; i++) {
+                    if ((whitelistedPermissions == null
+                            || !whitelistedPermissions.contains(permissions.get(i)))
+                            && !isCallerPrivileged) {
+                        throw new SecurityException("Adding to upgrade whitelist requires"
+                                + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+                    }
+                }
+            }
+
+            if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
+                if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+                    throw new SecurityException("Modifying installer whitelist requires"
+                            + " being installer on record or "
+                            + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+                }
+            }
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            setWhitelistedRestrictedPermissionsForUser(
+                    pkg, userId, permissions, Process.myUid(), flags, mDefaultPermissionCallback);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+        return true;
+    }
+
+    @Override
+    public void grantRuntimePermission(String packageName, String permName, final int userId) {
+        final int callingUid = Binder.getCallingUid();
+        final boolean overridePolicy =
+                checkUidPermission(ADJUST_RUNTIME_PERMISSIONS_POLICY, callingUid)
+                        == PackageManager.PERMISSION_GRANTED;
+
+        grantRuntimePermissionInternal(permName, packageName, overridePolicy,
+                callingUid, userId, mDefaultPermissionCallback);
+    }
+
+    // TODO swap permission name and package name
+    private void grantRuntimePermissionInternal(String permName, String packageName,
+            boolean overridePolicy, int callingUid, final int userId, PermissionCallback callback) {
+        if (ApplicationPackageManager.DEBUG_TRACE_GRANTS
+                && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) {
+            Log.i(TAG, "System is granting "
+                    + permName + " for user " + userId + " on behalf of uid " + callingUid
+                    + " " + mPackageManagerInt.getNameForUid(callingUid),
+                    new RuntimeException());
+        }
+        if (!mUserManagerInt.exists(userId)) {
+            Log.e(TAG, "No such user:" + userId);
+            return;
+        }
+
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+                "grantRuntimePermission");
+
+        enforceCrossUserPermission(callingUid, userId,
+                true,  // requireFullPermission
+                true,  // checkShell
+                false, // requirePermissionWhenSameUser
+                "grantRuntimePermission");
+
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        if (pkg == null || pkg.mExtras == null) {
+            throw new IllegalArgumentException("Unknown package: " + packageName);
+        }
+        final BasePermission bp;
+        synchronized (mLock) {
+            bp = mSettings.getPermissionLocked(permName);
+        }
+        if (bp == null) {
+            throw new IllegalArgumentException("Unknown permission: " + permName);
+        }
+        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+            throw new IllegalArgumentException("Unknown package: " + packageName);
+        }
+
+        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+
+        // If a permission review is required for legacy apps we represent
+        // their permissions as always granted runtime ones since we need
+        // to keep the review required permission flag per user while an
+        // install permission's state is shared across all users.
+        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+                && bp.isRuntime()) {
+            return;
+        }
+
+        final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
+
+        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        final PermissionsState permissionsState = ps.getPermissionsState();
+
+        final int flags = permissionsState.getPermissionFlags(permName, userId);
+        if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
+            Log.e(TAG, "Cannot grant system fixed permission "
+                    + permName + " for package " + packageName);
+            return;
+        }
+        if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+            Log.e(TAG, "Cannot grant policy fixed permission "
+                    + permName + " for package " + packageName);
+            return;
+        }
+
+        if (bp.isHardRestricted()
+                && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
+            Log.e(TAG, "Cannot grant hard restricted non-exempt permission "
+                    + permName + " for package " + packageName);
+            return;
+        }
+
+        if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext,
+                pkg.applicationInfo, UserHandle.of(userId), permName).canBeGranted()) {
+            Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package "
+                    + packageName);
+            return;
+        }
+
+        if (bp.isDevelopment()) {
+            // Development permissions must be handled specially, since they are not
+            // normal runtime permissions.  For now they apply to all users.
+            if (permissionsState.grantInstallPermission(bp)
+                    != PERMISSION_OPERATION_FAILURE) {
+                if (callback != null) {
+                    callback.onInstallPermissionGranted();
+                }
+            }
+            return;
+        }
+
+        if (ps.getInstantApp(userId) && !bp.isInstant()) {
+            throw new SecurityException("Cannot grant non-ephemeral permission"
+                    + permName + " for package " + packageName);
+        }
+
+        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+            Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
+            return;
+        }
+
+        final int result = permissionsState.grantRuntimePermission(bp, userId);
+        switch (result) {
+            case PERMISSION_OPERATION_FAILURE: {
+                return;
+            }
+
+            case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
+                if (callback != null) {
+                    callback.onGidsChanged(UserHandle.getAppId(pkg.applicationInfo.uid), userId);
+                }
+            }
+            break;
+        }
+
+        if (bp.isRuntime()) {
+            logPermission(MetricsEvent.ACTION_PERMISSION_GRANTED, permName, packageName);
+        }
+
+        if (callback != null) {
+            callback.onPermissionGranted(uid, userId);
+        }
+
+        if (bp.isRuntime()) {
+            notifyRuntimePermissionStateChanged(packageName, userId);
+        }
+
+        // Only need to do this if user is initialized. Otherwise it's a new user
+        // and there are no processes running as the user yet and there's no need
+        // to make an expensive call to remount processes for the changed permissions.
+        if (READ_EXTERNAL_STORAGE.equals(permName)
+                || WRITE_EXTERNAL_STORAGE.equals(permName)) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (mUserManagerInt.isUserInitialized(userId)) {
+                    StorageManagerInternal storageManagerInternal = LocalServices.getService(
+                            StorageManagerInternal.class);
+                    storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+    }
+
+    @Override
+    public void revokeRuntimePermission(String packageName, String permName, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        final boolean overridePolicy =
+                checkUidPermission(ADJUST_RUNTIME_PERMISSIONS_POLICY, callingUid)
+                        == PackageManager.PERMISSION_GRANTED;
+
+        revokeRuntimePermissionInternal(permName, packageName, overridePolicy, callingUid, userId,
+                mDefaultPermissionCallback);
+    }
+
+    // TODO swap permission name and package name
+    private void revokeRuntimePermissionInternal(String permName, String packageName,
+            boolean overridePolicy, int callingUid, final int userId, PermissionCallback callback) {
+        if (ApplicationPackageManager.DEBUG_TRACE_GRANTS
+                && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) {
+            Log.i(TAG, "System is revoking "
+                            + permName + " for user " + userId + " on behalf of uid " + callingUid
+                            + " " + mPackageManagerInt.getNameForUid(callingUid),
+                    new RuntimeException());
+        }
+        if (!mUserManagerInt.exists(userId)) {
+            Log.e(TAG, "No such user:" + userId);
+            return;
+        }
+
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+                "revokeRuntimePermission");
+
+        enforceCrossUserPermission(callingUid, userId,
+                true,  // requireFullPermission
+                true,  // checkShell
+                false, // requirePermissionWhenSameUser
+                "revokeRuntimePermission");
+
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        if (pkg == null || pkg.mExtras == null) {
+            throw new IllegalArgumentException("Unknown package: " + packageName);
+        }
+        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+            throw new IllegalArgumentException("Unknown package: " + packageName);
+        }
+        final BasePermission bp = mSettings.getPermissionLocked(permName);
+        if (bp == null) {
+            throw new IllegalArgumentException("Unknown permission: " + permName);
+        }
+
+        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+
+        // If a permission review is required for legacy apps we represent
+        // their permissions as always granted runtime ones since we need
+        // to keep the review required permission flag per user while an
+        // install permission's state is shared across all users.
+        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+                && bp.isRuntime()) {
+            return;
+        }
+
+        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        final PermissionsState permissionsState = ps.getPermissionsState();
+
+        final int flags = permissionsState.getPermissionFlags(permName, userId);
+        // Only the system may revoke SYSTEM_FIXED permissions.
+        if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
+                && UserHandle.getCallingAppId() != Process.SYSTEM_UID) {
+            throw new SecurityException("Non-System UID cannot revoke system fixed permission "
+                    + permName + " for package " + packageName);
+        }
+        if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+            throw new SecurityException("Cannot revoke policy fixed permission "
+                    + permName + " for package " + packageName);
+        }
+
+        if (bp.isDevelopment()) {
+            // Development permissions must be handled specially, since they are not
+            // normal runtime permissions.  For now they apply to all users.
+            if (permissionsState.revokeInstallPermission(bp)
+                    != PERMISSION_OPERATION_FAILURE) {
+                if (callback != null) {
+                    mDefaultPermissionCallback.onInstallPermissionRevoked();
+                }
+            }
+            return;
+        }
+
+        // Permission is already revoked, no need to do anything.
+        if (!permissionsState.hasRuntimePermission(permName, userId)) {
+            return;
+        }
+
+        if (permissionsState.revokeRuntimePermission(bp, userId)
+                == PERMISSION_OPERATION_FAILURE) {
+            return;
+        }
+
+        if (bp.isRuntime()) {
+            logPermission(MetricsEvent.ACTION_PERMISSION_REVOKED, permName, packageName);
+        }
+
+        if (callback != null) {
+            callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
+        }
+
+        if (bp.isRuntime()) {
+            notifyRuntimePermissionStateChanged(packageName, userId);
+        }
+    }
+
+    @Override
+    public void resetRuntimePermissions() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+                "revokeRuntimePermission");
+
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "resetRuntimePermissions");
+        }
+
+        updateAllPermissions(
+                StorageManager.UUID_PRIVATE_INTERNAL, false, mDefaultPermissionCallback);
+        for (final int userId : UserManagerService.getInstance().getUserIds()) {
+            mPackageManagerInt.forEachPackage(
+                    (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId));
+        }
+    }
+
+    /**
+     * Reverts user permission state changes (permissions and flags).
+     *
+     * @param pkg The package for which to reset.
+     * @param userId The device user for which to do a reset.
+     */
+    @GuardedBy("mPackages")
+    private void resetRuntimePermissionsInternal(final PackageParser.Package pkg,
+            final int userId) {
+        final String packageName = pkg.packageName;
+
+        // These are flags that can change base on user actions.
+        final int userSettableMask = FLAG_PERMISSION_USER_SET
+                | FLAG_PERMISSION_USER_FIXED
+                | FLAG_PERMISSION_REVOKE_ON_UPGRADE
+                | FLAG_PERMISSION_REVIEW_REQUIRED;
+
+        final int policyOrSystemFlags = FLAG_PERMISSION_SYSTEM_FIXED
+                | FLAG_PERMISSION_POLICY_FIXED;
+
+        // Delay and combine non-async permission callbacks
+        final int permissionCount = pkg.requestedPermissions.size();
+        final boolean[] permissionRemoved = new boolean[1];
+        final ArraySet<Long> revokedPermissions = new ArraySet<>();
+        final IntArray syncUpdatedUsers = new IntArray(permissionCount);
+        final IntArray asyncUpdatedUsers = new IntArray(permissionCount);
+
+        PermissionCallback delayingPermCallback = new PermissionCallback() {
+            public void onGidsChanged(int appId, int userId) {
+                mDefaultPermissionCallback.onGidsChanged(appId, userId);
+            }
+
+            public void onPermissionChanged() {
+                mDefaultPermissionCallback.onPermissionChanged();
+            }
+
+            public void onPermissionGranted(int uid, int userId) {
+                mDefaultPermissionCallback.onPermissionGranted(uid, userId);
+            }
+
+            public void onInstallPermissionGranted() {
+                mDefaultPermissionCallback.onInstallPermissionGranted();
+            }
+
+            public void onPermissionRevoked(int uid, int userId) {
+                revokedPermissions.add(IntPair.of(uid, userId));
+
+                syncUpdatedUsers.add(userId);
+            }
+
+            public void onInstallPermissionRevoked() {
+                mDefaultPermissionCallback.onInstallPermissionRevoked();
+            }
+
+            public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
+                for (int userId : updatedUserIds) {
+                    if (sync) {
+                        syncUpdatedUsers.add(userId);
+                        asyncUpdatedUsers.remove(userId);
+                    } else {
+                        // Don't override sync=true by sync=false
+                        if (syncUpdatedUsers.indexOf(userId) == -1) {
+                            asyncUpdatedUsers.add(userId);
+                        }
+                    }
+                }
+            }
+
+            public void onPermissionRemoved() {
+                permissionRemoved[0] = true;
+            }
+
+            public void onInstallPermissionUpdated() {
+                mDefaultPermissionCallback.onInstallPermissionUpdated();
+            }
+        };
+
+        final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+        for (int i = 0; i < permissionCount; i++) {
+            final String permName = pkg.requestedPermissions.get(i);
+            final BasePermission bp;
+            synchronized (mLock) {
+                bp = mSettings.getPermissionLocked(permName);
+            }
+            if (bp == null) {
+                continue;
+            }
+
+            if (bp.isRemoved()) {
+                continue;
+            }
+
+            // If shared user we just reset the state to which only this app contributed.
+            final String sharedUserId =
+                    mPackageManagerInt.getSharedUserIdForPackage(pkg.packageName);
+            final String[] pkgNames =
+                    mPackageManagerInt.getPackagesForSharedUserId(sharedUserId, userId);
+            if (pkgNames != null && pkgNames.length > 0) {
+                boolean used = false;
+                final int packageCount = pkgNames.length;
+                for (int j = 0; j < packageCount; j++) {
+                    final String sharedPkgName = pkgNames[j];
+                    final PackageParser.Package sharedPkg =
+                            mPackageManagerInt.getPackage(sharedPkgName);
+                    if (sharedPkg != null && !sharedPkg.packageName.equals(packageName)
+                            && sharedPkg.requestedPermissions.contains(permName)) {
+                        used = true;
+                        break;
+                    }
+                }
+                if (used) {
+                    continue;
+                }
+            }
+
+            final int oldFlags =
+                    getPermissionFlagsInternal(permName, packageName, Process.SYSTEM_UID, userId);
+
+            // Always clear the user settable flags.
+            // If permission review is enabled and this is a legacy app, mark the
+            // permission as requiring a review as this is the initial state.
+            final int uid = mPackageManagerInt.getPackageUid(packageName, 0, userId);
+            final int targetSdk = mPackageManagerInt.getTargetSdk(uid);
+            final int flags = (targetSdk < Build.VERSION_CODES.M && bp.isRuntime())
+                    ? FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE
+                    : 0;
+
+            updatePermissionFlagsInternal(
+                    permName, packageName, userSettableMask, flags, Process.SYSTEM_UID, userId,
+                    false, delayingPermCallback);
+
+            // Below is only runtime permission handling.
+            if (!bp.isRuntime()) {
+                continue;
+            }
+
+            // Never clobber system or policy.
+            if ((oldFlags & policyOrSystemFlags) != 0) {
+                continue;
+            }
+
+            // If this permission was granted by default, make sure it is.
+            if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
+                grantRuntimePermissionInternal(permName, packageName, false,
+                        Process.SYSTEM_UID, userId, delayingPermCallback);
+                // Allow app op later as we are holding mPackages
+                // PermissionPolicyService will handle the app op for foreground/background
+                // permissions.
+                String appOp = AppOpsManager.permissionToOp(permName);
+                if (appOp != null) {
+                    mHandler.post(() -> appOpsManager.setUidMode(appOp, uid,
+                            AppOpsManager.MODE_ALLOWED));
+                }
+            // If permission review is enabled the permissions for a legacy apps
+            // are represented as constantly granted runtime ones, so don't revoke.
+            } else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
+                // Otherwise, reset the permission.
+                revokeRuntimePermissionInternal(permName, packageName, false, Process.SYSTEM_UID,
+                        userId, delayingPermCallback);
+            }
+        }
+
+        // Execute delayed callbacks
+        if (permissionRemoved[0]) {
+            mDefaultPermissionCallback.onPermissionRemoved();
+        }
+
+        // Slight variation on the code in mPermissionCallback.onPermissionRevoked() as we cannot
+        // kill uid while holding mPackages-lock
+        if (!revokedPermissions.isEmpty()) {
+            int numRevokedPermissions = revokedPermissions.size();
+            for (int i = 0; i < numRevokedPermissions; i++) {
+                int revocationUID = IntPair.first(revokedPermissions.valueAt(i));
+                int revocationUserId = IntPair.second(revokedPermissions.valueAt(i));
+
+                mOnPermissionChangeListeners.onPermissionsChanged(revocationUID);
+
+                // Kill app later as we are holding mPackages
+                mHandler.post(() -> killUid(UserHandle.getAppId(revocationUID), revocationUserId,
+                        KILL_APP_REASON_PERMISSIONS_REVOKED));
+            }
+        }
+
+        mPackageManagerInt.writePermissionSettings(syncUpdatedUsers.toArray(), false);
+        mPackageManagerInt.writePermissionSettings(asyncUpdatedUsers.toArray(), true);
+    }
+
+    @Override
+    public String getDefaultBrowser(int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (UserHandle.getUserId(callingUid) != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        }
+        if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+            return null;
+        }
+        synchronized (mLock) {
+            return mDefaultBrowserProvider == null
+                    ? null : mDefaultBrowserProvider.getDefaultBrowser(userId);
+        }
+    }
+
+    @Override
+    public boolean setDefaultBrowser(String packageName, int userId) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+        }
+        return setDefaultBrowserInternal(packageName, false, true, userId);
+    }
+
+    private boolean setDefaultBrowserInternal(String packageName, boolean async,
+            boolean doGrant, int userId) {
+        synchronized (mLock) {
+            if (userId == UserHandle.USER_ALL) {
+                return false;
+            }
+            if (mDefaultBrowserProvider == null) {
+                return false;
+            }
+            if (async) {
+                mDefaultBrowserProvider.setDefaultBrowserAsync(packageName, userId);
+            } else {
+                if (!mDefaultBrowserProvider.setDefaultBrowser(packageName, userId)) {
+                    return false;
+                }
+            }
+            if (doGrant && packageName != null) {
+                mDefaultPermissionGrantPolicy
+                        .grantDefaultPermissionsToDefaultBrowser(packageName, userId);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        PackageManagerServiceUtils
+                .enforceSystemOrPhoneCaller("grantPermissionsToEnabledCarrierApps", callingUid);
+        synchronized (mLock) {
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId));
+        }
+    }
+
+    @Override
+    public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
+                "grantDefaultPermissionsToEnabledImsServices", callingUid);
+        synchronized (mLock) {
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .grantDefaultPermissionsToEnabledImsServices(packageNames, userId));
+        }
+    }
+
+    @Override
+    public void grantDefaultPermissionsToEnabledTelephonyDataServices(
+            String[] packageNames, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
+                "grantDefaultPermissionsToEnabledTelephonyDataServices", callingUid);
+        synchronized (mLock) {
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .grantDefaultPermissionsToEnabledTelephonyDataServices(
+                            packageNames, userId));
+        }
+    }
+
+    @Override
+    public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+            String[] packageNames, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
+                "revokeDefaultPermissionsFromDisabledTelephonyDataServices", callingUid);
+        synchronized (mLock) {
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+                            packageNames, userId));
+        }
+    }
+
+    @Override
+    public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        PackageManagerServiceUtils
+                .enforceSystemOrPhoneCaller("grantDefaultPermissionsToActiveLuiApp", callingUid);
+        synchronized (mLock) {
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .grantDefaultPermissionsToActiveLuiApp(packageName, userId));
+        }
+    }
+
+    @Override
+    public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        PackageManagerServiceUtils
+                .enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromLuiApps", callingUid);
+        synchronized (mLock) {
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .revokeDefaultPermissionsFromLuiApps(packageNames, userId));
+        }
+    }
+
+    @Override
+    public void setPermissionEnforced(String permName, boolean enforced) {
+        // TODO: Now that we no longer change GID for storage, this should to away.
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+                "setPermissionEnforced");
+        if (READ_EXTERNAL_STORAGE.equals(permName)) {
+            mPackageManagerInt.setReadExternalStorageEnforced(enforced);
+            // kill any non-foreground processes so we restart them and
+            // grant/revoke the GID.
+            final IActivityManager am = ActivityManager.getService();
+            if (am != null) {
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    am.killProcessesBelowForeground("setPermissionEnforcement");
+                } catch (RemoteException e) {
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        } else {
+            throw new IllegalArgumentException("No selective enforcement for " + permName);
+        }
+    }
+
+    /** @deprecated */
+    @Override
+    @Deprecated
+    public boolean isPermissionEnforced(String permName) {
+        // allow instant applications
+        return true;
+    }
+
+    @Override
+    public boolean shouldShowRequestPermissionRationale(String permName,
+            String packageName, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "canShowRequestPermissionRationale for user " + userId);
+        }
+
+        final int uid =
+                mPackageManagerInt.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId);
+        if (UserHandle.getAppId(callingUid) != UserHandle.getAppId(uid)) {
+            return false;
+        }
+
+        if (checkPermission(permName, packageName, userId)
+                == PackageManager.PERMISSION_GRANTED) {
+            return false;
+        }
+
+        final int flags;
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            flags = getPermissionFlagsInternal(permName, packageName, callingUid, userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+        final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
+                | PackageManager.FLAG_PERMISSION_POLICY_FIXED
+                | PackageManager.FLAG_PERMISSION_USER_FIXED;
+
+        if ((flags & fixedFlags) != 0) {
+            return false;
+        }
+
+        return (flags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
+    }
+
+    @Override
+    public boolean isPermissionRevokedByPolicy(String permName, String packageName, int userId) {
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "isPermissionRevokedByPolicy for user " + userId);
+        }
+
+        if (checkPermission(permName, packageName, userId) == PackageManager.PERMISSION_GRANTED) {
+            return false;
+        }
+
+        final int callingUid = Binder.getCallingUid();
+        if (mPackageManagerInt.filterAppAccess(packageName, callingUid, userId)) {
+            return false;
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final int flags = getPermissionFlagsInternal(permName, packageName, callingUid, userId);
+            return (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     /**
      * Get the state of the runtime permissions as xml file.
      *
@@ -717,6 +2031,7 @@
             }
         }
 
+        final int callingUid = Binder.getCallingUid();
         final int numNewPackagePermissions = newPackage.permissions.size();
         for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions;
                 newPermissionNum++) {
@@ -741,9 +2056,9 @@
                         final int numPackages = allPackageNames.size();
                         for (int packageNum = 0; packageNum < numPackages; packageNum++) {
                             final String packageName = allPackageNames.get(packageNum);
-
-                            if (checkPermission(permissionName, packageName, UserHandle.USER_SYSTEM,
-                                    userId) == PackageManager.PERMISSION_GRANTED) {
+                            final int permissionState = checkPermissionInternal(
+                                    permissionName, packageName, UserHandle.USER_SYSTEM, userId);
+                            if (permissionState == PackageManager.PERMISSION_GRANTED) {
                                 EventLog.writeEvent(0x534e4554, "72710897",
                                         newPackage.applicationInfo.uid,
                                         "Revoking permission " + permissionName +
@@ -752,8 +2067,8 @@
                                         " to " + newPermissionGroupName);
 
                                 try {
-                                    revokeRuntimePermission(permissionName, packageName, false,
-                                            userId, permissionCallback);
+                                    revokeRuntimePermissionInternal(permissionName, packageName,
+                                            false, callingUid, userId, permissionCallback);
                                 } catch (IllegalArgumentException e) {
                                     Slog.e(TAG, "Could not revoke " + permissionName + " from "
                                             + packageName, e);
@@ -1674,9 +2989,9 @@
         } else if (pkg.isProduct()) {
             wlPermissions =
                     SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName);
-        } else if (pkg.isProductServices()) {
+        } else if (pkg.isSystemExt()) {
             wlPermissions =
-                    SystemConfig.getInstance().getProductServicesPrivAppPermissions(
+                    SystemConfig.getInstance().getSystemExtPrivAppPermissions(
                             pkg.packageName);
         } else {
             wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
@@ -1710,9 +3025,9 @@
                     } else if (pkg.isProduct()) {
                         deniedPermissions = SystemConfig.getInstance()
                                 .getProductPrivAppDenyPermissions(pkg.packageName);
-                    } else if (pkg.isProductServices()) {
+                    } else if (pkg.isSystemExt()) {
                         deniedPermissions = SystemConfig.getInstance()
-                                .getProductServicesPrivAppDenyPermissions(pkg.packageName);
+                                .getSystemExtPrivAppDenyPermissions(pkg.packageName);
                     } else {
                         deniedPermissions = SystemConfig.getInstance()
                                 .getPrivAppDenyPermissions(pkg.packageName);
@@ -1721,13 +3036,15 @@
                             deniedPermissions == null || !deniedPermissions.contains(perm);
                     if (permissionViolation) {
                         Slog.w(TAG, "Privileged permission " + perm + " for package "
-                                + pkg.packageName + " - not in privapp-permissions whitelist");
+                                + pkg.packageName + " (" + pkg.codePath
+                                + ") not in privapp-permissions whitelist");
 
                         if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
                             if (mPrivappPermissionsViolations == null) {
                                 mPrivappPermissionsViolations = new ArraySet<>();
                             }
-                            mPrivappPermissionsViolations.add(pkg.packageName + ": " + perm);
+                            mPrivappPermissionsViolations.add(
+                                    pkg.packageName + " (" + pkg.codePath + "): " + perm);
                         }
                     } else {
                         return false;
@@ -2001,7 +3318,7 @@
             }
             for (int userId : mUserManagerInt.getUserIds()) {
                 if (disabledPs.getPermissionsState().hasRuntimePermission(permission, userId)) {
-                    grantRuntimePermission(
+                    grantRuntimePermissionInternal(
                             permission, pkg.packageName, false, callingUid, userId, callback);
                 }
             }
@@ -2016,54 +3333,6 @@
         }
     }
 
-    private @Nullable List<String> getWhitelistedRestrictedPermissions(
-            @NonNull PackageParser.Package pkg, @PermissionWhitelistFlags int whitelistFlags,
-            @UserIdInt int userId) {
-        final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
-        if (packageSetting == null) {
-            return null;
-        }
-
-        final PermissionsState permissionsState = packageSetting.getPermissionsState();
-
-        int queryFlags = 0;
-        if ((whitelistFlags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0) {
-            queryFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
-        }
-        if ((whitelistFlags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
-            queryFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
-        }
-        if ((whitelistFlags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
-            queryFlags |=  PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
-        }
-
-        ArrayList<String> whitelistedPermissions = null;
-
-        final int permissionCount = pkg.requestedPermissions.size();
-        for (int i = 0; i < permissionCount; i++) {
-            final String permissionName = pkg.requestedPermissions.get(i);
-            final int currentFlags = permissionsState.getPermissionFlags(permissionName, userId);
-            if ((currentFlags & queryFlags) != 0) {
-                if (whitelistedPermissions == null) {
-                    whitelistedPermissions = new ArrayList<>();
-                }
-                whitelistedPermissions.add(permissionName);
-            }
-        }
-
-        return whitelistedPermissions;
-    }
-
-    private void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg,
-            @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid,
-            @PackageManager.PermissionWhitelistFlags int whitelistFlags,
-            @NonNull PermissionCallback callback) {
-        for (int userId : userIds) {
-            setWhitelistedRestrictedPermissionsForUser(pkg, userId, permissions,
-                    callingUid, whitelistFlags, callback);
-        }
-    }
-
     private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
             String[] grantedPermissions, int callingUid, PermissionCallback callback) {
         PackageSetting ps = (PackageSetting) pkg.mExtras;
@@ -2095,14 +3364,14 @@
                 if (supportsRuntimePermissions) {
                     // Installer cannot change immutable permissions.
                     if ((flags & immutableFlags) == 0) {
-                        grantRuntimePermission(permission, pkg.packageName, false, callingUid,
-                                userId, callback);
+                        grantRuntimePermissionInternal(permission, pkg.packageName, false,
+                                callingUid, userId, callback);
                     }
                 } else {
                     // In permission review mode we clear the review flag when we
                     // are asked to install the app with all permissions granted.
                     if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
-                        updatePermissionFlags(permission, pkg.packageName,
+                        updatePermissionFlagsInternal(permission, pkg.packageName,
                                 PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, callingUid,
                                 userId, false, callback);
                     }
@@ -2111,262 +3380,15 @@
         }
     }
 
-    private void grantRuntimePermission(String permName, String packageName, boolean overridePolicy,
-            int callingUid, final int userId, PermissionCallback callback) {
-        if (ApplicationPackageManager.DEBUG_TRACE_GRANTS
-                && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) {
-            Log.i(TAG, "System is granting "
-                    + permName + " for user " + userId + " on behalf of uid " + callingUid
-                    + " " + mPackageManagerInt.getNameForUid(callingUid),
-                    new RuntimeException());
-        }
-        if (!mUserManagerInt.exists(userId)) {
-            Log.e(TAG, "No such user:" + userId);
-            return;
-        }
-
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
-                "grantRuntimePermission");
-
-        enforceCrossUserPermission(callingUid, userId,
-                true,  // requireFullPermission
-                true,  // checkShell
-                false, // requirePermissionWhenSameUser
-                "grantRuntimePermission");
-
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
-        }
-        final BasePermission bp;
-        synchronized(mLock) {
-            bp = mSettings.getPermissionLocked(permName);
-        }
-        if (bp == null) {
-            throw new IllegalArgumentException("Unknown permission: " + permName);
-        }
-        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
-        }
-
-        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
-
-        // If a permission review is required for legacy apps we represent
-        // their permissions as always granted runtime ones since we need
-        // to keep the review required permission flag per user while an
-        // install permission's state is shared across all users.
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
-                && bp.isRuntime()) {
-            return;
-        }
-
-        final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
-
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
-        final PermissionsState permissionsState = ps.getPermissionsState();
-
-        final int flags = permissionsState.getPermissionFlags(permName, userId);
-        if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
-            Log.e(TAG, "Cannot grant system fixed permission "
-                    + permName + " for package " + packageName);
-            return;
-        }
-        if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
-            Log.e(TAG, "Cannot grant policy fixed permission "
-                    + permName + " for package " + packageName);
-            return;
-        }
-
-        if (bp.isHardRestricted()
-                && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
-            Log.e(TAG, "Cannot grant hard restricted non-exempt permission "
-                    + permName + " for package " + packageName);
-            return;
-        }
-
-        if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext,
-                pkg.applicationInfo, UserHandle.of(userId), permName).canBeGranted()) {
-            Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package "
-                    + packageName);
-            return;
-        }
-
-        if (bp.isDevelopment()) {
-            // Development permissions must be handled specially, since they are not
-            // normal runtime permissions.  For now they apply to all users.
-            if (permissionsState.grantInstallPermission(bp) !=
-                    PERMISSION_OPERATION_FAILURE) {
-                if (callback != null) {
-                    callback.onInstallPermissionGranted();
-                }
-            }
-            return;
-        }
-
-        if (ps.getInstantApp(userId) && !bp.isInstant()) {
-            throw new SecurityException("Cannot grant non-ephemeral permission"
-                    + permName + " for package " + packageName);
-        }
-
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
-            Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
-            return;
-        }
-
-        final int result = permissionsState.grantRuntimePermission(bp, userId);
-        switch (result) {
-            case PERMISSION_OPERATION_FAILURE: {
-                return;
-            }
-
-            case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
-                if (callback != null) {
-                    callback.onGidsChanged(UserHandle.getAppId(pkg.applicationInfo.uid), userId);
-                }
-            }
-            break;
-        }
-
-        if (bp.isRuntime()) {
-            logPermission(MetricsEvent.ACTION_PERMISSION_GRANTED, permName, packageName);
-        }
-
-        if (callback != null) {
-            callback.onPermissionGranted(uid, userId);
-        }
-
-        if (bp.isRuntime()) {
-            notifyRuntimePermissionStateChanged(packageName, userId);
-        }
-
-        // Only need to do this if user is initialized. Otherwise it's a new user
-        // and there are no processes running as the user yet and there's no need
-        // to make an expensive call to remount processes for the changed permissions.
-        if (READ_EXTERNAL_STORAGE.equals(permName)
-                || WRITE_EXTERNAL_STORAGE.equals(permName)) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                if (mUserManagerInt.isUserInitialized(userId)) {
-                    StorageManagerInternal storageManagerInternal = LocalServices.getService(
-                            StorageManagerInternal.class);
-                    storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-    }
-
-    private void revokeRuntimePermission(String permName, String packageName,
-            boolean overridePolicy, int userId, PermissionCallback callback) {
-        int callingUid = Binder.getCallingUid();
-        if (ApplicationPackageManager.DEBUG_TRACE_GRANTS
-                && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) {
-            Log.i(TAG, "System is revoking "
-                            + permName + " for user " + userId + " on behalf of uid " + callingUid
-                            + " " + mPackageManagerInt.getNameForUid(callingUid),
-                    new RuntimeException());
-        }
-        if (!mUserManagerInt.exists(userId)) {
-            Log.e(TAG, "No such user:" + userId);
-            return;
-        }
-
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
-                "revokeRuntimePermission");
-
-        enforceCrossUserPermission(callingUid, userId,
-                true,  // requireFullPermission
-                true,  // checkShell
-                false, // requirePermissionWhenSameUser
-                "revokeRuntimePermission");
-
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
-        }
-        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
-        }
-        final BasePermission bp = mSettings.getPermissionLocked(permName);
-        if (bp == null) {
-            throw new IllegalArgumentException("Unknown permission: " + permName);
-        }
-
-        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
-
-        // If a permission review is required for legacy apps we represent
-        // their permissions as always granted runtime ones since we need
-        // to keep the review required permission flag per user while an
-        // install permission's state is shared across all users.
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
-                && bp.isRuntime()) {
-            return;
-        }
-
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
-        final PermissionsState permissionsState = ps.getPermissionsState();
-
-        final int flags = permissionsState.getPermissionFlags(permName, userId);
-        // Only the system may revoke SYSTEM_FIXED permissions.
-        if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
-                && UserHandle.getCallingAppId() != Process.SYSTEM_UID) {
-            throw new SecurityException("Non-System UID cannot revoke system fixed permission "
-                    + permName + " for package " + packageName);
-        }
-        if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
-            throw new SecurityException("Cannot revoke policy fixed permission "
-                    + permName + " for package " + packageName);
-        }
-
-        if (bp.isDevelopment()) {
-            // Development permissions must be handled specially, since they are not
-            // normal runtime permissions.  For now they apply to all users.
-            if (permissionsState.revokeInstallPermission(bp) !=
-                    PERMISSION_OPERATION_FAILURE) {
-                if (callback != null) {
-                    callback.onInstallPermissionRevoked();
-                }
-            }
-            return;
-        }
-
-        // Permission is already revoked, no need to do anything.
-        if (!permissionsState.hasRuntimePermission(permName, userId)) {
-            return;
-        }
-
-        if (permissionsState.revokeRuntimePermission(bp, userId) ==
-                PERMISSION_OPERATION_FAILURE) {
-            return;
-        }
-
-        if (bp.isRuntime()) {
-            logPermission(MetricsEvent.ACTION_PERMISSION_REVOKED, permName, packageName);
-        }
-
-        if (callback != null) {
-            callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
-        }
-
-        if (bp.isRuntime()) {
-            notifyRuntimePermissionStateChanged(packageName, userId);
-        }
-    }
-
     private void setWhitelistedRestrictedPermissionsForUser(@NonNull PackageParser.Package pkg,
             @UserIdInt int userId, @Nullable List<String> permissions, int callingUid,
             @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
-        if (ps == null) {
+        final PermissionsState permissionsState =
+                PackageManagerServiceUtils.getPermissionsState(pkg);
+        if (permissionsState == null) {
             return;
         }
 
-        final PermissionsState permissionsState = ps.getPermissionsState();
-
         ArraySet<String> oldGrantedRestrictedPermissions = null;
         boolean updatePermissions = false;
 
@@ -2454,7 +3476,7 @@
                 newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
             }
 
-            updatePermissionFlags(permissionName, pkg.packageName, mask, newFlags,
+            updatePermissionFlagsInternal(permissionName, pkg.packageName, mask, newFlags,
                     callingUid, userId, false, null /*callback*/);
         }
 
@@ -2468,7 +3490,9 @@
                 for (int i = 0; i < oldGrantedCount; i++) {
                     final String permission = oldGrantedRestrictedPermissions.valueAt(i);
                     // Sometimes we create a new permission state instance during update.
-                    if (!ps.getPermissionsState().hasPermission(permission, userId)) {
+                    final PermissionsState newPermissionsState =
+                            PackageManagerServiceUtils.getPermissionsState(pkg);
+                    if (!newPermissionsState.hasPermission(permission, userId)) {
                         callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
                         break;
                     }
@@ -2541,37 +3565,6 @@
         return runtimePermissionChangedUserIds;
     }
 
-    private int getPermissionFlags(
-            String permName, String packageName, int callingUid, int userId) {
-        if (!mUserManagerInt.exists(userId)) {
-            return 0;
-        }
-
-        enforceGrantRevokeGetRuntimePermissionPermissions("getPermissionFlags");
-
-        enforceCrossUserPermission(callingUid, userId,
-                true,  // requireFullPermission
-                false, // checkShell
-                false, // requirePermissionWhenSameUser
-                "getPermissionFlags");
-
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
-            return 0;
-        }
-        synchronized (mLock) {
-            if (mSettings.getPermissionLocked(permName) == null) {
-                return 0;
-            }
-        }
-        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
-            return 0;
-        }
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
-        PermissionsState permissionsState = ps.getPermissionsState();
-        return permissionsState.getPermissionFlags(permName, userId);
-    }
-
     /**
      * Update permissions when a package changed.
      *
@@ -2586,16 +3579,15 @@
      * @param callback Callback to call after permission changes
      */
     private void updatePermissions(@NonNull String packageName, @Nullable PackageParser.Package pkg,
-            @NonNull Collection<PackageParser.Package> allPackages,
             @NonNull PermissionCallback callback) {
         final int flags =
                 (pkg != null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG : 0);
         updatePermissions(
-                packageName, pkg, getVolumeUuidForPackage(pkg), flags, allPackages, callback);
+                packageName, pkg, getVolumeUuidForPackage(pkg), flags, callback);
         if (pkg != null && pkg.childPackages != null) {
             for (PackageParser.Package childPkg : pkg.childPackages) {
                 updatePermissions(childPkg.packageName, childPkg,
-                        getVolumeUuidForPackage(childPkg), flags, allPackages, callback);
+                        getVolumeUuidForPackage(childPkg), flags, callback);
             }
         }
     }
@@ -2613,13 +3605,12 @@
      * @param callback Callback to call after permission changes
      */
     private void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdated,
-            @NonNull Collection<PackageParser.Package> allPackages,
             @NonNull PermissionCallback callback) {
         final int flags = UPDATE_PERMISSIONS_ALL |
                 (sdkUpdated
                         ? UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL
                         : 0);
-        updatePermissions(null, null, volumeUuid, flags, allPackages, callback);
+        updatePermissions(null, null, volumeUuid, flags, callback);
     }
 
     /**
@@ -2697,11 +3688,11 @@
      * @param allPackages All currently known packages
      * @param callback Callback to call after permission changes
      */
-    private void updatePermissions(@Nullable String changingPkgName,
-            @Nullable PackageParser.Package changingPkg, @Nullable String replaceVolumeUuid,
+    private void updatePermissions(final @Nullable String changingPkgName,
+            final @Nullable PackageParser.Package changingPkg,
+            final @Nullable String replaceVolumeUuid,
             @UpdatePermissionFlags int flags,
-            @NonNull Collection<PackageParser.Package> allPackages,
-            @Nullable PermissionCallback callback) {
+            final @Nullable PermissionCallback callback) {
         // TODO: Most of the methods exposing BasePermission internals [source package name,
         // etc..] shouldn't be needed. Instead, when we've parsed a permission that doesn't
         // have package settings, we should make note of it elsewhere [map between
@@ -2730,15 +3721,16 @@
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "restorePermissionState");
         // Now update the permissions for all packages.
         if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {
-            for (PackageParser.Package pkg : allPackages) {
-                if (pkg != changingPkg) {
-                    // Only replace for packages on requested volume
-                    final String volumeUuid = getVolumeUuidForPackage(pkg);
-                    final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0)
-                            && Objects.equals(replaceVolumeUuid, volumeUuid);
-                    restorePermissionState(pkg, replace, changingPkgName, callback);
+            final boolean replaceAll = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0);
+            mPackageManagerInt.forEachPackage((Package pkg) -> {
+                if (pkg == changingPkg) {
+                    return;
                 }
-            }
+                // Only replace for packages on requested volume
+                final String volumeUuid = getVolumeUuidForPackage(pkg);
+                final boolean replace = replaceAll && Objects.equals(replaceVolumeUuid, volumeUuid);
+                restorePermissionState(pkg, replace, changingPkgName, callback);
+            });
         }
 
         if (changingPkg != null) {
@@ -2880,127 +3872,6 @@
         return changed;
     }
 
-    private void updatePermissionFlags(String permName, String packageName, int flagMask,
-            int flagValues, int callingUid, int userId, boolean overridePolicy,
-            PermissionCallback callback) {
-        if (ApplicationPackageManager.DEBUG_TRACE_GRANTS
-                && ApplicationPackageManager.shouldTraceGrant(packageName, permName, userId)) {
-            Log.i(TAG, "System is updating flags for "
-                            + permName + " for user " + userId  + " "
-                            + DebugUtils.flagsToString(
-                                    PackageManager.class, "FLAG_PERMISSION_", flagMask)
-                            + " := "
-                            + DebugUtils.flagsToString(
-                                    PackageManager.class, "FLAG_PERMISSION_", flagValues)
-                            + " on behalf of uid " + callingUid
-                            + " " + mPackageManagerInt.getNameForUid(callingUid),
-                    new RuntimeException());
-        }
-
-        if (!mUserManagerInt.exists(userId)) {
-            return;
-        }
-
-        enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlags");
-
-        enforceCrossUserPermission(callingUid, userId,
-                true,  // requireFullPermission
-                true,  // checkShell
-                false, // requirePermissionWhenSameUser
-                "updatePermissionFlags");
-
-        if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0 && !overridePolicy) {
-            throw new SecurityException("updatePermissionFlags requires "
-                    + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
-        }
-
-        // Only the system can change these flags and nothing else.
-        if (callingUid != Process.SYSTEM_UID) {
-            flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
-            flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
-            flagMask &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
-            flagValues &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
-            flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
-            flagValues &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
-            flagValues &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
-            flagValues &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
-            flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
-        }
-
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
-            Log.e(TAG, "Unknown package: " + packageName);
-            return;
-        }
-        if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
-        }
-
-        final BasePermission bp;
-        synchronized (mLock) {
-            bp = mSettings.getPermissionLocked(permName);
-        }
-        if (bp == null) {
-            throw new IllegalArgumentException("Unknown permission: " + permName);
-        }
-
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
-        final PermissionsState permissionsState = ps.getPermissionsState();
-        final boolean hadState =
-                permissionsState.getRuntimePermissionState(permName, userId) != null;
-        final boolean permissionUpdated =
-                permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues);
-        if (permissionUpdated && bp.isRuntime()) {
-            notifyRuntimePermissionStateChanged(packageName, userId);
-        }
-        if (permissionUpdated && callback != null) {
-            // Install and runtime permissions are stored in different places,
-            // so figure out what permission changed and persist the change.
-            if (permissionsState.getInstallPermissionState(permName) != null) {
-                callback.onInstallPermissionUpdatedNotifyListener(pkg.applicationInfo.uid);
-            } else if (permissionsState.getRuntimePermissionState(permName, userId) != null
-                    || hadState) {
-                callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
-                        pkg.applicationInfo.uid);
-            }
-        }
-    }
-
-    private boolean updatePermissionFlagsForAllApps(int flagMask, int flagValues, int callingUid,
-            int userId, Collection<Package> packages, PermissionCallback callback) {
-        if (!mUserManagerInt.exists(userId)) {
-            return false;
-        }
-
-        enforceGrantRevokeRuntimePermissionPermissions(
-                "updatePermissionFlagsForAllApps");
-        enforceCrossUserPermission(callingUid, userId,
-                true,  // requireFullPermission
-                true,  // checkShell
-                false, // requirePermissionWhenSameUser
-                "updatePermissionFlagsForAllApps");
-
-        // Only the system can change system fixed flags.
-        if (callingUid != Process.SYSTEM_UID) {
-            flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
-            flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
-        }
-
-        boolean changed = false;
-        for (PackageParser.Package pkg : packages) {
-            final PackageSetting ps = (PackageSetting) pkg.mExtras;
-            if (ps == null) {
-                continue;
-            }
-            PermissionsState permissionsState = ps.getPermissionsState();
-            changed |= permissionsState.updatePermissionFlagsForAllPermissions(
-                    userId, flagMask, flagValues);
-            callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
-                    pkg.applicationInfo.uid);
-        }
-        return changed;
-    }
-
     private void enforceGrantRevokeRuntimePermissionPermissions(String message) {
         if (mContext.checkCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
                 != PackageManager.PERMISSION_GRANTED
@@ -3088,6 +3959,24 @@
         }
 
         mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
+
+        int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
+        for (int userId : UserManagerService.getInstance().getUserIds()) {
+            if (!mPackageManagerInt.areDefaultRuntimePermissionsGranted(userId)) {
+                grantPermissionsUserIds = ArrayUtils.appendInt(
+                        grantPermissionsUserIds, userId);
+            }
+        }
+        // If we upgraded grant all default permissions before kicking off.
+        for (int userId : grantPermissionsUserIds) {
+            mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
+        }
+        if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
+            // If we did not grant default permissions, we preload from this the
+            // default permission exceptions lazily to ensure we don't hit the
+            // disk on a new user creation.
+            mDefaultPermissionGrantPolicy.scheduleReadDefaultPermissionExceptions();
+        }
     }
 
     private static String getVolumeUuidForPackage(PackageParser.Package pkg) {
@@ -3153,10 +4042,9 @@
         public void revokeRuntimePermissionsIfGroupChanged(
                 @NonNull PackageParser.Package newPackage,
                 @NonNull PackageParser.Package oldPackage,
-                @NonNull ArrayList<String> allPackageNames,
-                @NonNull PermissionCallback permissionCallback) {
+                @NonNull ArrayList<String> allPackageNames) {
             PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage,
-                    oldPackage, allPackageNames, permissionCallback);
+                    oldPackage, allPackageNames, mDefaultPermissionCallback);
         }
         @Override
         public void addAllPermissions(Package pkg, boolean chatty) {
@@ -3171,57 +4059,50 @@
             PermissionManagerService.this.removeAllPermissions(pkg, chatty);
         }
         @Override
-        public void grantRuntimePermission(String permName, String packageName,
-                boolean overridePolicy, int callingUid, int userId,
-                PermissionCallback callback) {
-            PermissionManagerService.this.grantRuntimePermission(
-                    permName, packageName, overridePolicy, callingUid, userId, callback);
-        }
-        @Override
         public void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
-                String[] grantedPermissions, int callingUid, PermissionCallback callback) {
+                String[] grantedPermissions, int callingUid) {
             PermissionManagerService.this.grantRequestedRuntimePermissions(
-                    pkg, userIds, grantedPermissions, callingUid, callback);
-        }
-        @Override
-        public List<String> getWhitelistedRestrictedPermissions(PackageParser.Package pkg,
-                @PackageManager.PermissionWhitelistFlags int whitelistFlags, int userId) {
-            return PermissionManagerService.this.getWhitelistedRestrictedPermissions(pkg,
-                    whitelistFlags, userId);
+                    pkg, userIds, grantedPermissions, callingUid, mDefaultPermissionCallback);
         }
         @Override
         public void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg,
                 @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid,
-                @PackageManager.PermissionWhitelistFlags int whitelistFlags,
-                @NonNull PermissionCallback callback) {
-            PermissionManagerService.this.setWhitelistedRestrictedPermissions(
-                    pkg, userIds, permissions, callingUid, whitelistFlags, callback);
+                @PackageManager.PermissionWhitelistFlags int flags) {
+            for (int userId : userIds) {
+                setWhitelistedRestrictedPermissionsForUser(pkg, userId, permissions,
+                        callingUid, flags, mDefaultPermissionCallback);
+            }
+        }
+        @Override
+        public void setWhitelistedRestrictedPermissions(String packageName,
+                List<String> permissions, int flags, int userId) {
+            PermissionManagerService.this.setWhitelistedRestrictedPermissionsInternal(
+                    packageName, permissions, flags, userId);
         }
         @Override
         public void grantRuntimePermissionsGrantedToDisabledPackage(PackageParser.Package pkg,
-                int callingUid, PermissionCallback callback) {
+                int callingUid) {
             PermissionManagerService.this.grantRuntimePermissionsGrantedToDisabledPackageLocked(
-                    pkg, callingUid, callback);
+                    pkg, callingUid, mDefaultPermissionCallback);
         }
         @Override
-        public void revokeRuntimePermission(String permName, String packageName,
-                boolean overridePolicy, int userId, PermissionCallback callback) {
-            PermissionManagerService.this.revokeRuntimePermission(permName, packageName,
-                    overridePolicy, userId, callback);
+        public void updatePermissions(@NonNull String packageName, @Nullable Package pkg) {
+            PermissionManagerService.this
+                    .updatePermissions(packageName, pkg, mDefaultPermissionCallback);
         }
         @Override
-        public void updatePermissions(@NonNull String packageName, @Nullable Package pkg,
-                @NonNull Collection<PackageParser.Package> allPackages,
-                @NonNull PermissionCallback callback) {
-            PermissionManagerService.this.updatePermissions(
-                    packageName, pkg, allPackages, callback);
+        public void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdated) {
+            PermissionManagerService.this
+                    .updateAllPermissions(volumeUuid, sdkUpdated, mDefaultPermissionCallback);
         }
         @Override
-        public void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdated,
-                @NonNull Collection<PackageParser.Package> allPackages,
-                @NonNull PermissionCallback callback) {
-            PermissionManagerService.this.updateAllPermissions(
-                    volumeUuid, sdkUpdated, allPackages, callback);
+        public void resetRuntimePermissions(Package pkg, int userId) {
+            PermissionManagerService.this.resetRuntimePermissionsInternal(pkg, userId);
+        }
+        @Override
+        public void resetAllRuntimePermissions(final int userId) {
+            mPackageManagerInt.forEachPackage(
+                    (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId));
         }
         @Override
         public String[] getAppOpPermissionPackages(String permName, int callingUid) {
@@ -3229,26 +4110,6 @@
                     .getAppOpPermissionPackagesInternal(permName, callingUid);
         }
         @Override
-        public int getPermissionFlags(String permName, String packageName, int callingUid,
-                int userId) {
-            return PermissionManagerService.this.getPermissionFlags(permName, packageName,
-                    callingUid, userId);
-        }
-        @Override
-        public void updatePermissionFlags(String permName, String packageName, int flagMask,
-                int flagValues, int callingUid, int userId, boolean overridePolicy,
-                PermissionCallback callback) {
-            PermissionManagerService.this.updatePermissionFlags(
-                    permName, packageName, flagMask, flagValues, callingUid, userId,
-                    overridePolicy, callback);
-        }
-        @Override
-        public boolean updatePermissionFlagsForAllApps(int flagMask, int flagValues, int callingUid,
-                int userId, Collection<Package> packages, PermissionCallback callback) {
-            return PermissionManagerService.this.updatePermissionFlagsForAllApps(
-                    flagMask, flagValues, callingUid, userId, packages, callback);
-        }
-        @Override
         public void enforceCrossUserPermission(int callingUid, int userId,
                 boolean requireFullPermission, boolean checkShell, String message) {
             PermissionManagerService.this.enforceCrossUserPermission(callingUid, userId,
@@ -3266,25 +4127,10 @@
             PermissionManagerService.this.enforceGrantRevokeRuntimePermissionPermissions(message);
         }
         @Override
-        public int checkPermission(String permName, String packageName, int callingUid,
-                int userId) {
-            return PermissionManagerService.this.checkPermission(
-                    permName, packageName, callingUid, userId);
-        }
-        @Override
-        public int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
-                int callingUid) {
-            return PermissionManagerService.this.checkUidPermission(permName, pkg, uid, callingUid);
-        }
-        @Override
         public PermissionSettings getPermissionSettings() {
             return mSettings;
         }
         @Override
-        public DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() {
-            return mDefaultPermissionGrantPolicy;
-        }
-        @Override
         public BasePermission getPermissionTEMP(String permName) {
             synchronized (PermissionManagerService.this.mLock) {
                 return mSettings.getPermissionLocked(permName);
@@ -3341,5 +4187,233 @@
             PermissionManagerService.this.removeOnRuntimePermissionStateChangedListener(
                     listener);
         }
+
+        @Override
+        public CheckPermissionDelegate getCheckPermissionDelegate() {
+            synchronized (mLock) {
+                return mCheckPermissionDelegate;
+            }
+        }
+
+        @Override
+        public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) {
+            synchronized (mLock) {
+                mCheckPermissionDelegate = delegate;
+            }
+        }
+
+        @Override
+        public void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider) {
+            synchronized (mLock) {
+                mDefaultBrowserProvider = provider;
+            }
+        }
+
+        @Override
+        public void setDefaultBrowser(String packageName, boolean async, boolean doGrant,
+                int userId) {
+            setDefaultBrowserInternal(packageName, async, doGrant, userId);
+        }
+
+        @Override
+        public void setDefaultDialerProvider(@NonNull DefaultDialerProvider provider) {
+            synchronized (mLock) {
+                mDefaultDialerProvider = provider;
+            }
+        }
+
+        @Override
+        public void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider) {
+            synchronized (mLock) {
+                mDefaultHomeProvider = provider;
+            }
+        }
+
+        @Override
+        public void setDefaultHome(String packageName, int userId, Consumer<Boolean> callback) {
+            synchronized (mLock) {
+                if (userId == UserHandle.USER_ALL) {
+                    return;
+                }
+                if (mDefaultHomeProvider == null) {
+                    return;
+                }
+                mDefaultHomeProvider.setDefaultHomeAsync(packageName, userId, callback);
+            }
+        }
+
+        @Override
+        public void setDialerAppPackagesProvider(PackagesProvider provider) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.setDialerAppPackagesProvider(provider);
+            }
+        }
+
+        @Override
+        public void setLocationExtraPackagesProvider(PackagesProvider provider) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.setLocationExtraPackagesProvider(provider);
+            }
+        }
+
+        @Override
+        public void setLocationPackagesProvider(PackagesProvider provider) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.setLocationPackagesProvider(provider);
+            }
+        }
+
+        @Override
+        public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.setSimCallManagerPackagesProvider(provider);
+            }
+        }
+
+        @Override
+        public void setSmsAppPackagesProvider(PackagesProvider provider) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.setSmsAppPackagesProvider(provider);
+            }
+        }
+
+        @Override
+        public void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.setSyncAdapterPackagesProvider(provider);
+            }
+        }
+
+        @Override
+        public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.setUseOpenWifiAppPackagesProvider(provider);
+            }
+        }
+
+        @Override
+        public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.setVoiceInteractionPackagesProvider(provider);
+            }
+        }
+
+        @Override
+        public String getDefaultBrowser(int userId) {
+            synchronized (mLock) {
+                return mDefaultBrowserProvider == null
+                        ? null : mDefaultBrowserProvider.getDefaultBrowser(userId);
+            }
+        }
+
+        @Override
+        public String getDefaultDialer(int userId) {
+            synchronized (mLock) {
+                return mDefaultDialerProvider == null
+                        ? null : mDefaultDialerProvider.getDefaultDialer(userId);
+            }
+        }
+
+        @Override
+        public String getDefaultHome(int userId) {
+            synchronized (mLock) {
+                return mDefaultHomeProvider == null
+                        ? null : mDefaultHomeProvider.getDefaultHome(userId);
+            }
+        }
+
+        @Override
+        public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy
+                        .grantDefaultPermissionsToDefaultSimCallManager(packageName, userId);
+            }
+        }
+
+        @Override
+        public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy
+                        .grantDefaultPermissionsToDefaultUseOpenWifiApp(packageName, userId);
+            }
+        }
+
+        @Override
+        public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy
+                        .grantDefaultPermissionsToDefaultBrowser(packageName, userId);
+            }
+        }
+
+        @Override
+        public boolean wereDefaultPermissionsGrantedSinceBoot(int userId) {
+            synchronized (mLock) {
+                return mDefaultPermissionGrantPolicy.wereDefaultPermissionsGrantedSinceBoot(userId);
+            }
+        }
+
+        @Override
+        public void onNewUserCreated(int userId) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
+                // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
+                PermissionManagerService.this.updateAllPermissions(
+                        StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
+            }
+        }
+    }
+
+    private static final class OnPermissionChangeListeners extends Handler {
+        private static final int MSG_ON_PERMISSIONS_CHANGED = 1;
+
+        private final RemoteCallbackList<IOnPermissionsChangeListener> mPermissionListeners =
+                new RemoteCallbackList<>();
+
+        OnPermissionChangeListeners(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_PERMISSIONS_CHANGED: {
+                    final int uid = msg.arg1;
+                    handleOnPermissionsChanged(uid);
+                } break;
+            }
+        }
+
+        public void addListenerLocked(IOnPermissionsChangeListener listener) {
+            mPermissionListeners.register(listener);
+
+        }
+
+        public void removeListenerLocked(IOnPermissionsChangeListener listener) {
+            mPermissionListeners.unregister(listener);
+        }
+
+        public void onPermissionsChanged(int uid) {
+            if (mPermissionListeners.getRegisteredCallbackCount() > 0) {
+                obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
+            }
+        }
+
+        private void handleOnPermissionsChanged(int uid) {
+            final int count = mPermissionListeners.beginBroadcast();
+            try {
+                for (int i = 0; i < count; i++) {
+                    IOnPermissionsChangeListener callback = mPermissionListeners
+                            .getBroadcastItem(i);
+                    try {
+                        callback.onPermissionsChanged(uid);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Permission listener is dead", e);
+                    }
+                }
+            } finally {
+                mPermissionListeners.finishBroadcast();
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index a785575..04ec5ba 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -26,8 +26,8 @@
 import android.permission.PermissionManagerInternal;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Internal interfaces services.
@@ -36,6 +36,109 @@
  */
 public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
     /**
+     * Provider for package names.
+     */
+    public interface PackagesProvider {
+
+        /**
+         * Gets the packages for a given user.
+         * @param userId The user id.
+         * @return The package names.
+         */
+        String[] getPackages(int userId);
+    }
+
+    /**
+     * Provider for package names.
+     */
+    public interface SyncAdapterPackagesProvider {
+
+        /**
+         * Gets the sync adapter packages for given authority and user.
+         * @param authority The authority.
+         * @param userId The user id.
+         * @return The package names.
+         */
+        String[] getPackages(String authority, int userId);
+    }
+
+    /**
+     * Provider for default browser
+     */
+    public interface DefaultBrowserProvider {
+
+        /**
+         * Get the package name of the default browser.
+         *
+         * @param userId the user id
+         *
+         * @return the package name of the default browser, or {@code null} if none
+         */
+        @Nullable
+        String getDefaultBrowser(@UserIdInt int userId);
+
+        /**
+         * Set the package name of the default browser.
+         *
+         * @param packageName package name of the default browser, or {@code null} to remove
+         * @param userId the user id
+         *
+         * @return whether the default browser was successfully set.
+         */
+        boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId);
+
+        /**
+         * Set the package name of the default browser asynchronously.
+         *
+         * @param packageName package name of the default browser, or {@code null} to remove
+         * @param userId the user id
+         */
+        void setDefaultBrowserAsync(@Nullable String packageName, @UserIdInt int userId);
+    }
+
+    /**
+     * Provider for default dialer
+     */
+    public interface DefaultDialerProvider {
+
+        /**
+         * Get the package name of the default dialer.
+         *
+         * @param userId the user id
+         *
+         * @return the package name of the default dialer, or {@code null} if none
+         */
+        @Nullable
+        String getDefaultDialer(@UserIdInt int userId);
+    }
+
+    /**
+     * Provider for default home
+     */
+    public interface DefaultHomeProvider {
+
+        /**
+         * Get the package name of the default home.
+         *
+         * @param userId the user id
+         *
+         * @return the package name of the default home, or {@code null} if none
+         */
+        @Nullable
+        String getDefaultHome(@UserIdInt int userId);
+
+        /**
+         * Set the package name of the default home.
+         *
+         * @param packageName package name of the default home, or {@code null} to remove
+         * @param userId the user id
+         * @param callback the callback made after the default home as been updated
+         */
+        void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId,
+                @NonNull Consumer<Boolean> callback);
+    }
+
+    /**
      * Callbacks invoked when interesting actions have been taken on a permission.
      * <p>
      * NOTE: The current arguments are merely to support the existing use cases. This
@@ -73,27 +176,19 @@
     public abstract boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg,
             @UserIdInt int userId);
 
-    public abstract void grantRuntimePermission(
-            @NonNull String permName, @NonNull String packageName, boolean overridePolicy,
-            int callingUid, int userId, @Nullable PermissionCallback callback);
     public abstract void grantRuntimePermissionsGrantedToDisabledPackage(
-            @NonNull PackageParser.Package pkg, int callingUid,
-            @Nullable PermissionCallback callback);
+            @NonNull PackageParser.Package pkg, int callingUid);
     public abstract void grantRequestedRuntimePermissions(
             @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
-            @NonNull String[] grantedPermissions, int callingUid,
-            @Nullable PermissionCallback callback);
-    public abstract @Nullable List<String> getWhitelistedRestrictedPermissions(
-            @NonNull PackageParser.Package pkg,
-            @PackageManager.PermissionWhitelistFlags int whitelistFlags, int userId);
+            @NonNull String[] grantedPermissions, int callingUid);
     public abstract void setWhitelistedRestrictedPermissions(
             @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
             @NonNull List<String> permissions, int callingUid,
-            @PackageManager.PermissionWhitelistFlags int whitelistFlags,
-            @Nullable PermissionCallback callback);
-    public abstract void revokeRuntimePermission(@NonNull String permName,
-            @NonNull String packageName, boolean overridePolicy, int userId,
-            @Nullable PermissionCallback callback);
+            @PackageManager.PermissionWhitelistFlags int whitelistFlags);
+    /** Sets the whitelisted, restricted permissions for the given package. */
+    public abstract void setWhitelistedRestrictedPermissions(
+            @NonNull String packageName, @NonNull List<String> permissions,
+            @PackageManager.PermissionWhitelistFlags int flags, @NonNull int userId);
 
     /**
      * Update permissions when a package changed.
@@ -109,9 +204,7 @@
      * @param callback Callback to call after permission changes
      */
     public abstract void updatePermissions(@NonNull String packageName,
-            @Nullable PackageParser.Package pkg,
-            @NonNull Collection<PackageParser.Package> allPackages,
-            @NonNull PermissionCallback callback);
+            @Nullable PackageParser.Package pkg);
 
     /**
      * Update all permissions for all apps.
@@ -125,9 +218,22 @@
      * @param allPackages All currently known packages
      * @param callback Callback to call after permission changes
      */
-    public abstract void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdate,
-            @NonNull Collection<PackageParser.Package> allPackages,
-            @NonNull PermissionCallback callback);
+    public abstract void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdate);
+
+    /**
+     * Resets any user permission state changes (eg. permissions and flags) of all
+     * packages installed for the given user.
+     *
+     * @see #resetRuntimePermissions(android.content.pm.PackageParser.Package, int)
+     */
+    public abstract void resetAllRuntimePermissions(@UserIdInt int userId);
+
+    /**
+     * Resets any user permission state changes (eg. permissions and flags) of the
+     * specified package for the given user.
+     */
+    public abstract void resetRuntimePermissions(@NonNull PackageParser.Package pkg,
+            @UserIdInt int userId);
 
     /**
      * We might auto-grant permissions if any permission of the group is already granted. Hence if
@@ -137,13 +243,11 @@
      * @param newPackage The new package that was installed
      * @param oldPackage The old package that was updated
      * @param allPackageNames All packages
-     * @param permissionCallback Callback for permission changed
      */
     public abstract void revokeRuntimePermissionsIfGroupChanged(
             @NonNull PackageParser.Package newPackage,
             @NonNull PackageParser.Package oldPackage,
-            @NonNull ArrayList<String> allPackageNames,
-            @NonNull PermissionCallback permissionCallback);
+            @NonNull ArrayList<String> allPackageNames);
 
     /**
      * Add all permissions in the given package.
@@ -159,29 +263,6 @@
     public abstract @Nullable String[] getAppOpPermissionPackages(
             @NonNull String permName, int callingUid);
 
-    public abstract int getPermissionFlags(@NonNull String permName,
-            @NonNull String packageName, int callingUid, int userId);
-
-    /**
-     * Updates the flags associated with a permission by replacing the flags in
-     * the specified mask with the provided flag values.
-     */
-    public abstract void updatePermissionFlags(@NonNull String permName,
-            @NonNull String packageName, int flagMask, int flagValues, int callingUid, int userId,
-            boolean overridePolicy, @Nullable PermissionCallback callback);
-    /**
-     * Updates the flags for all applications by replacing the flags in the specified mask
-     * with the provided flag values.
-     */
-    public abstract boolean updatePermissionFlagsForAllApps(int flagMask, int flagValues,
-            int callingUid, int userId, @NonNull Collection<PackageParser.Package> packages,
-            @Nullable PermissionCallback callback);
-
-    public abstract int checkPermission(@NonNull String permName, @NonNull String packageName,
-            int callingUid, int userId);
-    public abstract int checkUidPermission(@NonNull String permName,
-            @Nullable PackageParser.Package pkg, int uid, int callingUid);
-
     /**
      * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
      * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userid} is not for the caller.
@@ -201,7 +282,10 @@
     public abstract void enforceGrantRevokeRuntimePermissionPermissions(@NonNull String message);
 
     public abstract @NonNull PermissionSettings getPermissionSettings();
-    public abstract @NonNull DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy();
+
+    /** Grants default browser permissions to the given package */
+    public abstract void grantDefaultPermissionsToDefaultBrowser(
+            @NonNull String packageName, @UserIdInt int userId);
 
     /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
     public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
@@ -209,4 +293,156 @@
     /** Get all permission that have a certain protection level */
     public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtectionLevel(
             @PermissionInfo.Protection int protectionLevel);
+
+    /**
+     * Returns the delegate used to influence permission checking.
+     *
+     * @return The delegate instance.
+     */
+    public abstract @Nullable CheckPermissionDelegate getCheckPermissionDelegate();
+
+    /**
+     * Sets the delegate used to influence permission checking.
+     *
+     * @param delegate A delegate instance or {@code null} to clear.
+     */
+    public abstract void setCheckPermissionDelegate(@Nullable CheckPermissionDelegate delegate);
+
+    /**
+     * Sets the dialer application packages provider.
+     * @param provider The provider.
+     */
+    public abstract void setDialerAppPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Set the location extra packages provider.
+     * @param provider The packages provider.
+     */
+    public abstract  void setLocationExtraPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the location provider packages provider.
+     * @param provider The packages provider.
+     */
+    public abstract void setLocationPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the SIM call manager packages provider.
+     * @param provider The provider.
+     */
+    public abstract void setSimCallManagerPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the SMS application packages provider.
+     * @param provider The provider.
+     */
+    public abstract void setSmsAppPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the sync adapter packages provider.
+     * @param provider The provider.
+     */
+    public abstract void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider);
+
+    /**
+     * Sets the Use Open Wifi packages provider.
+     * @param provider The packages provider.
+     */
+    public abstract void setUseOpenWifiAppPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the voice interaction packages provider.
+     * @param provider The packages provider.
+     */
+    public abstract void setVoiceInteractionPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the default browser provider.
+     *
+     * @param provider the provider
+     */
+    public abstract void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider);
+
+    /**
+     * Sets the package name of the default browser provider for the given user.
+     *
+     * @param packageName The package name of the default browser or {@code null}
+     *          to clear the default browser
+     * @param async If {@code true}, set the default browser asynchronously,
+     *          otherwise set it synchronously
+     * @param doGrant If {@code true} and if {@code packageName} is not {@code null},
+     *          perform default permission grants on the browser, otherwise skip the
+     *          default permission grants.
+     * @param userId The user to set the default browser for.
+     */
+    public abstract void setDefaultBrowser(@Nullable String packageName, boolean async,
+            boolean doGrant, @UserIdInt int userId);
+
+    /**
+     * Sets the default dialer provider.
+     *
+     * @param provider the provider
+     */
+    public abstract void setDefaultDialerProvider(@NonNull DefaultDialerProvider provider);
+
+    /**
+     * Sets the default home provider.
+     *
+     * @param provider the provider
+     */
+    public abstract void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider);
+
+    /**
+     * Asynchronously sets the package name of the default home provider for the given user.
+     *
+     * @param packageName The package name of the default home or {@code null}
+     *          to clear the default browser
+     * @param userId The user to set the default browser for
+     * @param callback Invoked after the default home has been set
+     */
+    public abstract void setDefaultHome(@Nullable String packageName, @UserIdInt int userId,
+            @NonNull Consumer<Boolean> callback);
+
+    /**
+     * Returns the default browser package name for the given user.
+     */
+    @Nullable
+    public abstract String getDefaultBrowser(@UserIdInt int userId);
+
+    /**
+     * Returns the default dialer package name for the given user.
+     */
+    @Nullable
+    public abstract String getDefaultDialer(@UserIdInt int userId);
+
+    /**
+     * Returns the default home package name for the given user.
+     */
+    @Nullable
+    public abstract String getDefaultHome(@UserIdInt int userId);
+
+    /**
+     * Requests granting of the default permissions to the current default Use Open Wifi app.
+     * @param packageName The default use open wifi package name.
+     * @param userId The user for which to grant the permissions.
+     */
+    public abstract void grantDefaultPermissionsToDefaultSimCallManager(
+            @NonNull String packageName, @UserIdInt int userId);
+
+    /**
+     * Requests granting of the default permissions to the current default Use Open Wifi app.
+     * @param packageName The default use open wifi package name.
+     * @param userId The user for which to grant the permissions.
+     */
+    public abstract void grantDefaultPermissionsToDefaultUseOpenWifiApp(
+            @NonNull String packageName, @UserIdInt int userId);
+
+    /**
+     * Returns whether or not default permission grants have been performed for the given
+     * user since the device booted.
+     */
+    public abstract boolean wereDefaultPermissionsGrantedSinceBoot(@UserIdInt int userId);
+
+    /** Called when a new user has been created. */
+    public abstract void onNewUserCreated(@UserIdInt int userId);
 }
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 3f9eb2d..af94e44 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -53,6 +53,14 @@
                     "include-filter": "android.appsecurity.cts.AppSecurityTests#testPermissionDiffCert"
                 }
             ]
+        },
+        {
+            "name": "CtsPermissionTestCases",
+            "options": [
+                {
+                    "include-filter": "android.permission.cts.PermissionUpdateListenerTest"
+                }
+            ]
         }
     ]
 }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 037293f..8da7f7b 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -260,9 +260,11 @@
     private void grantOrUpgradeDefaultRuntimePermissionsIfNeeded(@UserIdInt int userId) {
         if (DEBUG) Slog.i(LOG_TAG, "grantOrUpgradeDefaultPermsIfNeeded(" + userId + ")");
 
-        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
-        if (packageManagerInternal.wereDefaultPermissionsGrantedSinceBoot(userId)) {
+        final PackageManagerInternal packageManagerInternal =
+                LocalServices.getService(PackageManagerInternal.class);
+        final PermissionManagerServiceInternal permissionManagerInternal =
+                LocalServices.getService(PermissionManagerServiceInternal.class);
+        if (permissionManagerInternal.wereDefaultPermissionsGrantedSinceBoot(userId)) {
             if (DEBUG) Slog.i(LOG_TAG, "defaultPermsWereGrantedSinceBoot(" + userId + ")");
 
             // Now call into the permission controller to apply policy around permissions
@@ -798,7 +800,7 @@
         @Override
         public boolean checkStartActivity(@NonNull Intent intent, int callingUid,
                 @Nullable String callingPackage) {
-            if (callingPackage != null && isActionRemovedForCallingPackage(intent.getAction(),
+            if (callingPackage != null && isActionRemovedForCallingPackage(intent, callingUid,
                     callingPackage)) {
                 Slog.w(LOG_TAG, "Action Removed: starting " + intent.toString() + " from "
                         + callingPackage + " (uid=" + callingUid + ")");
@@ -811,8 +813,9 @@
          * 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.
          */
-        private boolean isActionRemovedForCallingPackage(@Nullable String action,
+        private boolean isActionRemovedForCallingPackage(@NonNull Intent intent, int callingUid,
                 @NonNull String callingPackage) {
+            String action = intent.getAction();
             if (action == null) {
                 return false;
             }
@@ -821,15 +824,19 @@
                 case Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT: {
                     ApplicationInfo applicationInfo;
                     try {
-                        applicationInfo = getContext().getPackageManager().getApplicationInfo(
-                                callingPackage, 0);
+                        applicationInfo = getContext().getPackageManager().getApplicationInfoAsUser(
+                                callingPackage, 0, UserHandle.getUserId(callingUid));
+                        if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
+                            // Applications targeting Q or higher should use
+                            // RoleManager.createRequestRoleIntent() instead.
+                            return true;
+                        }
                     } catch (PackageManager.NameNotFoundException e) {
                         Slog.i(LOG_TAG, "Cannot find application info for " + callingPackage);
-                        return false;
                     }
-                    // Applications targeting Q should use RoleManager.createRequestRoleIntent()
-                    // instead.
-                    return applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q;
+                    // Make sure RequestRoleActivity can know the calling package if we allow it.
+                    intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage);
+                    return false;
                 }
                 default:
                     return false;
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index d53f685..c1a6dbd 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -28,11 +28,14 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
 
+import static java.lang.Integer.min;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.UserHandle;
 
@@ -73,6 +76,41 @@
             };
 
     /**
+     * TargetSDK is per package. To make sure two apps int the same shared UID do not fight over
+     * what to set, always compute the combined targetSDK.
+     *
+     * @param context A context
+     * @param appInfo The app that is changed
+     * @param user The user the app belongs to
+     *
+     * @return The minimum targetSDK of all apps sharing the uid of the app
+     */
+    private static int getMinimumTargetSDK(@NonNull Context context,
+            @NonNull ApplicationInfo appInfo, @NonNull UserHandle user) {
+        PackageManager pm = context.getPackageManager();
+
+        int minimumTargetSDK = appInfo.targetSdkVersion;
+
+        String[] uidPkgs = pm.getPackagesForUid(appInfo.uid);
+        if (uidPkgs != null) {
+            for (String uidPkg : uidPkgs) {
+                if (!uidPkg.equals(appInfo.packageName)) {
+                    ApplicationInfo uidPkgInfo;
+                    try {
+                        uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        continue;
+                    }
+
+                    minimumTargetSDK = min(minimumTargetSDK, uidPkgInfo.targetSdkVersion);
+                }
+            }
+        }
+
+        return minimumTargetSDK;
+    }
+
+    /**
      * Get the policy for a soft restricted permission.
      *
      * @param context A context to use
@@ -99,12 +137,36 @@
                 final int targetSDK;
 
                 if (appInfo != null) {
-                    flags = context.getPackageManager().getPermissionFlags(permission,
-                            appInfo.packageName, user);
+                    PackageManager pm = context.getPackageManager();
+                    flags = pm.getPermissionFlags(permission, appInfo.packageName, user);
                     applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
                     isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
-                    hasRequestedLegacyExternalStorage = appInfo.hasRequestedLegacyExternalStorage();
-                    targetSDK = appInfo.targetSdkVersion;
+                    targetSDK = getMinimumTargetSDK(context, appInfo, user);
+
+                    boolean hasAnyRequestedLegacyExternalStorage =
+                            appInfo.hasRequestedLegacyExternalStorage();
+
+                    // hasRequestedLegacyExternalStorage is per package. To make sure two apps in
+                    // the same shared UID do not fight over what to set, always compute the
+                    // combined hasRequestedLegacyExternalStorage
+                    String[] uidPkgs = pm.getPackagesForUid(appInfo.uid);
+                    if (uidPkgs != null) {
+                        for (String uidPkg : uidPkgs) {
+                            if (!uidPkg.equals(appInfo.packageName)) {
+                                ApplicationInfo uidPkgInfo;
+                                try {
+                                    uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user);
+                                } catch (PackageManager.NameNotFoundException e) {
+                                    continue;
+                                }
+
+                                hasAnyRequestedLegacyExternalStorage |=
+                                        uidPkgInfo.hasRequestedLegacyExternalStorage();
+                            }
+                        }
+                    }
+
+                    hasRequestedLegacyExternalStorage = hasAnyRequestedLegacyExternalStorage;
                 } else {
                     flags = 0;
                     applyRestriction = false;
@@ -155,7 +217,7 @@
                     final int flags = context.getPackageManager().getPermissionFlags(permission,
                             appInfo.packageName, user);
                     isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
-                    targetSDK = appInfo.targetSdkVersion;
+                    targetSDK = getMinimumTargetSDK(context, appInfo, user);
                 } else {
                     isWhiteListed = false;
                     targetSDK = 0;
diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING
index 9f64039..484017b 100644
--- a/services/core/java/com/android/server/policy/TEST_MAPPING
+++ b/services/core/java/com/android/server/policy/TEST_MAPPING
@@ -33,6 +33,9 @@
       "options": [
         {
           "include-filter": "android.permission2.cts.RestrictedPermissionsTest"
+        },
+        {
+          "include-filter": "android.permission2.cts.RestrictedStoragePermissionSharedUidTest"
         }
       ]
     },
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index c6a1867..1948b20 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.role;
 
 import android.Manifest;
+import android.annotation.AnyThread;
 import android.annotation.CheckResult;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
@@ -49,7 +50,6 @@
 import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
-import android.provider.Telephony;
 import android.service.sms.FinancialSmsService;
 import android.telephony.IFinancialSmsCallback;
 import android.text.TextUtils;
@@ -61,6 +61,8 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.ThrottledRunnable;
 import com.android.internal.telephony.SmsApplication;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.BitUtils;
@@ -74,6 +76,7 @@
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
@@ -82,7 +85,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -99,6 +101,8 @@
 
     private static final boolean DEBUG = false;
 
+    private static final long GRANT_DEFAULT_ROLES_INTERVAL_MILLIS = 1000;
+
     @NonNull
     private final UserManagerInternal mUserManagerInternal;
     @NonNull
@@ -142,6 +146,14 @@
     @NonNull
     private final Handler mListenerHandler = FgThread.getHandler();
 
+    /**
+     * Maps user id to its throttled runnable for granting default roles.
+     */
+    @GuardedBy("mLock")
+    @NonNull
+    private final SparseArray<ThrottledRunnable> mGrantDefaultRolesThrottledRunnables =
+            new SparseArray<>();
+
     public RoleManagerService(@NonNull Context context,
             @NonNull RoleHoldersResolver legacyRoleResolver) {
         super(context);
@@ -155,11 +167,11 @@
 
         LocalServices.addService(RoleManagerInternal.class, new Internal());
 
-        PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
-        packageManagerInternal.setDefaultBrowserProvider(new DefaultBrowserProvider());
-        packageManagerInternal.setDefaultDialerProvider(new DefaultDialerProvider());
-        packageManagerInternal.setDefaultHomeProvider(new DefaultHomeProvider());
+        PermissionManagerServiceInternal permissionManagerInternal =
+                LocalServices.getService(PermissionManagerServiceInternal.class);
+        permissionManagerInternal.setDefaultBrowserProvider(new DefaultBrowserProvider());
+        permissionManagerInternal.setDefaultDialerProvider(new DefaultDialerProvider());
+        permissionManagerInternal.setDefaultHomeProvider(new DefaultHomeProvider());
 
         registerUserRemovedReceiver();
     }
@@ -182,8 +194,6 @@
     public void onStart() {
         publishBinderService(Context.ROLE_SERVICE, new Stub());
 
-        //TODO add watch for new user creation and run default grants for them
-
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
@@ -203,64 +213,78 @@
                     // Package is being upgraded - we're about to get ACTION_PACKAGE_ADDED
                     return;
                 }
-                performInitialGrantsIfNecessaryAsync(userId);
+                maybeGrantDefaultRolesAsync(userId);
             }
         }, UserHandle.ALL, intentFilter, null, null);
     }
 
     @Override
     public void onStartUser(@UserIdInt int userId) {
-        performInitialGrantsIfNecessary(userId);
-    }
-
-    private CompletableFuture<Void> performInitialGrantsIfNecessaryAsync(@UserIdInt int userId) {
-        RoleUserState userState;
-        userState = getOrCreateUserState(userId);
-
-        String packagesHash = computeComponentStateHash(userId);
-        String oldPackagesHash = userState.getPackagesHash();
-        boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash);
-        if (needGrant) {
-
-            //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
-            migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
-            migrateRoleIfNecessary(RoleManager.ROLE_ASSISTANT, userId);
-            migrateRoleIfNecessary(RoleManager.ROLE_DIALER, userId);
-            migrateRoleIfNecessary(RoleManager.ROLE_EMERGENCY, userId);
-
-            // Some vital packages state has changed since last role grant
-            // Run grants again
-            Slog.i(LOG_TAG, "Granting default permissions...");
-            CompletableFuture<Void> result = new CompletableFuture<>();
-            getOrCreateController(userId).grantDefaultRoles(FgThread.getExecutor(),
-                    successful -> {
-                        if (successful) {
-                            userState.setPackagesHash(packagesHash);
-                            result.complete(null);
-                        } else {
-                            result.completeExceptionally(new RuntimeException());
-                        }
-                    });
-            return result;
-        } else if (DEBUG) {
-            Slog.i(LOG_TAG, "Already ran grants for package state " + packagesHash);
-        }
-        return CompletableFuture.completedFuture(null);
+        maybeGrantDefaultRolesSync(userId);
     }
 
     @MainThread
-    private void performInitialGrantsIfNecessary(@UserIdInt int userId) {
-        CompletableFuture<Void> result = performInitialGrantsIfNecessaryAsync(userId);
+    private void maybeGrantDefaultRolesSync(@UserIdInt int userId) {
+        AndroidFuture<Void> future = maybeGrantDefaultRolesInternal(userId);
         try {
-            result.get(30, TimeUnit.SECONDS);
+            future.get(30, TimeUnit.SECONDS);
         } catch (InterruptedException | ExecutionException | TimeoutException e) {
-            Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e);
+            Slog.e(LOG_TAG, "Failed to grant default roles for user " + userId, e);
         }
     }
 
-    private void migrateRoleIfNecessary(String role, @UserIdInt int userId) {
+    private void maybeGrantDefaultRolesAsync(@UserIdInt int userId) {
+        ThrottledRunnable runnable;
+        synchronized (mLock) {
+            runnable = mGrantDefaultRolesThrottledRunnables.get(userId);
+            if (runnable == null) {
+                runnable = new ThrottledRunnable(FgThread.getHandler(),
+                        GRANT_DEFAULT_ROLES_INTERVAL_MILLIS,
+                        () -> maybeGrantDefaultRolesInternal(userId));
+                mGrantDefaultRolesThrottledRunnables.put(userId, runnable);
+            }
+        }
+        runnable.run();
+    }
+
+    @AnyThread
+    @NonNull
+    private AndroidFuture<Void> maybeGrantDefaultRolesInternal(@UserIdInt int userId) {
+        RoleUserState userState = getOrCreateUserState(userId);
+        String oldPackagesHash = userState.getPackagesHash();
+        String newPackagesHash = computeComponentStateHash(userId);
+        if (Objects.equals(oldPackagesHash, newPackagesHash)) {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "Already granted default roles for packages hash "
+                        + newPackagesHash);
+            }
+            return AndroidFuture.completedFuture(null);
+        }
+
+        //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_DIALER, userId);
+        maybeMigrateRole(RoleManager.ROLE_EMERGENCY, userId);
+
+        // Some package state has changed, so grant default roles again.
+        Slog.i(LOG_TAG, "Granting default roles...");
+        AndroidFuture<Void> future = new AndroidFuture<>();
+        getOrCreateController(userId).grantDefaultRoles(FgThread.getExecutor(),
+                successful -> {
+                    if (successful) {
+                        userState.setPackagesHash(newPackagesHash);
+                        future.complete(null);
+                    } else {
+                        future.completeExceptionally(new RuntimeException());
+                    }
+                });
+        return future;
+    }
+
+    private void maybeMigrateRole(String role, @UserIdInt int userId) {
         // Any role for which we have a record are already migrated
         RoleUserState userState = getOrCreateUserState(userId);
         if (!userState.isRoleAvailable(role)) {
@@ -366,6 +390,7 @@
         RemoteCallbackList<IOnRoleHoldersChangedListener> listeners;
         RoleUserState userState;
         synchronized (mLock) {
+            mGrantDefaultRolesThrottledRunnables.remove(userId);
             listeners = mListeners.removeReturnOld(userId);
             mControllers.remove(userId);
             userState = mUserStates.removeReturnOld(userId);
@@ -731,7 +756,8 @@
         }
     }
 
-    private class DefaultBrowserProvider implements PackageManagerInternal.DefaultBrowserProvider {
+    private class DefaultBrowserProvider implements
+            PermissionManagerServiceInternal.DefaultBrowserProvider {
 
         @Nullable
         @Override
@@ -742,7 +768,7 @@
 
         @Override
         public boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) {
-            CompletableFuture<Void> future = new CompletableFuture<>();
+            AndroidFuture<Void> future = new AndroidFuture<>();
             RemoteCallback callback = new RemoteCallback(result -> {
                 boolean successful = result != null;
                 if (successful) {
@@ -785,7 +811,8 @@
         }
     }
 
-    private class DefaultDialerProvider implements PackageManagerInternal.DefaultDialerProvider {
+    private class DefaultDialerProvider implements
+            PermissionManagerServiceInternal.DefaultDialerProvider {
 
         @Nullable
         @Override
@@ -795,7 +822,8 @@
         }
     }
 
-    private class DefaultHomeProvider implements PackageManagerInternal.DefaultHomeProvider {
+    private class DefaultHomeProvider implements
+            PermissionManagerServiceInternal.DefaultHomeProvider {
 
         @Nullable
         @Override
diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java
index e139ab8..4970862 100644
--- a/services/core/java/com/android/server/slice/PinnedSliceState.java
+++ b/services/core/java/com/android/server/slice/PinnedSliceState.java
@@ -188,7 +188,7 @@
             b.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
             try {
                 client.call(SliceProvider.METHOD_PIN, null, b);
-            } catch (RemoteException e) {
+            } catch (Exception e) {
                 Log.w(TAG, "Unable to contact " + mUri, e);
             }
         }
@@ -201,7 +201,7 @@
             b.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
             try {
                 client.call(SliceProvider.METHOD_UNPIN, null, b);
-            } catch (RemoteException e) {
+            } catch (Exception e) {
                 Log.w(TAG, "Unable to contact " + mUri, e);
             }
         }
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 54369ca..a853529 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -39,7 +39,6 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.UserManagerService;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 /**
@@ -66,9 +65,9 @@
                 ServiceManager.addService(Context.TELECOM_SERVICE, service);
 
                 synchronized (mLock) {
+                    final PermissionManagerServiceInternal permissionManager =
+                            LocalServices.getService(PermissionManagerServiceInternal.class);
                     if (mDefaultSimCallManagerRequests != null) {
-                        final DefaultPermissionGrantPolicy permissionPolicy =
-                                getDefaultPermissionGrantPolicy();
                         if (mDefaultSimCallManagerRequests != null) {
                             TelecomManager telecomManager =
                                 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
@@ -80,7 +79,7 @@
                                 for (int i = requestCount - 1; i >= 0; i--) {
                                     final int userId = mDefaultSimCallManagerRequests.get(i);
                                     mDefaultSimCallManagerRequests.remove(i);
-                                    permissionPolicy
+                                    permissionManager
                                             .grantDefaultPermissionsToDefaultSimCallManager(
                                                     packageName, userId);
                                 }
@@ -99,11 +98,6 @@
         }
     }
 
-    private DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() {
-        return LocalServices.getService(PermissionManagerServiceInternal.class)
-                .getDefaultPermissionGrantPolicy();
-    }
-
     private static final ComponentName SERVICE_COMPONENT = new ComponentName(
             "com.android.server.telecom",
             "com.android.server.telecom.components.TelecomService");
@@ -162,10 +156,11 @@
 
 
     private void registerDefaultAppProviders() {
-        final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy();
+        final PermissionManagerServiceInternal permissionManager =
+                LocalServices.getService(PermissionManagerServiceInternal.class);
 
         // Set a callback for the permission grant policy to query the default sms app.
-        permissionPolicy.setSmsAppPackagesProvider(userId -> {
+        permissionManager.setSmsAppPackagesProvider(userId -> {
             synchronized (mLock) {
                 if (mServiceConnection == null) {
                     return null;
@@ -180,7 +175,7 @@
         });
 
         // Set a callback for the permission grant policy to query the default dialer app.
-        permissionPolicy.setDialerAppPackagesProvider(userId -> {
+        permissionManager.setDialerAppPackagesProvider(userId -> {
             synchronized (mLock) {
                 if (mServiceConnection == null) {
                     return null;
@@ -194,7 +189,7 @@
         });
 
         // Set a callback for the permission grant policy to query the default sim call manager.
-        permissionPolicy.setSimCallManagerPackagesProvider(userId -> {
+        permissionManager.setSimCallManagerPackagesProvider(userId -> {
             synchronized (mLock) {
                 if (mServiceConnection == null) {
                     if (mDefaultSimCallManagerRequests == null) {
@@ -215,12 +210,11 @@
     }
 
     private void registerDefaultAppNotifier() {
-        final DefaultPermissionGrantPolicy permissionPolicy = getDefaultPermissionGrantPolicy();
         // Notify the package manager on default app changes
         final RoleManager roleManager = mContext.getSystemService(RoleManager.class);
         roleManager.addOnRoleHoldersChangedListenerAsUser(mContext.getMainExecutor(),
-                (roleName, user) -> updateSimCallManagerPermissions(permissionPolicy,
-                        user.getIdentifier()), UserHandle.ALL);
+                (roleName, user) -> updateSimCallManagerPermissions(user.getIdentifier()),
+                UserHandle.ALL);
     }
 
 
@@ -230,7 +224,7 @@
             public void onReceive(Context context, Intent intent) {
                 if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
                     for (int userId : UserManagerService.getInstance().getUserIds()) {
-                        updateSimCallManagerPermissions(getDefaultPermissionGrantPolicy(), userId);
+                        updateSimCallManagerPermissions(userId);
                     }
                 }
             }
@@ -240,16 +234,16 @@
             new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), null, null);
     }
 
-    private void updateSimCallManagerPermissions(
-            DefaultPermissionGrantPolicy permissionGrantPolicy, int userId) {
+    private void updateSimCallManagerPermissions(int userId) {
+        final PermissionManagerServiceInternal permissionManager =
+                LocalServices.getService(PermissionManagerServiceInternal.class);
         TelecomManager telecomManager =
             (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
         PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
         if (phoneAccount != null) {
             Slog.i(TAG, "updating sim call manager permissions for userId:" + userId);
             String packageName = phoneAccount.getComponentName().getPackageName();
-            permissionGrantPolicy.grantDefaultPermissionsToDefaultSimCallManager(
-                packageName, userId);
+            permissionManager.grantDefaultPermissionsToDefaultSimCallManager(packageName, userId);
         }
     }
 }
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 55f062b..04839e1 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -110,6 +110,7 @@
     private static final String TAG = "UriGrantsManagerService";
     // Maximum number of persisted Uri grants a package is allowed
     private static final int MAX_PERSISTED_URI_GRANTS = 128;
+    private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false;
 
     private final Object mLock = new Object();
     private final Context mContext;
@@ -949,7 +950,25 @@
             return false;
         }
 
-        return readMet && writeMet;
+        // If this provider says that grants are always required, we need to
+        // consult it directly to determine if the UID has permission
+        final boolean forceMet;
+        if (ENABLE_DYNAMIC_PERMISSIONS && pi.forceUriPermissions) {
+            final int providerUserId = UserHandle.getUserId(pi.applicationInfo.uid);
+            final int clientUserId = UserHandle.getUserId(uid);
+            if (providerUserId == clientUserId) {
+                forceMet = (mAmInternal.checkContentProviderUriPermission(grantUri.uri,
+                        providerUserId, uid, modeFlags) == PackageManager.PERMISSION_GRANTED);
+            } else {
+                // The provider can't track cross-user permissions, so we have
+                // to assume they're always denied
+                forceMet = false;
+            }
+        } else {
+            forceMet = true;
+        }
+
+        return readMet && writeMet && forceMet;
     }
 
     private void removeUriPermissionIfNeeded(UriPermission perm) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index bace7e3..26ca975 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -22,6 +22,7 @@
 
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.utils.RegionUtils.forEachRect;
 
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
@@ -84,7 +85,8 @@
 
     private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
 
-    private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
+    private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
+            new SparseArray<>();
 
     public boolean setMagnificationCallbacksLocked(int displayId,
             MagnificationCallbacks callbacks) {
@@ -114,27 +116,52 @@
         return result;
     }
 
-    public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
+    public boolean setWindowsForAccessibilityCallbackLocked(int displayId,
+            WindowsForAccessibilityCallback callback) {
         if (callback != null) {
-            if (mWindowsForAccessibilityObserver != null) {
-                throw new IllegalStateException(
-                        "Windows for accessibility callback already set!");
+            final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+            if (dc == null) {
+                return false;
             }
-            mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
-                    mService, callback);
+
+            final Display display = dc.getDisplay();
+            if (mWindowsForAccessibilityObserver.get(displayId) != null) {
+                if (display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null) {
+                    // The window observer of this embedded display had been set from
+                    // window manager after setting its parent window
+                    return true;
+                } else {
+                    throw new IllegalStateException(
+                            "Windows for accessibility callback of display "
+                                    + displayId + " already set!");
+                }
+            }
+            if (display.getType() == Display.TYPE_OVERLAY) {
+                return false;
+            }
+            mWindowsForAccessibilityObserver.put(displayId,
+                    new WindowsForAccessibilityObserver(mService, displayId, callback));
         } else {
-            if (mWindowsForAccessibilityObserver == null) {
+            final WindowsForAccessibilityObserver windowsForA11yObserver =
+                    mWindowsForAccessibilityObserver.get(displayId);
+            if  (windowsForA11yObserver == null) {
                 throw new IllegalStateException(
-                        "Windows for accessibility callback already cleared!");
+                        "Windows for accessibility callback of display " + displayId
+                                + " already cleared!");
             }
-            mWindowsForAccessibilityObserver = null;
+            mWindowsForAccessibilityObserver.remove(displayId);
         }
+        return true;
     }
 
-    public void performComputeChangedWindowsNotLocked(boolean forceSend) {
+    public void performComputeChangedWindowsNotLocked(int displayId, boolean forceSend) {
         WindowsForAccessibilityObserver observer = null;
         synchronized (mService) {
-            observer = mWindowsForAccessibilityObserver;
+            final WindowsForAccessibilityObserver windowsForA11yObserver =
+                    mWindowsForAccessibilityObserver.get(displayId);
+            if (windowsForA11yObserver != null) {
+                observer = windowsForA11yObserver;
+            }
         }
         if (observer != null) {
             observer.performComputeChangedWindowsNotLocked(forceSend);
@@ -146,9 +173,10 @@
         if (displayMagnifier != null) {
             displayMagnifier.setMagnificationSpecLocked(spec);
         }
-        // TODO: support multi-display for windows observer
-        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -172,9 +200,10 @@
         if (displayMagnifier != null) {
             displayMagnifier.onWindowLayersChangedLocked();
         }
-        // TODO: support multi-display for windows observer
-        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -184,9 +213,10 @@
         if (displayMagnifier != null) {
             displayMagnifier.onRotationChangedLocked(displayContent);
         }
-        // TODO: support multi-display for windows observer
-        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -205,29 +235,36 @@
         if (displayMagnifier != null) {
             displayMagnifier.onWindowTransitionLocked(windowState, transition);
         }
-        // TODO: support multi-display for windows observer
-        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
-    public void onWindowFocusChangedNotLocked() {
+    public void onWindowFocusChangedNotLocked(int displayId) {
         // Not relevant for the display magnifier.
 
         WindowsForAccessibilityObserver observer = null;
         synchronized (mService) {
-            observer = mWindowsForAccessibilityObserver;
+            final WindowsForAccessibilityObserver windowsForA11yObserver =
+                    mWindowsForAccessibilityObserver.get(displayId);
+            if (windowsForA11yObserver != null) {
+                observer = windowsForA11yObserver;
+            }
         }
         if (observer != null) {
             observer.performComputeChangedWindowsNotLocked(false);
         }
     }
 
-    public void onSomeWindowResizedOrMovedLocked() {
+    public void onSomeWindowResizedOrMovedLocked(int displayId) {
         // Not relevant for the display magnifier.
 
-        if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -263,6 +300,29 @@
         }
     }
 
+    public void handleWindowObserverOfEmbeddedDisplayLocked(int embeddedDisplayId,
+            WindowState parentWindow) {
+        if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) {
+            return;
+        }
+        // Finds the parent display of this embedded display
+        final int parentDisplayId;
+        WindowState candidate = parentWindow;
+        while (candidate != null) {
+            parentWindow = candidate;
+            candidate = parentWindow.getDisplayContent().getParentWindow();
+        }
+        parentDisplayId = parentWindow.getDisplayId();
+        // Uses the observer of parent display
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(parentDisplayId);
+
+        if (windowsForA11yObserver != null) {
+            // Replaces the observer of embedded display to the one of parent display
+            mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
+        }
+    }
+
     private static void populateTransformationMatrixLocked(WindowState windowState,
             Matrix outMatrix) {
         windowState.getTransformationMatrix(sTempFloats, outMatrix);
@@ -1058,13 +1118,17 @@
 
         private final WindowsForAccessibilityCallback mCallback;
 
+        private final int mDisplayId;
+
         private final long mRecurringAccessibilityEventsIntervalMillis;
 
         public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
+                int displayId,
                 WindowsForAccessibilityCallback callback) {
             mContext = windowManagerService.mContext;
             mService = windowManagerService;
             mCallback = callback;
+            mDisplayId = displayId;
             mHandler = new MyHandler(mService.mH.getLooper());
             mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
                     .getSendRecurringAccessibilityEventsInterval();
@@ -1099,14 +1163,17 @@
                 // Do not send the windows if there is no current focus as
                 // the window manager is still looking for where to put it.
                 // We will do the work when we get a focus change callback.
-                // TODO(b/112273690): Support multiple displays
+                // TODO [Multi-Display] : only checks top focused window
                 if (!isCurrentFocusWindowOnDefaultDisplay()) {
                     return;
                 }
 
-                WindowManager windowManager = (WindowManager)
-                        mContext.getSystemService(Context.WINDOW_SERVICE);
-                windowManager.getDefaultDisplay().getRealSize(mTempPoint);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+                if (dc == null) {
+                    return;
+                }
+                final Display display = dc.getDisplay();
+                display.getRealSize(mTempPoint);
                 final int screenWidth = mTempPoint.x;
                 final int screenHeight = mTempPoint.y;
 
@@ -1126,14 +1193,13 @@
                 // Iterate until we figure out what is touchable for the entire screen.
                 for (int i = visibleWindowCount - 1; i >= 0; i--) {
                     final WindowState windowState = visibleWindows.valueAt(i);
+                    final Region regionInScreen = new Region();
+                    computeWindowRegionInScreen(windowState, regionInScreen);
 
-                    final Rect boundsInScreen = mTempRect;
-                    computeWindowBoundsInScreen(windowState, boundsInScreen);
-
-                    if (windowMattersToAccessibility(windowState, boundsInScreen, unaccountedSpace,
+                    if (windowMattersToAccessibility(windowState, regionInScreen, unaccountedSpace,
                             skipRemainingWindowsForTasks)) {
-                        addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows);
-                        updateUnaccountedSpace(windowState, boundsInScreen, unaccountedSpace,
+                        addPopulatedWindowInfo(windowState, regionInScreen, windows, addedWindows);
+                        updateUnaccountedSpace(windowState, regionInScreen, unaccountedSpace,
                                 skipRemainingWindowsForTasks);
                         focusedWindowAdded |= windowState.isFocused();
                     }
@@ -1171,8 +1237,9 @@
             clearAndRecycleWindows(windows);
         }
 
-        private boolean windowMattersToAccessibility(WindowState windowState, Rect boundsInScreen,
-                Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
+        private boolean windowMattersToAccessibility(WindowState windowState,
+                Region regionInScreen, Region unaccountedSpace,
+                HashSet<Integer> skipRemainingWindowsForTasks) {
             if (windowState.isFocused()) {
                 return true;
             }
@@ -1192,7 +1259,7 @@
             }
 
             // If the window is completely covered by other windows - ignore.
-            if (unaccountedSpace.quickReject(boundsInScreen)) {
+            if (unaccountedSpace.quickReject(regionInScreen)) {
                 return false;
             }
 
@@ -1204,7 +1271,7 @@
             return false;
         }
 
-        private void updateUnaccountedSpace(WindowState windowState, Rect boundsInScreen,
+        private void updateUnaccountedSpace(WindowState windowState, Region regionInScreen,
                 Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
             if (windowState.mAttrs.type
                     != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
@@ -1212,59 +1279,71 @@
                 // Account for the space this window takes if the window
                 // is not an accessibility overlay which does not change
                 // the reported windows.
-                unaccountedSpace.op(boundsInScreen, unaccountedSpace,
+                unaccountedSpace.op(regionInScreen, unaccountedSpace,
                         Region.Op.REVERSE_DIFFERENCE);
 
                 // If a window is modal it prevents other windows from being touched
                 if ((windowState.mAttrs.flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
-                    // Account for all space in the task, whether the windows in it are
-                    // touchable or not. The modal window blocks all touches from the task's
-                    // area.
-                    unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
-                            Region.Op.REVERSE_DIFFERENCE);
+                    if (!windowState.hasTapExcludeRegion()) {
+                        // Account for all space in the task, whether the windows in it are
+                        // touchable or not. The modal window blocks all touches from the task's
+                        // area.
+                        unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
+                                Region.Op.REVERSE_DIFFERENCE);
+                    } else {
+                        // If a window has tap exclude region, we need to account it.
+                        final Region displayRegion = new Region(windowState.getDisplayFrameLw());
+                        final Region tapExcludeRegion = new Region();
+                        windowState.amendTapExcludeRegion(tapExcludeRegion);
+                        displayRegion.op(tapExcludeRegion, displayRegion,
+                                Region.Op.REVERSE_DIFFERENCE);
+                        unaccountedSpace.op(displayRegion, unaccountedSpace,
+                                Region.Op.REVERSE_DIFFERENCE);
+                    }
 
                     final Task task = windowState.getTask();
                     if (task != null) {
                         // If the window is associated with a particular task, we can skip the
                         // rest of the windows for that task.
                         skipRemainingWindowsForTasks.add(task.mTaskId);
-                    } else {
+                    } else if (!windowState.hasTapExcludeRegion()) {
                         // If the window is not associated with a particular task, then it is
-                        // globally modal. In this case we can skip all remaining windows.
+                        // globally modal. In this case we can skip all remaining windows when
+                        // it doesn't has tap exclude region.
                         unaccountedSpace.setEmpty();
                     }
                 }
             }
         }
 
-        private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
+        private void computeWindowRegionInScreen(WindowState windowState, Region outRegion) {
             // Get the touchable frame.
             Region touchableRegion = mTempRegion1;
             windowState.getTouchableRegion(touchableRegion);
-            Rect touchableFrame = mTempRect;
-            touchableRegion.getBounds(touchableFrame);
-
-            // Move to origin as all transforms are captured by the matrix.
-            RectF windowFrame = mTempRectF;
-            windowFrame.set(touchableFrame);
-            windowFrame.offset(-windowState.getFrameLw().left, -windowState.getFrameLw().top);
 
             // Map the frame to get what appears on the screen.
             Matrix matrix = mTempMatrix;
             populateTransformationMatrixLocked(windowState, matrix);
-            matrix.mapRect(windowFrame);
 
-            // Got the bounds.
-            outBounds.set((int) windowFrame.left, (int) windowFrame.top,
-                    (int) windowFrame.right, (int) windowFrame.bottom);
+            forEachRect(touchableRegion, rect -> {
+                // Move to origin as all transforms are captured by the matrix.
+                RectF windowFrame = mTempRectF;
+                windowFrame.set(rect);
+                windowFrame.offset(-windowState.getFrameLw().left, -windowState.getFrameLw().top);
+
+                matrix.mapRect(windowFrame);
+
+                // Union all rects.
+                outRegion.union(new Rect((int) windowFrame.left, (int) windowFrame.top,
+                        (int) windowFrame.right, (int) windowFrame.bottom));
+            });
         }
 
-        private static void addPopulatedWindowInfo(
-                WindowState windowState, Rect boundsInScreen,
+        private static void addPopulatedWindowInfo(WindowState windowState, Region regionInScreen,
                 List<WindowInfo> out, Set<IBinder> tokenOut) {
             final WindowInfo window = windowState.getWindowInfo();
-            window.boundsInScreen.set(boundsInScreen);
+            window.regionInScreen.set(regionInScreen);
             window.layer = tokenOut.size();
             out.add(window);
             tokenOut.add(window.token);
@@ -1292,8 +1371,12 @@
 
         private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
             final List<WindowState> tempWindowStatesList = new ArrayList<>();
-            final DisplayContent dc = mService.getDefaultDisplayContentLocked();
-            dc.forAllWindows((w) -> {
+            final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+            if (dc == null) {
+                return;
+            }
+
+            dc.forAllWindows(w -> {
                 if (w.isVisibleLw()) {
                     tempWindowStatesList.add(w);
                 }
@@ -1306,17 +1389,10 @@
                     return;
                 }
 
-                // TODO: Use Region instead to get rid of this complicated logic.
-                // Check the tap exclude region of the parent window. If the tap exclude region
-                // is empty, it means there is another can-receive-pointer-event view on top of
-                // the region. Hence, we don't count the window as visible.
-                if (w.isVisibleLw() && parentWindow.getDisplayContent().isDefaultDisplay
-                        && parentWindow.hasTapExcludeRegion()
-                        && tempWindowStatesList.contains(parentWindow)) {
-                    tempWindowStatesList.add(
-                            tempWindowStatesList.lastIndexOf(parentWindow) + 1, w);
+                if (w.isVisibleLw() && tempWindowStatesList.contains(parentWindow)) {
+                    tempWindowStatesList.add(tempWindowStatesList.lastIndexOf(parentWindow), w);
                 }
-            }, true /* traverseTopToBottom */);
+            }, false /* traverseTopToBottom */);
             for (int i = 0; i < tempWindowStatesList.size(); i++) {
                 outWindows.put(i, tempWindowStatesList.get(i));
             }
@@ -1334,7 +1410,7 @@
             }
             return displayParentWindow;
         }
-
+        // TODO [Multi-Display] : only checks top focused window
         private boolean isCurrentFocusWindowOnDefaultDisplay() {
             final WindowState focusedWindow =
                     mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index fe4811d..f1cd721 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -174,6 +174,7 @@
         mDisplayId = display.getDisplayId();
         mDisplay = display;
         mDisplayContent = createDisplayContent();
+        mDisplayContent.reconfigureDisplayLocked();
         updateBounds();
     }
 
@@ -1229,7 +1230,7 @@
                 final ActivityStack stack = mStacks.get(stackNdx);
                 // Always finish non-standard type stacks.
                 if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
-                    stack.finishAllActivitiesLocked(true /* immediately */);
+                    stack.finishAllActivitiesImmediately();
                 } else {
                     // If default display is in split-window mode, set windowing mode of the stack
                     // to split-screen secondary. Otherwise, set the windowing mode to undefined by
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9c87ce8..015464e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -92,6 +92,8 @@
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
 
 import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
 import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
@@ -103,6 +105,7 @@
 import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY;
 import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
 import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
@@ -116,18 +119,29 @@
 import static com.android.server.wm.ActivityStack.PAUSE_TIMEOUT_MSG;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STOP_TIMEOUT_MSG;
+import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONTAINERS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -149,8 +163,10 @@
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityOptions;
 import android.app.PendingIntent;
@@ -194,6 +210,7 @@
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.service.voice.IVoiceInteractionSession;
+import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.MergedConfiguration;
@@ -215,11 +232,14 @@
 import com.android.server.AttributeCache;
 import com.android.server.AttributeCache.Entry;
 import com.android.server.am.AppTimeTracker;
+import com.android.server.am.EventLogTags;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.uri.UriPermissionOwner;
 import com.android.server.wm.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot;
 import com.android.server.wm.ActivityStack.ActivityState;
 
+import com.google.android.collect.Sets;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -240,11 +260,16 @@
 final class ActivityRecord extends ConfigurationContainer {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_ATM;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+    private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
+    private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
+    private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
+    private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
     private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
     private static final String TAG_STATES = TAG + POSTFIX_STATES;
     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
+    private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
     private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
-    private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
 
     private static final String ATTR_ID = "id";
     private static final String TAG_INTENT = "intent";
@@ -317,12 +342,15 @@
     UriPermissionOwner uriPermissions; // current special URI access perms.
     WindowProcessController app;      // if non-null, hosting application
     private ActivityState mState;    // current state we are in
-    Bundle  icicle;         // last saved activity state
-    PersistableBundle persistentState; // last persistently saved activity state
-    // TODO: See if this is still needed.
-    boolean frontOfTask;    // is this the root activity of its task?
+    private Bundle mIcicle;         // last saved activity state
+    private PersistableBundle mPersistentState; // last persistently saved activity state
+    private boolean mHaveState = true; // Indicates whether the last saved state of activity is
+                                       // preserved. This starts out 'true', since the initial state
+                                       // of an activity is that we have everything, and we should
+                                       // never consider it lacking in state to be removed if it
+                                       // dies. After an activity is launched it follows the value
+                                       // of #mIcicle.
     boolean launchFailed;   // set if a launched failed, to abort on 2nd try
-    boolean haveState;      // have we gotten the last activity state?
     boolean stopped;        // is activity pause finished?
     boolean delayedResume;  // not yet resumed because of stopped app switches?
     boolean finishing;      // activity in pending finish list?
@@ -439,7 +467,7 @@
                 pw.print(" userId="); pw.println(mUserId);
         pw.print(prefix); pw.print("app="); pw.println(app);
         pw.print(prefix); pw.println(intent.toInsecureStringWithClip());
-        pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask);
+        pw.print(prefix); pw.print("rootOfTask="); pw.print(isRootOfTask());
                 pw.print(" task="); pw.println(task);
         pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
         pw.print(prefix); pw.print("mActivityComponent=");
@@ -552,8 +580,8 @@
                 if (lastLaunchTime == 0) pw.print("0");
                 else TimeUtils.formatDuration(lastLaunchTime, now, pw);
                 pw.println();
-        pw.print(prefix); pw.print("haveState="); pw.print(haveState);
-                pw.print(" icicle="); pw.println(icicle);
+        pw.print(prefix); pw.print("mHaveState="); pw.print(mHaveState);
+                pw.print(" mIcicle="); pw.println(mIcicle);
         pw.print(prefix); pw.print("state="); pw.print(mState);
                 pw.print(" stopped="); pw.print(stopped);
                 pw.print(" delayedResume="); pw.print(delayedResume);
@@ -614,6 +642,34 @@
         }
     }
 
+    /** Update the saved state of an activity. */
+    void setSavedState(@Nullable Bundle savedState) {
+        mIcicle = savedState;
+        mHaveState = mIcicle != null;
+    }
+
+    /**
+     * Get the actual Bundle instance of the saved state.
+     * @see #hasSavedState() for checking if the record has saved state.
+     */
+    @Nullable Bundle getSavedState() {
+        return mIcicle;
+    }
+
+    /**
+     * Check if the activity has saved state.
+     * @return {@code true} if the client reported a non-empty saved state from last onStop(), or
+     *         if this record was just created and the client is yet to be launched and resumed.
+     */
+    boolean hasSavedState() {
+        return mHaveState;
+    }
+
+    /** @return The actual PersistableBundle instance of the saved persistent state. */
+    @Nullable PersistableBundle getPersistentSavedState() {
+        return mPersistentState;
+    }
+
     void updateApplicationInfo(ApplicationInfo aInfo) {
         info.applicationInfo = aInfo;
     }
@@ -916,8 +972,9 @@
         return ResolverActivity.class.getName().equals(className);
     }
 
-    boolean isResolverActivity() {
-        return isResolverActivity(mActivityComponent.getClassName());
+    boolean isResolverOrDelegateActivity() {
+        return isResolverActivity(mActivityComponent.getClassName()) || Objects.equals(
+                mActivityComponent, mAtmService.mStackSupervisor.getSystemChooserActivity());
     }
 
     boolean isResolverOrChildActivity() {
@@ -956,7 +1013,6 @@
         resultWho = _resultWho;
         requestCode = _reqCode;
         setState(INITIALIZING, "ActivityRecord ctor");
-        frontOfTask = false;
         launchFailed = false;
         stopped = false;
         delayedResume = false;
@@ -971,10 +1027,6 @@
         hasBeenLaunched = false;
         mStackSupervisor = supervisor;
 
-        // This starts out true, since the initial state of an activity is that we have everything,
-        // and we shouldn't never consider it lacking in state to be removed if it dies.
-        haveState = true;
-
         // If the class name in the intent doesn't match that of the target, this is
         // probably an alias. We have to create a new ComponentName object to keep track
         // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly.
@@ -1247,7 +1299,8 @@
                 && intent.getType() == null;
     }
 
-    private boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
+    @VisibleForTesting
+    boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
         if (uid == Process.myUid() || uid == 0) {
             // System process can launch home activity.
             return true;
@@ -1257,8 +1310,8 @@
         if (recentTasks != null && recentTasks.isCallerRecents(uid)) {
             return true;
         }
-        // Resolver activity can launch home activity.
-        return sourceRecord != null && sourceRecord.isResolverActivity();
+        // Resolver or system chooser activity can launch home activity.
+        return sourceRecord != null && sourceRecord.isResolverOrDelegateActivity();
     }
 
     /**
@@ -1277,7 +1330,7 @@
             ActivityOptions options, ActivityRecord sourceRecord) {
         int activityType = ACTIVITY_TYPE_UNDEFINED;
         if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord))
-                && isHomeIntent(intent) && !isResolverActivity()) {
+                && isHomeIntent(intent) && !isResolverOrDelegateActivity()) {
             // This sure looks like a home activity!
             activityType = ACTIVITY_TYPE_HOME;
 
@@ -1523,12 +1576,313 @@
         stack.moveToFront(reason, task);
         // Report top activity change to tracking services and WM
         if (mRootActivityContainer.getTopResumedActivity() == this) {
-            // TODO(b/111361570): Support multiple focused apps in WM
             mAtmService.setResumedActivityUncheckLocked(this, reason);
         }
         return true;
     }
 
+    /** Finish all activities in the task with the same affinity as this one. */
+    void finishActivityAffinity() {
+        final ArrayList<ActivityRecord> activities = getTaskRecord().mActivities;
+        for (int index = activities.indexOf(this); index >= 0; --index) {
+            final ActivityRecord cur = activities.get(index);
+            if (!Objects.equals(cur.taskAffinity, taskAffinity)) {
+                break;
+            }
+            cur.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                    "request-affinity", true /* oomAdj */);
+        }
+    }
+
+    /**
+     * Sets the result for activity that started this one, clears the references to activities
+     * started for result from this one, and clears new intents.
+     */
+    void finishActivityResults(int resultCode, Intent resultData) {
+        // Send the result if needed
+        if (resultTo != null) {
+            if (DEBUG_RESULTS) {
+                Slog.v(TAG_RESULTS, "Adding result to " + resultTo
+                        + " who=" + resultWho + " req=" + requestCode
+                        + " res=" + resultCode + " data=" + resultData);
+            }
+            if (resultTo.mUserId != mUserId) {
+                if (resultData != null) {
+                    resultData.prepareToLeaveUser(mUserId);
+                }
+            }
+            if (info.applicationInfo.uid > 0) {
+                mAtmService.mUgmInternal.grantUriPermissionFromIntent(info.applicationInfo.uid,
+                        resultTo.packageName, resultData,
+                        resultTo.getUriPermissionsLocked(), resultTo.mUserId);
+            }
+            resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData);
+            resultTo = null;
+        } else if (DEBUG_RESULTS) {
+            Slog.v(TAG_RESULTS, "No result destination from " + this);
+        }
+
+        // Make sure this HistoryRecord is not holding on to other resources,
+        // because clients have remote IPC references to this object so we
+        // can't assume that will go away and want to avoid circular IPC refs.
+        results = null;
+        pendingResults = null;
+        newIntents = null;
+        setSavedState(null /* savedState */);
+    }
+
+    /** Activity finish request was not executed. */
+    static final int FINISH_RESULT_CANCELLED = 0;
+    /** Activity finish was requested, activity will be fully removed later. */
+    static final int FINISH_RESULT_REQUESTED = 1;
+    /** Activity finish was requested, activity was removed from history. */
+    static final int FINISH_RESULT_REMOVED = 2;
+
+    /** Definition of possible results for activity finish request. */
+    @IntDef(prefix = { "FINISH_RESULT_" }, value = {
+            FINISH_RESULT_CANCELLED,
+            FINISH_RESULT_REQUESTED,
+            FINISH_RESULT_REMOVED,
+    })
+    @interface FinishRequest {}
+
+    /**
+     * See {@link #finishActivityLocked(int, Intent, String, boolean, boolean)}
+     */
+    @FinishRequest int finishActivityLocked(int resultCode, Intent resultData, String reason,
+            boolean oomAdj) {
+        return finishActivityLocked(resultCode, resultData, reason, oomAdj, !PAUSE_IMMEDIATELY);
+    }
+
+    /**
+     * @return One of {@link FinishRequest} values:
+     * {@link #FINISH_RESULT_REMOVED} if this activity has been removed from the history list.
+     * {@link #FINISH_RESULT_REQUESTED} if removal process was started, but it is still in the list
+     * and will be removed from history later.
+     * {@link #FINISH_RESULT_CANCELLED} if activity is already finishing or in invalid state and the
+     * request to finish it was not ignored.
+     */
+    @FinishRequest int finishActivityLocked(int resultCode, Intent resultData, String reason,
+            boolean oomAdj, boolean pauseImmediately) {
+        if (DEBUG_RESULTS || DEBUG_STATES) {
+            Slog.v(TAG_STATES, "Finishing activity r=" + this + ", result=" + resultCode
+                    + ", data=" + resultData + ", reason=" + reason);
+        }
+
+        if (finishing) {
+            Slog.w(TAG, "Duplicate finish request for r=" + this);
+            return FINISH_RESULT_CANCELLED;
+        }
+
+        if (!isInStackLocked()) {
+            Slog.w(TAG, "Finish request when not in stack for r=" + this);
+            return FINISH_RESULT_CANCELLED;
+        }
+
+        mAtmService.mWindowManager.deferSurfaceLayout();
+        try {
+            makeFinishingLocked();
+            final TaskRecord task = getTaskRecord();
+            EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
+                    mUserId, System.identityHashCode(this),
+                    task.taskId, shortComponentName, reason);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
+            final int index = activities.indexOf(this);
+            if (index < (activities.size() - 1)) {
+                if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
+                    // If the caller asked that this activity (and all above it)
+                    // be cleared when the task is reset, don't lose that information,
+                    // but propagate it up to the next activity.
+                    final ActivityRecord next = activities.get(index + 1);
+                    next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+                }
+            }
+
+            pauseKeyDispatchingLocked();
+
+            final ActivityStack stack = getActivityStack();
+            stack.adjustFocusedActivityStack(this, "finishActivity");
+
+            finishActivityResults(resultCode, resultData);
+
+            final boolean endTask = index <= 0 && !task.isClearingToReuseTask();
+            final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;
+            if (stack.getResumedActivity() == this) {
+                if (DEBUG_VISIBILITY || DEBUG_TRANSITION) {
+                    Slog.v(TAG_TRANSITION, "Prepare close transition: finishing " + this);
+                }
+                if (endTask) {
+                    mAtmService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
+                            task.getTaskInfo());
+                }
+                getDisplay().mDisplayContent.prepareAppTransition(transit, false);
+
+                // When finishing the activity preemptively take the snapshot before the app window
+                // is marked as hidden and any configuration changes take place
+                if (mAtmService.mWindowManager.mTaskSnapshotController != null) {
+                    final ArraySet<Task> tasks = Sets.newArraySet(task.mTask);
+                    mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks);
+                    mAtmService.mWindowManager.mTaskSnapshotController
+                            .addSkipClosingAppSnapshotTasks(tasks);
+                }
+
+                // Tell window manager to prepare for this one to be removed.
+                setVisibility(false);
+
+                if (stack.mPausingActivity == null) {
+                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + this);
+                    if (DEBUG_USER_LEAVING) {
+                        Slog.v(TAG_USER_LEAVING, "finish() => pause with userLeaving=false");
+                    }
+                    stack.startPausingLocked(false, false, null, pauseImmediately);
+                }
+
+                if (endTask) {
+                    mAtmService.getLockTaskController().clearLockedTask(task);
+                }
+            } else if (!isState(PAUSING)) {
+                // If the activity is PAUSING, we will complete the finish once
+                // it is done pausing; else we can just directly finish it here.
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + this);
+                if (visible) {
+                    prepareActivityHideTransitionAnimation(transit);
+                }
+
+                final int finishMode = (visible || nowVisible) ? FINISH_AFTER_VISIBLE
+                        : FINISH_AFTER_PAUSE;
+                final boolean removedActivity = finishCurrentActivityLocked(finishMode, oomAdj,
+                        "finishActivityLocked") == null;
+
+                // The following code is an optimization. When the last non-task overlay activity
+                // is removed from the task, we remove the entire task from the stack. However,
+                // since that is done after the scheduled destroy callback from the activity, that
+                // call to change the visibility of the task overlay activities would be out of
+                // sync with the activity visibility being set for this finishing activity above.
+                // In this case, we can set the visibility of all the task overlay activities when
+                // we detect the last one is finishing to keep them in sync.
+                if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) {
+                    for (ActivityRecord taskOverlay : task.mActivities) {
+                        if (!taskOverlay.mTaskOverlay) {
+                            continue;
+                        }
+                        taskOverlay.prepareActivityHideTransitionAnimation(transit);
+                    }
+                }
+                return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED;
+            } else {
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + this);
+            }
+
+            return FINISH_RESULT_REQUESTED;
+        } finally {
+            mAtmService.mWindowManager.continueSurfaceLayout();
+        }
+    }
+
+    private void prepareActivityHideTransitionAnimation(int transit) {
+        final DisplayContent dc = getDisplay().mDisplayContent;
+        dc.prepareAppTransition(transit, false);
+        setVisibility(false);
+        dc.executeAppTransition();
+    }
+
+    static final int FINISH_IMMEDIATELY = 0;
+    private static final int FINISH_AFTER_PAUSE = 1;
+    static final int FINISH_AFTER_VISIBLE = 2;
+
+    ActivityRecord finishCurrentActivityLocked(int mode, boolean oomAdj, String reason) {
+        // First things first: if this activity is currently visible,
+        // and the resumed activity is not yet visible, then hold off on
+        // finishing until the resumed one becomes visible.
+
+        // The activity that we are finishing may be over the lock screen. In this case, we do not
+        // want to consider activities that cannot be shown on the lock screen as running and should
+        // proceed with finishing the activity if there is no valid next top running activity.
+        // Note that if this finishing activity is floating task, we don't need to wait the
+        // next activity resume and can destroy it directly.
+        final ActivityStack stack = getActivityStack();
+        final ActivityDisplay display = getDisplay();
+        final ActivityRecord next = display.topRunningActivity(true /* considerKeyguardState */);
+        final boolean isFloating = getConfiguration().windowConfiguration.tasksAreFloating();
+
+        if (mode == FINISH_AFTER_VISIBLE && (visible || nowVisible)
+                && next != null && !next.nowVisible && !isFloating) {
+            if (!mStackSupervisor.mStoppingActivities.contains(this)) {
+                stack.addToStopping(this, false /* scheduleIdle */, false /* idleDelayed */,
+                        "finishCurrentActivityLocked");
+            }
+            if (DEBUG_STATES) {
+                Slog.v(TAG_STATES, "Moving to STOPPING: " + this + " (finish requested)");
+            }
+            setState(STOPPING, "finishCurrentActivityLocked");
+            if (oomAdj) {
+                mAtmService.updateOomAdj();
+            }
+            return this;
+        }
+
+        // make sure the record is cleaned out of other places.
+        mStackSupervisor.mStoppingActivities.remove(this);
+        mStackSupervisor.mGoingToSleepActivities.remove(this);
+        final ActivityState prevState = getState();
+        if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + this);
+
+        setState(FINISHING, "finishCurrentActivityLocked");
+
+        // Don't destroy activity immediately if the display contains home stack, although there is
+        // no next activity at the moment but another home activity should be started later. Keep
+        // this activity alive until next home activity is resumed then user won't see a temporary
+        // black screen.
+        final boolean noRunningStack = next == null && display.topRunningActivity() == null
+                && display.getHomeStack() == null;
+        final boolean noFocusedStack = stack != display.getFocusedStack();
+        final boolean finishingInNonFocusedStackOrNoRunning = mode == FINISH_AFTER_VISIBLE
+                && prevState == PAUSED && (noFocusedStack || noRunningStack);
+
+        if (mode == FINISH_IMMEDIATELY
+                || (prevState == PAUSED && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
+                || finishingInNonFocusedStackOrNoRunning
+                || prevState == STARTED
+                || prevState == STOPPING
+                || prevState == STOPPED
+                || prevState == ActivityState.INITIALIZING) {
+            makeFinishingLocked();
+            boolean activityRemoved = stack.destroyActivityLocked(this, true /* removeFromApp */,
+                    "finish-imm:" + reason);
+
+            if (finishingInNonFocusedStackOrNoRunning) {
+                // Finishing activity that was in paused state and it was in not currently focused
+                // stack, need to make something visible in its place. Also if the display does not
+                // have running activity, the configuration may need to be updated for restoring
+                // original orientation of the display.
+                mRootActivityContainer.ensureVisibilityAndConfig(next, getDisplayId(),
+                        false /* markFrozenIfConfigChanged */, true /* deferResume */);
+            }
+            if (activityRemoved) {
+                mRootActivityContainer.resumeFocusedStacksTopActivities();
+            }
+            if (DEBUG_CONTAINERS) {
+                Slog.d(TAG_CONTAINERS, "destroyActivityLocked: finishCurrentActivityLocked r="
+                        + this + " destroy returned removed=" + activityRemoved);
+            }
+            return activityRemoved ? null : this;
+        }
+
+        // Need to go through the full pause cycle to get this
+        // activity into the stopped state and then finish it.
+        if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + this);
+        mStackSupervisor.mFinishingActivities.add(this);
+        resumeKeyDispatchingLocked();
+        mRootActivityContainer.resumeFocusedStacksTopActivities();
+        // If activity was not paused at this point - explicitly pause it to start finishing
+        // process. Finishing will be completed once it reports pause back.
+        if (isState(RESUMED) && stack.mPausingActivity != null) {
+            stack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
+                    next /* resuming */, false /* dontWait */);
+        }
+        return this;
+    }
+
     void makeFinishingLocked() {
         if (finishing) {
             return;
@@ -2184,8 +2538,7 @@
             // been removed (e.g. destroy timeout), so the token could be null.
             return;
         }
-        r.icicle = null;
-        r.haveState = false;
+        r.setSavedState(null /* savedState */);
 
         final ActivityDisplay display = r.getDisplay();
         if (display != null) {
@@ -2258,19 +2611,18 @@
             return;
         }
         if (newPersistentState != null) {
-            persistentState = newPersistentState;
+            mPersistentState = newPersistentState;
             mAtmService.notifyTaskPersisterLocked(task, false);
         }
-        if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle);
 
         if (newIcicle != null) {
             // If icicle is null, this is happening due to a timeout, so we haven't really saved
             // the state.
-            icicle = newIcicle;
-            haveState = true;
+            setSavedState(newIcicle);
             launchCount = 0;
             updateTaskDescription(description);
         }
+        if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + mIcicle);
         if (!stopped) {
             if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
             stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
@@ -2551,7 +2903,8 @@
         }
         final TaskRecord task = r.task;
         final int activityNdx = task.mActivities.indexOf(r);
-        if (activityNdx < 0 || (onlyRoot && activityNdx > task.findEffectiveRootIndex())) {
+        if (activityNdx < 0
+                || (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) {
             return INVALID_TASK_ID;
         }
         return task.taskId;
@@ -2589,7 +2942,7 @@
         }
         final ActivityStack stack = getActivityStack();
         if (stack == null || this == stack.getResumedActivity() || this == stack.mPausingActivity
-                || !haveState || !stopped) {
+                || !mHaveState || !stopped) {
             // We're not ready for this kind of thing.
             return false;
         }
@@ -3524,7 +3877,7 @@
         // The restarting state avoids removing this record when process is died.
         setState(RESTARTING_PROCESS, "restartActivityProcess");
 
-        if (!visible || haveState) {
+        if (!visible || mHaveState) {
             // Kill its process immediately because the activity should be in background.
             // The activity state will be update to {@link #DESTROYED} in
             // {@link ActivityStack#cleanUpActivityLocked} when handling process died.
@@ -3613,9 +3966,9 @@
         intent.saveToXml(out);
         out.endTag(null, TAG_INTENT);
 
-        if (isPersistable() && persistentState != null) {
+        if (isPersistable() && mPersistentState != null) {
             out.startTag(null, TAG_PERSISTABLEBUNDLE);
-            persistentState.saveToXml(out);
+            mPersistentState.saveToXml(out);
             out.endTag(null, TAG_PERSISTABLEBUNDLE);
         }
     }
@@ -3696,7 +4049,7 @@
                 0 /* reqCode */, componentSpecified, false /* rootVoiceInteraction */,
                 stackSupervisor, null /* options */, null /* sourceRecord */);
 
-        r.persistentState = persistentState;
+        r.mPersistentState = persistentState;
         r.taskDescription = taskDescription;
         r.createTime = createTime;
 
@@ -3802,6 +4155,27 @@
         return display != null && this == display.getResumedActivity();
     }
 
+
+    /**
+     * Check if this is the root of the task - first activity that is not finishing, starting from
+     * the bottom of the task. If all activities are finishing - then this method will return
+     * {@code true} if the activity is at the bottom.
+     *
+     * NOTE: This is different from 'effective root' - an activity that defines the task identity.
+     */
+    boolean isRootOfTask() {
+        if (task == null) {
+            return false;
+        }
+        final ActivityRecord rootActivity = task.getRootActivity();
+        if (rootActivity != null) {
+            return this == rootActivity;
+        }
+        // No non-finishing activity found. In this case the bottom-most activity is considered to
+        // be the root.
+        return task.getChildAt(0) == this;
+    }
+
     void registerRemoteAnimations(RemoteAnimationDefinition definition) {
         if (mAppWindowToken == null) {
             Slog.w(TAG_WM, "Attempted to register remote animations with non-existing app"
@@ -3845,7 +4219,7 @@
         writeIdentifierToProto(proto, IDENTIFIER);
         proto.write(STATE, mState.toString());
         proto.write(VISIBLE, visible);
-        proto.write(FRONT_OF_TASK, frontOfTask);
+        proto.write(FRONT_OF_TASK, isRootOfTask());
         if (hasProcess()) {
             proto.write(PROC_ID, app.getPid());
         }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 18a57ae..17536e4 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -56,9 +56,12 @@
 import static com.android.server.am.ActivityStackProto.TASKS;
 import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
 import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
+import static com.android.server.wm.ActivityRecord.FINISH_AFTER_VISIBLE;
+import static com.android.server.wm.ActivityRecord.FINISH_IMMEDIATELY;
+import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
+import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
-import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
@@ -78,7 +81,6 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
@@ -93,7 +95,6 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
@@ -165,8 +166,6 @@
 import com.android.server.am.EventLogTags;
 import com.android.server.am.PendingIntentRecord;
 
-import com.google.android.collect.Sets;
-
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -187,7 +186,6 @@
     private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
     private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
     private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
-    private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
     private static final String TAG_STACK = TAG + POSTFIX_STACK;
     private static final String TAG_STATES = TAG + POSTFIX_STATES;
     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
@@ -565,7 +563,6 @@
                     + reason);
             setResumedActivity(record, reason + " - onActivityStateChanged");
             if (record == mRootActivityContainer.getTopResumedActivity()) {
-                // TODO(b/111361570): Support multiple focused apps in WM
                 mService.setResumedActivityUncheckLocked(record, reason);
             }
             mStackSupervisor.mRecentTasks.add(record.getTaskRecord());
@@ -1158,13 +1155,6 @@
         return null;
     }
 
-    private TaskRecord bottomTask() {
-        if (mTaskHistory.isEmpty()) {
-            return null;
-        }
-        return mTaskHistory.get(0);
-    }
-
     TaskRecord taskForIdLocked(int id) {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1500,8 +1490,6 @@
                 + " callers=" + Debug.getCallers(5));
         r.setState(RESUMED, "minimalResumeActivityLocked");
         r.completeResumeLocked();
-        if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
-                "Launch completed; removing icicle of " + r.icicle);
     }
 
     private void clearLaunchTime(ActivityRecord r) {
@@ -1783,7 +1771,7 @@
                     if (r.finishing) {
                         if (DEBUG_PAUSE) Slog.v(TAG,
                                 "Executing finish of failed to pause activity: " + r);
-                        finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false,
+                        r.finishCurrentActivityLocked(FINISH_AFTER_VISIBLE, false,
                                 "activityPausedLocked");
                     }
                 }
@@ -1802,7 +1790,7 @@
             prev.setState(PAUSED, "completePausedLocked");
             if (prev.finishing) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
-                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
+                prev = prev.finishCurrentActivityLocked(FINISH_AFTER_VISIBLE, false /* oomAdj */,
                         "completePausedLocked");
             } else if (prev.hasProcess()) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
@@ -1896,7 +1884,7 @@
         // last of activity of the last task the stack will be empty and must
         // be cleared immediately.
         boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
-                || (r.frontOfTask && mTaskHistory.size() <= 1);
+                || (r.isRootOfTask() && mTaskHistory.size() <= 1);
         if (scheduleIdle || forceIdle) {
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle="
                     + forceIdle + "immediate=" + !idleDelayed);
@@ -2794,8 +2782,8 @@
                 !mLastNoHistoryActivity.finishing) {
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "no-history finish of " + mLastNoHistoryActivity + " on new resume");
-            requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED,
-                    null, "resume-no-history", false);
+            mLastNoHistoryActivity.finishActivityLocked(Activity.RESULT_CANCELED,
+                    null /* resultData */, "resume-no-history", false /* oomAdj */);
             mLastNoHistoryActivity = null;
         }
 
@@ -3030,8 +3018,8 @@
                 // If any exception gets thrown, toss away this
                 // activity and try the next one.
                 Slog.w(TAG, "Exception thrown during resume of " + next, e);
-                requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
-                        "resume-exception", true);
+                next.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                        "resume-exception", true /* oomAdj */);
                 return true;
             }
         } else {
@@ -3210,8 +3198,6 @@
             r.createAppWindowToken();
         }
 
-        task.setFrontOfTask();
-
         // The transition animation and starting window are not needed if {@code allowMoveToFront}
         // is false, because the activity won't be visible.
         if ((!isHomeOrRecentsStack() || numActivities() > 0) && allowMoveToFront) {
@@ -3323,20 +3309,17 @@
     }
 
     /**
-     * Perform a reset of the given task, if needed as part of launching it.
-     * Returns the new HistoryRecord at the top of the task.
-     */
-    /**
-     * Helper method for #resetTaskIfNeededLocked.
-     * We are inside of the task being reset...  we'll either finish this activity, push it out
-     * for another task, or leave it as-is.
+     * Helper method for {@link #resetTaskIfNeededLocked(ActivityRecord, ActivityRecord)}.
+     * Performs a reset of the given task, if needed for new activity start.
      * @param task The task containing the Activity (taskTop) that might be reset.
-     * @param forceReset
+     * @param forceReset Flag indicating if clear task was requested
      * @return An ActivityOptions that needs to be processed.
      */
     private ActivityOptions resetTargetTaskIfNeededLocked(TaskRecord task, boolean forceReset) {
         ActivityOptions topOptions = null;
 
+        // Tracker of the end of currently handled reply chain (sublist) of activities. What happens
+        // to activities in the same chain will depend on what the end activity of the chain needs.
         int replyChainEnd = -1;
         boolean canMoveOptions = true;
 
@@ -3344,11 +3327,14 @@
         // the root, we may no longer have the task!).
         final ArrayList<ActivityRecord> activities = task.mActivities;
         final int numActivities = activities.size();
-        final int rootActivityNdx = task.findEffectiveRootIndex();
-        for (int i = numActivities - 1; i > rootActivityNdx; --i ) {
+        int lastActivityNdx = task.findRootIndex(true /* effectiveRoot */);
+        if (lastActivityNdx == -1) {
+            lastActivityNdx = 0;
+        }
+        for (int i = numActivities - 1; i > lastActivityNdx; --i) {
             ActivityRecord target = activities.get(i);
-            if (target.frontOfTask)
-                break;
+            // TODO: Why is this needed? Looks like we're breaking the loop before we reach the root
+            if (target.isRootOfTask()) break;
 
             final int flags = target.info.flags;
             final boolean finishOnTaskLaunch =
@@ -3381,12 +3367,13 @@
                 // bottom of the activity stack.  This also keeps it
                 // correctly ordered with any activities we previously
                 // moved.
+                // TODO: We should probably look for other stacks also, since corresponding task
+                // with the same affinity is unlikely to be in the same stack.
                 final TaskRecord targetTask;
                 final ActivityRecord bottom =
                         !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
                                 mTaskHistory.get(0).mActivities.get(0) : null;
-                if (bottom != null && target.taskAffinity != null
-                        && target.taskAffinity.equals(bottom.getTaskRecord().affinity)) {
+                if (bottom != null && target.taskAffinity.equals(bottom.getTaskRecord().affinity)) {
                     // If the activity currently at the bottom has the
                     // same task affinity as the one we are moving,
                     // then merge it into the same task.
@@ -3396,7 +3383,8 @@
                 } else {
                     targetTask = createTaskRecord(
                             mStackSupervisor.getNextTaskIdForUserLocked(target.mUserId),
-                            target.info, null, null, null, false);
+                            target.info, null /* intent */, null /* voiceSession */,
+                            null /* voiceInteractor */, false /* toTop */);
                     targetTask.affinityIntent = target.intent;
                     if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
                             + " out to new task " + targetTask);
@@ -3458,8 +3446,8 @@
                     }
                     if (DEBUG_TASKS) Slog.w(TAG_TASKS,
                             "resetTaskIntendedTask: calling finishActivity on " + p);
-                    if (finishActivityLocked(
-                            p, Activity.RESULT_CANCELED, null, "reset-task", false)) {
+                    if (p.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                            "reset-task", false /* oomAdj */) == FINISH_RESULT_REMOVED) {
                         end--;
                         srcPos--;
                     }
@@ -3477,28 +3465,34 @@
     }
 
     /**
-     * Helper method for #resetTaskIfNeededLocked. Processes all of the activities in a given
-     * TaskRecord looking for an affinity with the task of resetTaskIfNeededLocked.taskTop.
+     * Helper method for {@link #resetTaskIfNeededLocked(ActivityRecord, ActivityRecord)}.
+     * Processes all of the activities in a given TaskRecord looking for an affinity with the task
+     * of resetTaskIfNeededLocked.taskTop.
      * @param affinityTask The task we are looking for an affinity to.
      * @param task Task that resetTaskIfNeededLocked.taskTop belongs to.
      * @param topTaskIsHigher True if #task has already been processed by resetTaskIfNeededLocked.
-     * @param forceReset Flag passed in to resetTaskIfNeededLocked.
+     * @param forceReset Flag indicating if clear task was requested
      */
+    // TODO: Consider merging with #resetTargetTaskIfNeededLocked() above
     private int resetAffinityTaskIfNeededLocked(TaskRecord affinityTask, TaskRecord task,
             boolean topTaskIsHigher, boolean forceReset, int taskInsertionPoint) {
+        // Tracker of the end of currently handled reply chain (sublist) of activities. What happens
+        // to activities in the same chain will depend on what the end activity of the chain needs.
         int replyChainEnd = -1;
-        final int taskId = task.taskId;
         final String taskAffinity = task.affinity;
 
         final ArrayList<ActivityRecord> activities = affinityTask.mActivities;
         final int numActivities = activities.size();
-        final int rootActivityNdx = affinityTask.findEffectiveRootIndex();
 
         // Do not operate on or below the effective root Activity.
-        for (int i = numActivities - 1; i > rootActivityNdx; --i) {
+        int lastActivityNdx = affinityTask.findRootIndex(true /* effectiveRoot */);
+        if (lastActivityNdx == -1) {
+            lastActivityNdx = 0;
+        }
+        for (int i = numActivities - 1; i > lastActivityNdx; --i) {
             ActivityRecord target = activities.get(i);
-            if (target.frontOfTask)
-                break;
+            // TODO: Why is this needed? Looks like we're breaking the loop before we reach the root
+            if (target.isRootOfTask()) break;
 
             final int flags = target.info.flags;
             boolean finishOnTaskLaunch = (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
@@ -3537,8 +3531,8 @@
                         if (p.finishing) {
                             continue;
                         }
-                        finishActivityLocked(
-                                p, Activity.RESULT_CANCELED, null, "move-affinity", false);
+                        p.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                                "move-affinity", false /* oomAdj */);
                     }
                 } else {
                     if (taskInsertionPoint < 0) {
@@ -3567,13 +3561,13 @@
                     // instance of the same activity?  Then we drop the instance
                     // below so it remains singleTop.
                     if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
-                        ArrayList<ActivityRecord> taskActivities = task.mActivities;
-                        int targetNdx = taskActivities.indexOf(target);
+                        final ArrayList<ActivityRecord> taskActivities = task.mActivities;
+                        final int targetNdx = taskActivities.indexOf(target);
                         if (targetNdx > 0) {
-                            ActivityRecord p = taskActivities.get(targetNdx - 1);
+                            final ActivityRecord p = taskActivities.get(targetNdx - 1);
                             if (p.intent.getComponent().equals(target.intent.getComponent())) {
-                                finishActivityLocked(p, Activity.RESULT_CANCELED, null, "replace",
-                                        false);
+                                p.finishActivityLocked(Activity.RESULT_CANCELED,
+                                        null /* resultData */, "replace", false /* oomAdj */);
                             }
                         }
                     }
@@ -3591,11 +3585,11 @@
                 (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
         final TaskRecord task = taskTop.getTaskRecord();
 
-        /** False until we evaluate the TaskRecord associated with taskTop. Switches to true
-         * for remaining tasks. Used for later tasks to reparent to task. */
+        // False until we evaluate the TaskRecord associated with taskTop. Switches to true
+        // for remaining tasks. Used for later tasks to reparent to task.
         boolean taskFound = false;
 
-        /** If ActivityOptions are moved out and need to be aborted or moved to taskTop. */
+        // If ActivityOptions are moved out and need to be aborted or moved to taskTop.
         ActivityOptions topOptions = null;
 
         // Preserve the location for reparenting in the new task.
@@ -3676,7 +3670,7 @@
         return false;
     }
 
-    private void adjustFocusedActivityStack(ActivityRecord r, String reason) {
+    void adjustFocusedActivityStack(ActivityRecord r, String reason) {
         if (!mRootActivityContainer.isTopDisplayFocusedStack(this) ||
                 ((mResumedActivity != r) && (mResumedActivity != null))) {
             return;
@@ -3711,9 +3705,6 @@
         if (nextFocusableStack != null) {
             final ActivityRecord top = nextFocusableStack.topRunningActivityLocked();
             if (top != null && top == mRootActivityContainer.getTopResumedActivity()) {
-                // TODO(b/111361570): Remove this and update focused app per-display in
-                // WindowManager every time an activity becomes resumed in
-                // ActivityTaskManagerService#setResumedActivityUncheckLocked().
                 mService.setResumedActivityUncheckLocked(top, reason);
             }
             return;
@@ -3764,10 +3755,9 @@
             if (!r.finishing) {
                 if (!shouldSleepActivities()) {
                     if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
-                    if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
-                            "stop-no-history", false)) {
-                        // If {@link requestFinishActivityLocked} returns {@code true},
-                        // {@link adjustFocusedActivityStack} would have been already called.
+                    if (r.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                            "stop-no-history", false /* oomAdj */) != FINISH_RESULT_CANCELLED) {
+                        // {@link adjustFocusedActivityStack} must have been already called.
                         r.resumeKeyDispatchingLocked();
                         return;
                     }
@@ -3816,25 +3806,7 @@
         }
     }
 
-    /**
-     * @return Returns true if the activity is being finished, false if for
-     * some reason it is being left as-is.
-     */
-    final boolean requestFinishActivityLocked(IBinder token, int resultCode,
-            Intent resultData, String reason, boolean oomAdj) {
-        ActivityRecord r = isInStackLocked(token);
-        if (DEBUG_RESULTS || DEBUG_STATES) Slog.v(TAG_STATES,
-                "Finishing activity token=" + token + " r="
-                + ", result=" + resultCode + ", data=" + resultData
-                + ", reason=" + reason);
-        if (r == null) {
-            return false;
-        }
-
-        finishActivityLocked(r, resultCode, resultData, reason, oomAdj);
-        return true;
-    }
-
+    /** Finish all activities that were started for result from the specified activity. */
     final void finishSubActivityLocked(ActivityRecord self, String resultWho, int requestCode) {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
@@ -3843,8 +3815,8 @@
                 if (r.resultTo == self && r.requestCode == requestCode) {
                     if ((r.resultWho == null && resultWho == null) ||
                         (r.resultWho != null && r.resultWho.equals(resultWho))) {
-                        finishActivityLocked(r, Activity.RESULT_CANCELED, null, "request-sub",
-                                false);
+                        r.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                                "request-sub", false /* oomAdj */);
                     }
                 }
             }
@@ -3874,7 +3846,8 @@
         int activityNdx = task.mActivities.indexOf(r);
         getDisplay().mDisplayContent.prepareAppTransition(
                 TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
-        finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
+        r.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */, reason,
+                false /* oomAdj */);
         finishedTask = task;
         // Also terminate any activities below it that aren't yet
         // stopped, to avoid a situation where one will get
@@ -3895,7 +3868,8 @@
                 if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
                     Slog.w(TAG, "  Force finishing activity "
                             + r.intent.getComponent().flattenToShortString());
-                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
+                    r.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */, reason,
+                            false /* oomAdj */);
                 }
             }
         }
@@ -3911,8 +3885,8 @@
                 for (int activityNdx = tr.mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
                     ActivityRecord r = tr.mActivities.get(activityNdx);
                     if (!r.finishing) {
-                        finishActivityLocked(r, Activity.RESULT_CANCELED, null, "finish-voice",
-                                false);
+                        r.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                                "finish-voice", false /* oomAdj */);
                         didOne = true;
                     }
                 }
@@ -3941,280 +3915,17 @@
         }
     }
 
-    final boolean finishActivityAffinityLocked(ActivityRecord r) {
-        ArrayList<ActivityRecord> activities = r.getTaskRecord().mActivities;
-        for (int index = activities.indexOf(r); index >= 0; --index) {
-            ActivityRecord cur = activities.get(index);
-            if (!Objects.equals(cur.taskAffinity, r.taskAffinity)) {
-                break;
-            }
-            finishActivityLocked(cur, Activity.RESULT_CANCELED, null, "request-affinity", true);
-        }
-        return true;
-    }
-
-    private void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
-        // send the result
-        ActivityRecord resultTo = r.resultTo;
-        if (resultTo != null) {
-            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Adding result to " + resultTo
-                    + " who=" + r.resultWho + " req=" + r.requestCode
-                    + " res=" + resultCode + " data=" + resultData);
-            if (resultTo.mUserId != r.mUserId) {
-                if (resultData != null) {
-                    resultData.prepareToLeaveUser(r.mUserId);
-                }
-            }
-            if (r.info.applicationInfo.uid > 0) {
-                mService.mUgmInternal.grantUriPermissionFromIntent(r.info.applicationInfo.uid,
-                        resultTo.packageName, resultData,
-                        resultTo.getUriPermissionsLocked(), resultTo.mUserId);
-            }
-            resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode, resultData);
-            r.resultTo = null;
-        }
-        else if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "No result destination from " + r);
-
-        // Make sure this HistoryRecord is not holding on to other resources,
-        // because clients have remote IPC references to this object so we
-        // can't assume that will go away and want to avoid circular IPC refs.
-        r.results = null;
-        r.pendingResults = null;
-        r.newIntents = null;
-        r.icicle = null;
-    }
-
-    /**
-     * See {@link #finishActivityLocked(ActivityRecord, int, Intent, String, boolean, boolean)}
-     */
-    final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
-            String reason, boolean oomAdj) {
-        return finishActivityLocked(r, resultCode, resultData, reason, oomAdj, !PAUSE_IMMEDIATELY);
-    }
-
-    /**
-     * @return Returns true if this activity has been removed from the history
-     * list, or false if it is still in the list and will be removed later.
-     */
-    final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
-            String reason, boolean oomAdj, boolean pauseImmediately) {
-        if (r.finishing) {
-            Slog.w(TAG, "Duplicate finish request for " + r);
-            return false;
-        }
-
-        mWindowManager.deferSurfaceLayout();
-        try {
-            r.makeFinishingLocked();
-            final TaskRecord task = r.getTaskRecord();
-            EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
-                    r.mUserId, System.identityHashCode(r),
-                    task.taskId, r.shortComponentName, reason);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
-            final int index = activities.indexOf(r);
-            if (index < (activities.size() - 1)) {
-                task.setFrontOfTask();
-                if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
-                    // If the caller asked that this activity (and all above it)
-                    // be cleared when the task is reset, don't lose that information,
-                    // but propagate it up to the next activity.
-                    ActivityRecord next = activities.get(index+1);
-                    next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
-                }
-            }
-
-            r.pauseKeyDispatchingLocked();
-
-            adjustFocusedActivityStack(r, "finishActivity");
-
-            finishActivityResultsLocked(r, resultCode, resultData);
-
-            final boolean endTask = index <= 0 && !task.isClearingToReuseTask();
-            final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;
-            if (mResumedActivity == r) {
-                if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
-                        "Prepare close transition: finishing " + r);
-                if (endTask) {
-                    mService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
-                            task.getTaskInfo());
-                }
-                getDisplay().mDisplayContent.prepareAppTransition(transit, false);
-
-                // When finishing the activity pre-emptively take the snapshot before the app window
-                // is marked as hidden and any configuration changes take place
-                if (mWindowManager.mTaskSnapshotController != null) {
-                    final ArraySet<Task> tasks = Sets.newArraySet(task.mTask);
-                    mWindowManager.mTaskSnapshotController.snapshotTasks(tasks);
-                    mWindowManager.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(tasks);
-                }
-
-                // Tell window manager to prepare for this one to be removed.
-                r.setVisibility(false);
-
-                if (mPausingActivity == null) {
-                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
-                    if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
-                            "finish() => pause with userLeaving=false");
-                    startPausingLocked(false, false, null, pauseImmediately);
-                }
-
-                if (endTask) {
-                    mService.getLockTaskController().clearLockedTask(task);
-                }
-            } else if (!r.isState(PAUSING)) {
-                // If the activity is PAUSING, we will complete the finish once
-                // it is done pausing; else we can just directly finish it here.
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
-                if (r.visible) {
-                    prepareActivityHideTransitionAnimation(r, transit);
-                }
-
-                final int finishMode = (r.visible || r.nowVisible) ? FINISH_AFTER_VISIBLE
-                        : FINISH_AFTER_PAUSE;
-                final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj,
-                        "finishActivityLocked") == null;
-
-                // The following code is an optimization. When the last non-task overlay activity
-                // is removed from the task, we remove the entire task from the stack. However,
-                // since that is done after the scheduled destroy callback from the activity, that
-                // call to change the visibility of the task overlay activities would be out of
-                // sync with the activitiy visibility being set for this finishing activity above.
-                // In this case, we can set the visibility of all the task overlay activities when
-                // we detect the last one is finishing to keep them in sync.
-                if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) {
-                    for (ActivityRecord taskOverlay : task.mActivities) {
-                        if (!taskOverlay.mTaskOverlay) {
-                            continue;
-                        }
-                        prepareActivityHideTransitionAnimation(taskOverlay, transit);
-                    }
-                }
-                return removedActivity;
-            } else {
-                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
-            }
-
-            return false;
-        } finally {
-            mWindowManager.continueSurfaceLayout();
-        }
-    }
-
-    private void prepareActivityHideTransitionAnimation(ActivityRecord r, int transit) {
-        final DisplayContent dc = getDisplay().mDisplayContent;
-        dc.prepareAppTransition(transit, false);
-        r.setVisibility(false);
-        dc.executeAppTransition();
-    }
-
-    static final int FINISH_IMMEDIATELY = 0;
-    static final int FINISH_AFTER_PAUSE = 1;
-    static final int FINISH_AFTER_VISIBLE = 2;
-
-    final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj,
-            String reason) {
-        // First things first: if this activity is currently visible,
-        // and the resumed activity is not yet visible, then hold off on
-        // finishing until the resumed one becomes visible.
-
-        // The activity that we are finishing may be over the lock screen. In this case, we do not
-        // want to consider activities that cannot be shown on the lock screen as running and should
-        // proceed with finishing the activity if there is no valid next top running activity.
-        // Note that if this finishing activity is floating task, we don't need to wait the
-        // next activity resume and can destroy it directly.
-        final ActivityDisplay display = getDisplay();
-        final ActivityRecord next = display.topRunningActivity(true /* considerKeyguardState */);
-        final boolean isFloating = r.getConfiguration().windowConfiguration.tasksAreFloating();
-
-        if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible)
-                && next != null && !next.nowVisible && !isFloating) {
-            if (!mStackSupervisor.mStoppingActivities.contains(r)) {
-                addToStopping(r, false /* scheduleIdle */, false /* idleDelayed */,
-                        "finishCurrentActivityLocked");
-            }
-            if (DEBUG_STATES) Slog.v(TAG_STATES,
-                    "Moving to STOPPING: "+ r + " (finish requested)");
-            r.setState(STOPPING, "finishCurrentActivityLocked");
-            if (oomAdj) {
-                mService.updateOomAdj();
-            }
-            return r;
-        }
-
-        // make sure the record is cleaned out of other places.
-        mStackSupervisor.mStoppingActivities.remove(r);
-        mStackSupervisor.mGoingToSleepActivities.remove(r);
-        final ActivityState prevState = r.getState();
-        if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
-
-        r.setState(FINISHING, "finishCurrentActivityLocked");
-
-        // Don't destroy activity immediately if the display contains home stack, although there is
-        // no next activity at the moment but another home activity should be started later. Keep
-        // this activity alive until next home activity is resumed then user won't see a temporary
-        // black screen.
-        final boolean noRunningStack = next == null && display.topRunningActivity() == null
-                && display.getHomeStack() == null;
-        final boolean noFocusedStack = r.getActivityStack() != display.getFocusedStack();
-        final boolean finishingInNonFocusedStackOrNoRunning = mode == FINISH_AFTER_VISIBLE
-                && prevState == PAUSED && (noFocusedStack || noRunningStack);
-
-        if (mode == FINISH_IMMEDIATELY
-                || (prevState == PAUSED
-                    && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
-                || finishingInNonFocusedStackOrNoRunning
-                || prevState == STARTED
-                || prevState == STOPPING
-                || prevState == STOPPED
-                || prevState == ActivityState.INITIALIZING) {
-            r.makeFinishingLocked();
-            boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason);
-
-            if (finishingInNonFocusedStackOrNoRunning) {
-                // Finishing activity that was in paused state and it was in not currently focused
-                // stack, need to make something visible in its place. Also if the display does not
-                // have running activity, the configuration may need to be updated for restoring
-                // original orientation of the display.
-                mRootActivityContainer.ensureVisibilityAndConfig(next, mDisplayId,
-                        false /* markFrozenIfConfigChanged */, true /* deferResume */);
-            }
-            if (activityRemoved) {
-                mRootActivityContainer.resumeFocusedStacksTopActivities();
-            }
-            if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
-                    "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
-                    " destroy returned removed=" + activityRemoved);
-            return activityRemoved ? null : r;
-        }
-
-        // Need to go through the full pause cycle to get this
-        // activity into the stopped state and then finish it.
-        if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
-        mStackSupervisor.mFinishingActivities.add(r);
-        r.resumeKeyDispatchingLocked();
-        mRootActivityContainer.resumeFocusedStacksTopActivities();
-        // If activity was not paused at this point - explicitly pause it to start finishing
-        // process. Finishing will be completed once it reports pause back.
-        if (r.isState(RESUMED) && mPausingActivity != null) {
-            startPausingLocked(false /* userLeaving */, false /* uiSleeping */, next /* resuming */,
-                    false /* dontWait */);
-        }
-        return r;
-    }
-
-    void finishAllActivitiesLocked(boolean immediately) {
+    /** Finish all activities in the stack without waiting. */
+    void finishAllActivitiesImmediately() {
         boolean noActivitiesInStack = true;
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 noActivitiesInStack = false;
-                if (r.finishing && !immediately) {
-                    continue;
-                }
-                Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r + " immediately");
-                finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
-                        "finishAllActivitiesLocked");
+                Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r);
+                r.finishCurrentActivityLocked(FINISH_IMMEDIATELY, false /* oomAdj */,
+                        "finishAllActivitiesImmediatelyLocked");
             }
         }
         if (noActivitiesInStack) {
@@ -4248,7 +3959,8 @@
         // of a document, unless simply finishing it will return them to the the
         // correct app behind.
         final TaskRecord task = srec.getTaskRecord();
-        if (srec.frontOfTask && task.getBaseIntent() != null && task.getBaseIntent().isDocument()) {
+        if (srec.isRootOfTask() && task.getBaseIntent() != null
+                && task.getBaseIntent().isDocument()) {
             // Okay, this activity is at the root of its task.  What to do, what to do...
             if (!inFrontOfStandardStack()) {
                 // Finishing won't return to an application, so we need to recreate.
@@ -4316,8 +4028,8 @@
         }
         final long origId = Binder.clearCallingIdentity();
         for (int i = start; i > finishTo; i--) {
-            ActivityRecord r = activities.get(i);
-            requestFinishActivityLocked(r.appToken, resultCode, resultData, "navigate-up", true);
+            final ActivityRecord r = activities.get(i);
+            r.finishActivityLocked(resultCode, resultData, "navigate-up", true /* oomAdj */);
             // Only return the supplied result for the first activity finished
             resultCode = Activity.RESULT_CANCELED;
             resultData = null;
@@ -4354,8 +4066,8 @@
                 } catch (RemoteException e) {
                     foundParentInTask = false;
                 }
-                requestFinishActivityLocked(parent.appToken, resultCode,
-                        resultData, "navigate-top", true);
+                parent.finishActivityLocked(resultCode, resultData, "navigate-top",
+                        true /* oomAdj */);
             }
         }
         Binder.restoreCallingIdentity(origId);
@@ -4440,7 +4152,7 @@
     }
 
     private void removeActivityFromHistoryLocked(ActivityRecord r, String reason) {
-        finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
+        r.finishActivityResults(Activity.RESULT_CANCELED, null /* resultData */);
         r.makeFinishingLocked();
         if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
                 "Removing activity " + r + " from stack callers=" + Debug.getCallers(5));
@@ -4798,7 +4510,7 @@
                         // it has failed more than twice. Skip activities that's already finishing
                         // cleanly by itself.
                         remove = false;
-                    } else if ((!r.haveState && !r.stateNotNeeded
+                    } else if ((!r.hasSavedState() && !r.stateNotNeeded
                             && !r.isState(ActivityState.RESTARTING_PROCESS)) || r.finishing) {
                         // Don't currently have state for the activity, or
                         // it is finishing -- always remove it.
@@ -4818,7 +4530,7 @@
                     if (remove) {
                         if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE,
                                 "Removing activity " + r + " from stack at " + i
-                                + ": haveState=" + r.haveState
+                                + ": hasSavedState=" + r.hasSavedState()
                                 + " stateNotNeeded=" + r.stateNotNeeded
                                 + " finishing=" + r.finishing
                                 + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
@@ -4841,11 +4553,6 @@
                         // This is needed when user later tap on the dead window, we need to stop
                         // other apps when user transfers focus to the restarted activity.
                         r.nowVisible = r.visible;
-                        if (!r.haveState) {
-                            if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
-                                    "App died, clearing saved state of " + r);
-                            r.icicle = null;
-                        }
                     }
                     cleanUpActivityLocked(r, true, true);
                     if (remove) {
@@ -5183,7 +4890,7 @@
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
-                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, "close-sys", true);
+                    r.finishActivityLocked(Activity.RESULT_CANCELED, null, "close-sys", true);
                 }
             }
         }
@@ -5227,8 +4934,7 @@
                     didSomething = true;
                     Slog.i(TAG, "  Force finishing activity " + r);
                     lastTask = r.getTaskRecord();
-                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop",
-                            true);
+                    r.finishActivityLocked(Activity.RESULT_CANCELED, null, "force-stop", true);
                 }
             }
         }
@@ -5282,7 +4988,7 @@
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(top).mActivities;
             int activityTop = activities.size() - 1;
             if (activityTop >= 0) {
-                finishActivityLocked(activities.get(activityTop), Activity.RESULT_CANCELED, null,
+                activities.get(activityTop).finishActivityLocked(Activity.RESULT_CANCELED, null,
                         "unhandled-back", true);
             }
         }
@@ -5319,7 +5025,7 @@
                     r.app = null;
                     getDisplay().mDisplayContent.prepareAppTransition(
                             TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
-                    finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
+                    r.finishCurrentActivityLocked(FINISH_IMMEDIATELY, false /* oomAdj */,
                             "handleAppCrashedLocked");
                 }
             }
@@ -5651,7 +5357,6 @@
         // If the original state is resumed, there is no state change to update focused app.
         // So here makes sure the activity focus is set if it is the top.
         if (origState == RESUMED && r == mRootActivityContainer.getTopResumedActivity()) {
-            // TODO(b/111361570): Support multiple focused apps in WM
             mService.setResumedActivityUncheckLocked(r, reason);
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index feb4a36..1c56a10 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -130,6 +130,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.ReferrerIntent;
@@ -323,6 +324,12 @@
     boolean mUserLeaving = false;
 
     /**
+     * The system chooser activity which worked as a delegate of
+     * {@link com.android.internal.app.ResolverActivity}.
+     */
+    private ComponentName mSystemChooserActivity;
+
+    /**
      * We don't want to allow the device to go to sleep while in the process
      * of launching an activity.  This is primarily to allow alarm intent
      * receivers to launch an activity and get that to run before the device
@@ -469,6 +476,14 @@
         return mKeyguardController;
     }
 
+    ComponentName getSystemChooserActivity() {
+        if (mSystemChooserActivity == null) {
+            mSystemChooserActivity = ComponentName.unflattenFromString(
+                    mService.mContext.getResources().getString(R.string.config_chooserActivity));
+        }
+        return mSystemChooserActivity;
+    }
+
     void setRecentTasks(RecentTasks recentTasks) {
         mRecentTasks = recentTasks;
         mRecentTasks.registerCallback(this);
@@ -798,8 +813,9 @@
                     newIntents = r.newIntents;
                 }
                 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
-                        "Launching: " + r + " icicle=" + r.icicle + " with results=" + results
-                                + " newIntents=" + newIntents + " andResume=" + andResume);
+                        "Launching: " + r + " savedState=" + r.getSavedState()
+                                + " with results=" + results + " newIntents=" + newIntents
+                                + " andResume=" + andResume);
                 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.mUserId,
                         System.identityHashCode(r), task.taskId, r.shortComponentName);
                 if (r.isActivityTypeHome()) {
@@ -821,7 +837,7 @@
                         proc.getConfiguration(), r.getMergedOverrideConfiguration());
                 r.setLastReportedConfiguration(mergedConfiguration);
 
-                logIfTransactionTooLarge(r.intent, r.icicle);
+                logIfTransactionTooLarge(r.intent, r.getSavedState());
 
 
                 // Create activity launch transaction.
@@ -836,7 +852,7 @@
                         mergedConfiguration.getGlobalConfiguration(),
                         mergedConfiguration.getOverrideConfiguration(), r.compat,
                         r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
-                        r.icicle, r.persistentState, results, newIntents,
+                        r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
                         dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
                                 r.assistToken));
 
@@ -874,8 +890,8 @@
                     Slog.e(TAG, "Second failure launching "
                             + r.intent.getComponent().flattenToShortString() + ", giving up", e);
                     proc.appDied();
-                    stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
-                            "2nd-crash", false);
+                    r.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                            "2nd-crash", false /* oomAdj */);
                     return false;
                 }
 
@@ -1324,8 +1340,8 @@
             final ActivityStack stack = r.getActivityStack();
             if (stack != null) {
                 if (r.finishing) {
-                    stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
-                            "activityIdleInternalLocked");
+                    r.finishCurrentActivityLocked(ActivityRecord.FINISH_IMMEDIATELY,
+                            false /* oomAdj */, "activityIdleInternalLocked");
                 } else {
                     stack.stopActivityLocked(r);
                 }
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 54eb07f..a334ed8 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1416,7 +1416,7 @@
                 // performing operations without a window container.
                 final ActivityStack stack = mStartActivity.getActivityStack();
                 if (stack != null) {
-                    stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
+                    mStartActivity.finishActivityLocked(RESULT_CANCELED,
                             null /* intentResultData */, "startActivity", true /* oomAdj */);
                 }
 
@@ -1557,7 +1557,7 @@
                 }
 
                 if (top != null) {
-                    if (top.frontOfTask) {
+                    if (top.isRootOfTask()) {
                         // Activity aliases may mean we use different intents for the top activity,
                         // so make sure the task now has the identity of the new intent.
                         top.getTaskRecord().setIntent(mStartActivity);
@@ -1980,8 +1980,8 @@
             // Also put noDisplay activities in the source task. These by itself can be placed
             // in any task/stack, however it could launch other activities like ResolverActivity,
             // and we want those to stay in the original task.
-            if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
-                    && mSourceRecord.inFreeformWindowingMode())  {
+            if ((mStartActivity.isResolverOrDelegateActivity() || mStartActivity.noDisplay)
+                    && mSourceRecord != null && mSourceRecord.inFreeformWindowingMode()) {
                 mAddingToTask = true;
             }
         }
@@ -2260,7 +2260,7 @@
                         || LAUNCH_SINGLE_TOP == mLaunchMode)
                     && intentActivity.mActivityComponent.equals(
                             mStartActivity.mActivityComponent)) {
-                if (intentActivity.frontOfTask) {
+                if (intentActivity.isRootOfTask()) {
                     intentActivity.getTaskRecord().setIntent(mStartActivity);
                 }
                 deliverNewIntent(intentActivity);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 971a24d..b351faf 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -84,6 +84,7 @@
 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;
@@ -1553,13 +1554,13 @@
         }
 
         synchronized (mGlobalLock) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return true;
             }
             // Keep track of the root activity of the task before we finish it
             final TaskRecord tr = r.getTaskRecord();
-            ActivityRecord rootR = tr.getRootActivity();
+            final ActivityRecord rootR = tr.getRootActivity();
             if (rootR == null) {
                 Slog.w(TAG, "Finishing task with all activities already finished");
             }
@@ -1609,7 +1610,7 @@
                     // because we don't support returning them across task boundaries. Also, to
                     // keep backwards compatibility we remove the task from recents when finishing
                     // task with root activity.
-                    res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
+                    res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false /* killProcess */,
                             finishWithRootActivity, "finish-activity");
                     if (!res) {
                         Slog.i(TAG, "Removing task failed to finish activity");
@@ -1617,8 +1618,8 @@
                     // Explicitly dismissing the activity so reset its relaunch flag.
                     r.mRelaunchReason = RELAUNCH_REASON_NONE;
                 } else {
-                    res = tr.getStack().requestFinishActivityLocked(token, resultCode,
-                            resultData, "app-request", true);
+                    res = r.finishActivityLocked(resultCode, resultData, "app-request",
+                            true /* oomAdj */) != FINISH_RESULT_CANCELLED;
                     if (!res) {
                         Slog.i(TAG, "Failed to finish by app-request");
                     }
@@ -1642,11 +1643,11 @@
 
                 // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps
                 // can finish.
-                final TaskRecord task = r.getTaskRecord();
                 if (getLockTaskController().activityBlockedFromFinish(r)) {
                     return false;
                 }
-                return task.getStack().finishActivityAffinityLocked(r);
+                r.finishActivityAffinity();
+                return true;
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -4912,7 +4913,7 @@
     }
 
     void dumpActivityContainersLocked(PrintWriter pw) {
-        pw.println("ACTIVITY MANAGER STARTER (dumpsys activity containers)");
+        pw.println("ACTIVITY MANAGER CONTAINERS (dumpsys activity containers)");
         mRootActivityContainer.dumpChildrenNames(pw, " ");
         pw.println(" ");
     }
@@ -4928,6 +4929,9 @@
      *  - the cmd arg isn't the flattened component name of an existing activity:
      *    dump all activity whose component contains the cmd as a substring
      *  - A hex number of the ActivityRecord object instance.
+     * <p>
+     * The caller should not hold lock when calling this method because it will wait for the
+     * activities to complete the dump.
      *
      *  @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
      *  @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
@@ -4980,29 +4984,28 @@
     private void dumpActivity(String prefix, FileDescriptor fd, PrintWriter pw,
             final ActivityRecord r, String[] args, boolean dumpAll) {
         String innerPrefix = prefix + "  ";
+        IApplicationThread appThread = null;
         synchronized (mGlobalLock) {
             pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
             pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
             pw.print(" pid=");
-            if (r.hasProcess()) pw.println(r.app.getPid());
-            else pw.println("(not running)");
+            if (r.hasProcess()) {
+                pw.println(r.app.getPid());
+                appThread = r.app.getThread();
+            } else {
+                pw.println("(not running)");
+            }
             if (dumpAll) {
                 r.dump(pw, innerPrefix);
             }
         }
-        if (r.attachedToProcess()) {
+        if (appThread != null) {
             // flush anything that is already in the PrintWriter since the thread is going
             // to write to the file descriptor directly
             pw.flush();
-            try {
-                TransferPipe tp = new TransferPipe();
-                try {
-                    r.app.getThread().dumpActivity(tp.getWriteFd(),
-                            r.appToken, innerPrefix, args);
-                    tp.go(fd);
-                } finally {
-                    tp.kill();
-                }
+            try (TransferPipe tp = new TransferPipe()) {
+                appThread.dumpActivity(tp.getWriteFd(), r.appToken, innerPrefix, args);
+                tp.go(fd);
             } catch (IOException e) {
                 pw.println(innerPrefix + "Failure while dumping the activity: " + e);
             } catch (RemoteException e) {
@@ -7063,10 +7066,8 @@
         public boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
                 String[] args, int opti, boolean dumpAll, boolean dumpVisibleStacksOnly,
                 boolean dumpFocusedStackOnly) {
-            synchronized (mGlobalLock) {
-                return ActivityTaskManagerService.this.dumpActivity(fd, pw, name, args, opti,
-                        dumpAll, dumpVisibleStacksOnly, dumpFocusedStackOnly);
-            }
+            return ActivityTaskManagerService.this.dumpActivity(fd, pw, name, args, opti, dumpAll,
+                    dumpVisibleStacksOnly, dumpFocusedStackOnly);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 8007c0f..aefc152 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -260,9 +260,9 @@
     ActivityRecord mActivityRecord;
 
     /**
-     * See {@link #canTurnScreenOn()}
+     * @see #currentLaunchCanTurnScreenOn()
      */
-    private boolean mCanTurnScreenOn = true;
+    private boolean mCurrentLaunchCanTurnScreenOn = true;
 
     /**
      * If we are running an animation, this determines the transition type. Must be one of
@@ -1002,7 +1002,7 @@
                 + " " + this);
         mAppStopped = false;
         // Allow the window to turn the screen on once the app is resumed again.
-        setCanTurnScreenOn(true);
+        setCurrentLaunchCanTurnScreenOn(true);
         if (!wasStopped) {
             destroySurfaces(true /*cleanupOnResume*/);
         }
@@ -1015,6 +1015,8 @@
     void notifyAppStopped() {
         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this);
         mAppStopped = true;
+        // Reset the last saved PiP snap fraction on app stop.
+        mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
         destroySurfaces();
         // Remove any starting window that was added for this app if they are still around.
         removeStartingWindow();
@@ -2420,21 +2422,25 @@
     }
 
     /**
-     * Sets whether the current launch can turn the screen on. See {@link #canTurnScreenOn()}
+     * Sets whether the current launch can turn the screen on.
+     * @see #currentLaunchCanTurnScreenOn()
      */
-    void setCanTurnScreenOn(boolean canTurnScreenOn) {
-        mCanTurnScreenOn = canTurnScreenOn;
+    void setCurrentLaunchCanTurnScreenOn(boolean currentLaunchCanTurnScreenOn) {
+        mCurrentLaunchCanTurnScreenOn = currentLaunchCanTurnScreenOn;
     }
 
     /**
      * Indicates whether the current launch can turn the screen on. This is to prevent multiple
      * relayouts from turning the screen back on. The screen should only turn on at most
      * once per activity resume.
+     * <p>
+     * Note this flag is only meaningful when {@link WindowManager.LayoutParams#FLAG_TURN_SCREEN_ON}
+     * or {@link ActivityRecord#canTurnScreenOn} is set.
      *
-     * @return true if the screen can be turned on.
+     * @return {@code true} if the activity is ready to turn on the screen.
      */
-    boolean canTurnScreenOn() {
-        return mCanTurnScreenOn;
+    boolean currentLaunchCanTurnScreenOn() {
+        return mCurrentLaunchCanTurnScreenOn;
     }
 
     /**
@@ -2481,7 +2487,7 @@
         // transformed the task.
         final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
         if (controller != null && controller.isAnimatingTask(getTask())
-                && controller.shouldCancelWithDeferredScreenshot()) {
+                && controller.shouldDeferCancelUntilNextTransition()) {
             return false;
         }
 
@@ -3072,11 +3078,6 @@
     @Override
     void setHidden(boolean hidden) {
         super.setHidden(hidden);
-
-        if (hidden) {
-            // Once the app window is hidden, reset the last saved PiP snap fraction
-            mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
-        }
         scheduleAnimation();
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e2d5928..faf75b6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -122,7 +122,6 @@
 import static com.android.server.wm.WindowManagerService.H.REPORT_FOCUS_CHANGE;
 import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE;
 import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS;
-import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
 import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER;
 import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
@@ -1212,27 +1211,45 @@
         }
     }
 
-    /** Notify the configuration change of this display. */
-    void postNewConfigurationToHandler() {
-        mWmService.mH.obtainMessage(SEND_NEW_CONFIGURATION, this).sendToTarget();
+    void reconfigureDisplayLocked() {
+        if (!isReady()) {
+            return;
+        }
+        configureDisplayPolicy();
+        setLayoutNeeded();
+
+        boolean configChanged = updateOrientationFromAppTokens();
+        final Configuration currentDisplayConfig = getConfiguration();
+        mTmpConfiguration.setTo(currentDisplayConfig);
+        computeScreenConfiguration(mTmpConfiguration);
+        configChanged |= currentDisplayConfig.diff(mTmpConfiguration) != 0;
+
+        if (configChanged) {
+            mWaitingForConfig = true;
+            mWmService.startFreezingDisplayLocked(0 /* exitAnim */, 0 /* enterAnim */, this);
+            sendNewConfiguration();
+        }
+
+        mWmService.mWindowPlacerLocked.performSurfacePlacement();
     }
 
     void sendNewConfiguration() {
-        synchronized (mWmService.mGlobalLock) {
-            final boolean configUpdated = mAcitvityDisplay
-                    .updateDisplayOverrideConfigurationLocked();
-            if (!configUpdated) {
-                // Something changed (E.g. device rotation), but no configuration update is needed.
-                // E.g. changing device rotation by 180 degrees. Go ahead and perform surface
-                // placement to unfreeze the display since we froze it when the rotation was updated
-                // in DisplayContent#updateRotationUnchecked.
-                if (mWaitingForConfig) {
-                    mWaitingForConfig = false;
-                    mWmService.mLastFinishedFreezeSource = "config-unchanged";
-                    setLayoutNeeded();
-                    mWmService.mWindowPlacerLocked.performSurfacePlacement();
-                }
-            }
+        if (!isReady() || mAcitvityDisplay == null) {
+            return;
+        }
+        final boolean configUpdated = mAcitvityDisplay.updateDisplayOverrideConfigurationLocked();
+        if (configUpdated) {
+            return;
+        }
+        // Something changed (E.g. device rotation), but no configuration update is needed.
+        // E.g. changing device rotation by 180 degrees. Go ahead and perform surface placement to
+        // unfreeze the display since we froze it when the rotation was updated in
+        // DisplayContent#updateRotationUnchecked.
+        if (mWaitingForConfig) {
+            mWaitingForConfig = false;
+            mWmService.mLastFinishedFreezeSource = "config-unchanged";
+            setLayoutNeeded();
+            mWmService.mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -1351,7 +1368,7 @@
     boolean updateRotationAndSendNewConfigIfNeeded() {
         final boolean changed = updateRotationUnchecked(false /* forceUpdate */);
         if (changed) {
-            postNewConfigurationToHandler();
+            sendNewConfiguration();
         }
         return changed;
     }
@@ -2292,7 +2309,7 @@
             mInitialDisplayHeight = newHeight;
             mInitialDisplayDensity = newDensity;
             mInitialDisplayCutout = newCutout;
-            mWmService.reconfigureDisplayLocked(this);
+            reconfigureDisplayLocked();
         }
     }
 
@@ -2345,7 +2362,7 @@
         final boolean updateCurrent = userId == UserHandle.USER_CURRENT;
         if (mWmService.mCurrentUserId == userId || updateCurrent) {
             mBaseDisplayDensity = density;
-            mWmService.reconfigureDisplayLocked(this);
+            reconfigureDisplayLocked();
         }
         if (updateCurrent) {
             // We are applying existing settings so no need to save it again.
@@ -2366,7 +2383,7 @@
 
         mDisplayScalingDisabled = (mode != FORCE_SCALING_MODE_AUTO);
         Slog.i(TAG_WM, "Using display scaling mode: " + (mDisplayScalingDisabled ? "off" : "auto"));
-        mWmService.reconfigureDisplayLocked(this);
+        reconfigureDisplayLocked();
 
         mWmService.mDisplayWindowSettings.setForcedScalingMode(this, mode);
     }
@@ -2385,7 +2402,7 @@
 
         Slog.i(TAG_WM, "Using new display size: " + width + "x" + height);
         updateBaseDisplayMetrics(width, height, mBaseDisplayDensity);
-        mWmService.reconfigureDisplayLocked(this);
+        reconfigureDisplayLocked();
 
         if (clear) {
             width = height = 0;
@@ -3730,7 +3747,7 @@
                 if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
                 if (updateOrientationFromAppTokens()) {
                     setLayoutNeeded();
-                    postNewConfigurationToHandler();
+                    sendNewConfiguration();
                 }
             }
 
@@ -5094,7 +5111,7 @@
         if (!mLocationInParentWindow.equals(x, y)) {
             mLocationInParentWindow.set(x, y);
             if (mWmService.mAccessibilityController != null) {
-                mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+                mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(mDisplayId);
             }
             notifyLocationInParentDisplayChanged();
         }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index cf87203..1576873 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -284,6 +284,8 @@
     /** See {@link #getNavigationBarFrameHeight} */
     private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
 
+    private boolean mIsFreeformWindowOverlappingWithNavBar;
+
     /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
     @Px private int mWindowOutsetBottom;
 
@@ -877,27 +879,24 @@
     }
 
     /**
-     * Preflight adding a window to the system.
+     * Check if a window can be added to the system.
      *
-     * Currently enforces that three window types are singletons per display:
+     * Currently enforces that two window types are singletons per display:
      * <ul>
      * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
      * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
      * </ul>
      *
-     * @param win The window to be added
-     * @param attrs Information about the window to be added
+     * @param attrs Information about the window to be added.
      *
      * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
      * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
      */
-    public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
-
+    int validateAddingWindowLw(WindowManager.LayoutParams attrs) {
         if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.STATUS_BAR_SERVICE,
                     "DisplayPolicy");
-            mScreenDecorWindows.add(win);
         }
 
         switch (attrs.type) {
@@ -910,6 +909,42 @@
                         return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
                     }
                 }
+                break;
+            case TYPE_NAVIGATION_BAR:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "DisplayPolicy");
+                if (mNavigationBar != null) {
+                    if (mNavigationBar.isAlive()) {
+                        return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+                    }
+                }
+                break;
+            case TYPE_NAVIGATION_BAR_PANEL:
+            case TYPE_STATUS_BAR_PANEL:
+            case TYPE_STATUS_BAR_SUB_PANEL:
+            case TYPE_VOICE_INTERACTION_STARTING:
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.STATUS_BAR_SERVICE,
+                        "DisplayPolicy");
+                break;
+        }
+        return ADD_OKAY;
+    }
+
+    /**
+     * Called when a window is being added to the system.  Must not throw an exception.
+     *
+     * @param win The window being added.
+     * @param attrs Information about the window to be added.
+     */
+    void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
+        if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
+            mScreenDecorWindows.add(win);
+        }
+
+        switch (attrs.type) {
+            case TYPE_STATUS_BAR:
                 mStatusBar = win;
                 mStatusBarController.setWindow(win);
                 if (mDisplayContent.isDefaultDisplay) {
@@ -925,14 +960,6 @@
                 mDisplayContent.setInsetProvider(TYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
                 break;
             case TYPE_NAVIGATION_BAR:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.STATUS_BAR_SERVICE,
-                        "DisplayPolicy");
-                if (mNavigationBar != null) {
-                    if (mNavigationBar.isAlive()) {
-                        return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
-                    }
-                }
                 mNavigationBar = win;
                 mNavigationBarController.setWindow(win);
                 mNavigationBarController.setOnBarVisibilityChangedListener(
@@ -966,16 +993,7 @@
                         });
                 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
                 break;
-            case TYPE_NAVIGATION_BAR_PANEL:
-            case TYPE_STATUS_BAR_PANEL:
-            case TYPE_STATUS_BAR_SUB_PANEL:
-            case TYPE_VOICE_INTERACTION_STARTING:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.STATUS_BAR_SERVICE,
-                        "DisplayPolicy");
-                break;
         }
-        return ADD_OKAY;
     }
 
     /**
@@ -984,7 +1002,7 @@
      *
      * @param win The window being removed.
      */
-    public void removeWindowLw(WindowState win) {
+    void removeWindowLw(WindowState win) {
         if (mStatusBar == win) {
             mStatusBar = null;
             mStatusBarController.setWindow(null);
@@ -2379,6 +2397,7 @@
         mAllowLockscreenWhenOn = false;
         mShowingDream = false;
         mWindowSleepTokenNeeded = false;
+        mIsFreeformWindowOverlappingWithNavBar = false;
     }
 
     /**
@@ -2478,6 +2497,13 @@
             }
         }
 
+        // Check if the freeform window overlaps with the navigation bar area.
+        final WindowState navBarWin = hasNavigationBar() ? mNavigationBar : null;
+        if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode()
+                && isOverlappingWithNavBar(win, navBarWin)) {
+            mIsFreeformWindowOverlappingWithNavBar = true;
+        }
+
         // Also keep track of any windows that are dimming but not necessarily fullscreen in the
         // docked stack.
         if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
@@ -3458,7 +3484,11 @@
             }
         } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
             if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
-                visibility = setNavBarOpaqueFlag(visibility);
+                if (mIsFreeformWindowOverlappingWithNavBar) {
+                    visibility = setNavBarTranslucentFlag(visibility);
+                } else {
+                    visibility = setNavBarOpaqueFlag(visibility);
+                }
             } else if (fullscreenDrawsBackground) {
                 visibility = setNavBarTransparentFlag(visibility);
             }
@@ -3747,4 +3777,14 @@
         wm.removeView(mPointerLocationView);
         mPointerLocationView = null;
     }
+
+    @VisibleForTesting
+    static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
+        if (navBarWindow == null || !navBarWindow.isVisibleLw()
+                || targetWindow.mAppToken == null || !targetWindow.isVisibleLw()) {
+            return false;
+        }
+
+        return Rect.intersects(targetWindow.getFrameLw(), navBarWindow.getFrameLw());
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index a46fa13..207e8ef 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -30,6 +30,7 @@
 import android.annotation.Nullable;
 import android.app.WindowConfiguration;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.provider.Settings;
 import android.util.AtomicFile;
 import android.util.Slog;
@@ -64,6 +65,11 @@
 class DisplayWindowSettings {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayWindowSettings" : TAG_WM;
 
+    private static final String SYSTEM_DIRECTORY = "system";
+    private static final String DISPLAY_SETTINGS_FILE_NAME = "display_settings.xml";
+    private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/" + DISPLAY_SETTINGS_FILE_NAME;
+    private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
+
     private static final int IDENTIFIER_UNIQUE_ID = 0;
     private static final int IDENTIFIER_PORT = 1;
     @IntDef(prefix = { "IDENTIFIER_" }, value = {
@@ -688,8 +694,26 @@
         private final AtomicFile mAtomicFile;
 
         AtomicFileStorage() {
-            final File folder = new File(Environment.getDataDirectory(), "system");
-            mAtomicFile = new AtomicFile(new File(folder, "display_settings.xml"), "wm-displays");
+            final File folder = new File(Environment.getDataDirectory(), SYSTEM_DIRECTORY);
+            final File settingsFile = new File(folder, DISPLAY_SETTINGS_FILE_NAME);
+            // If display_settings.xml doesn't exist, try to copy the vendor's one instead
+            // in order to provide the vendor specific initialization.
+            if (!settingsFile.exists()) {
+                copyVendorSettings(settingsFile);
+            }
+            mAtomicFile = new AtomicFile(settingsFile, WM_DISPLAY_COMMIT_TAG);
+        }
+
+        private static void copyVendorSettings(File target) {
+            final File vendorFile = new File(Environment.getVendorDirectory(),
+                    VENDOR_DISPLAY_SETTINGS_PATH);
+            if (vendorFile.canRead()) {
+                try {
+                    FileUtils.copy(vendorFile, target);
+                } catch (IOException e) {
+                    Slog.e(TAG, "Failed to copy vendor display_settings.xml");
+                }
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index b16d956..6830ade 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -133,7 +133,10 @@
     @Override
     public void notifyConfigurationChanged() {
         // TODO(multi-display): Notify proper displays that are associated with this input device.
-        mService.mRoot.getDisplayContent(DEFAULT_DISPLAY).sendNewConfiguration();
+
+        synchronized (mService.mGlobalLock) {
+            mService.getDefaultDisplayContentLocked().sendNewConfiguration();
+        }
 
         synchronized (mInputDevicesReadyMonitor) {
             if (!mInputDevicesReady) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index ca4749f..85ba95f 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -43,11 +43,13 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Trace;
+import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.server.am.EventLogTags;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
 
@@ -88,24 +90,11 @@
     }
 
     /**
-     * @return true if either Keyguard or AOD are showing, not going away, and not being occluded
-     *         on the given display, false otherwise.
+     * @return true if either 1) AOD is showing, or 2) Keyguard is showing, not going away, and not
+     *         being occluded on the given display, false otherwise.
      */
     boolean isKeyguardOrAodShowing(int displayId) {
-        return (mKeyguardShowing || mAodShowing) && !mKeyguardGoingAway
-                && !isDisplayOccluded(displayId);
-    }
-
-    /**
-     * @return {@code true} for default display when AOD is showing. Otherwise, same as
-     *         {@link #isKeyguardOrAodShowing(int)}
-     * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic.
-     */
-    boolean isKeyguardUnoccludedOrAodShowing(int displayId) {
-        if (displayId == DEFAULT_DISPLAY && mAodShowing) {
-            return true;
-        }
-        return isKeyguardOrAodShowing(displayId);
+        return mAodShowing || isKeyguardShowing(displayId);
     }
 
     /**
@@ -113,7 +102,7 @@
      *         display, false otherwise
      */
     boolean isKeyguardShowing(int displayId) {
-        return mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId);
+        return mKeyguardShowing && !mKeyguardGoingAway && !isKeyguardOccluded(displayId);
     }
 
     /**
@@ -142,6 +131,11 @@
         if (!keyguardChanged && !aodChanged) {
             return;
         }
+        EventLog.writeEvent(EventLogTags.AM_SET_KEYGUARD_SHOWN,
+                keyguardShowing ? 1 : 0,
+                aodShowing ? 1 : 0,
+                mKeyguardGoingAway ? 1 : 0,
+                "setKeyguardShown");
         mKeyguardShowing = keyguardShowing;
         mAodShowing = aodShowing;
         mWindowManager.setAodShowing(aodShowing);
@@ -178,6 +172,11 @@
         mWindowManager.deferSurfaceLayout();
         try {
             setKeyguardGoingAway(true);
+            EventLog.writeEvent(EventLogTags.AM_SET_KEYGUARD_SHOWN,
+                    1 /* keyguardShowing */,
+                    mAodShowing ? 1 : 0,
+                    1 /* keyguardGoingAway */,
+                    "keyguardGoingAway");
             mRootActivityContainer.getDefaultDisplay().mDisplayContent
                     .prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
                             false /* alwaysKeepCurrent */, convertTransitFlags(flags),
@@ -316,7 +315,7 @@
             return;
         }
 
-        mWindowManager.onKeyguardOccludedChanged(isDisplayOccluded(DEFAULT_DISPLAY));
+        mWindowManager.onKeyguardOccludedChanged(isKeyguardOccluded(DEFAULT_DISPLAY));
         if (isKeyguardLocked()) {
             mWindowManager.deferSurfaceLayout();
             try {
@@ -361,7 +360,7 @@
         }
     }
 
-    private boolean isDisplayOccluded(int displayId) {
+    private boolean isKeyguardOccluded(int displayId) {
         return getDisplay(displayId).mOccluded;
     }
 
@@ -379,13 +378,13 @@
         if (mBeforeUnoccludeTransit != TRANSIT_UNSET
                 && dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
                 // TODO(b/113840485): Handle app transition for individual display.
-                && isDisplayOccluded(DEFAULT_DISPLAY)) {
+                && isKeyguardOccluded(DEFAULT_DISPLAY)) {
 
             // Reuse old transit in case we are occluding Keyguard again, meaning that we never
             // actually occclude/unocclude Keyguard, but just run a normal transition.
             return mBeforeUnoccludeTransit;
             // TODO(b/113840485): Handle app transition for individual display.
-        } else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
+        } else if (!isKeyguardOccluded(DEFAULT_DISPLAY)) {
 
             // Save transit in case we dismiss/occlude Keyguard shortly after.
             mBeforeUnoccludeTransit = dc.mAppTransition.getAppTransition();
@@ -397,7 +396,7 @@
 
     private void dismissDockedStackIfNeeded() {
         // TODO(b/113840485): Handle docked stack for individual display.
-        if (mKeyguardShowing && isDisplayOccluded(DEFAULT_DISPLAY)) {
+        if (mKeyguardShowing && isKeyguardOccluded(DEFAULT_DISPLAY)) {
             // The lock screen is currently showing, but is occluded by a window that can
             // show on top of the lock screen. In this can we want to dismiss the docked
             // stack since it will be complicated/risky to try to put the activity on top
@@ -422,9 +421,9 @@
 
     private void updateKeyguardSleepToken(int displayId) {
         final KeyguardDisplayState state = getDisplay(displayId);
-        if (isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken == null) {
+        if (isKeyguardOrAodShowing(displayId) && state.mSleepToken == null) {
             state.acquiredSleepToken();
-        } else if (!isKeyguardUnoccludedOrAodShowing(displayId) && state.mSleepToken != null) {
+        } else if (!isKeyguardOrAodShowing(displayId) && state.mSleepToken != null) {
             state.releaseSleepToken();
         }
     }
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index af72931..ef0049b 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -350,7 +350,7 @@
             // Calculate the stack bounds in the new orientation to the same same fraction along the
             // rotated movement bounds.
             final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
-                    false /* adjustForIme */, false /* adjustForShelf */);
+                    false /* adjustForIme */);
             mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
                     snapFraction);
             if (mIsMinimized) {
@@ -540,8 +540,7 @@
      */
     private Rect getMovementBounds(Rect stackBounds) {
         synchronized (mService.mGlobalLock) {
-            return getMovementBounds(stackBounds, true /* adjustForIme */,
-                    true /* adjustForShelf */);
+            return getMovementBounds(stackBounds, true /* adjustForIme */);
         }
     }
 
@@ -549,15 +548,16 @@
      * @return the movement bounds for the given {@param stackBounds} and the current state of the
      *         controller.
      */
-    private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme, boolean adjustForShelf) {
+    private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
         synchronized (mService.mGlobalLock) {
             final Rect movementBounds = new Rect();
             getInsetBounds(movementBounds);
 
-            // Apply the movement bounds adjustments based on the current state
+            // Apply the movement bounds adjustments based on the current state.
+            // Note that shelf offset does not affect the movement bounds here
+            // since it's been taken care of in system UI.
             mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
-                    Math.max((adjustForIme && mIsImeShowing) ? mImeHeight : 0,
-                            (adjustForShelf && mIsShelfShowing) ? mShelfHeight : 0));
+                    (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
             return movementBounds;
         }
     }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index bf627ec..0a3e7a4 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -355,7 +355,7 @@
                         // launch-behind state is restored. That also prevents the next transition
                         // type being disturbed if the visibility is updated after setting the next
                         // transition (the target activity will be one of closing apps).
-                        if (!controller.shouldCancelWithDeferredScreenshot()
+                        if (!controller.shouldDeferCancelWithScreenshot()
                                 && !targetStack.isFocusedStackOnDisplay()) {
                             targetStack.ensureActivitiesVisibleLocked(null /* starting */,
                                     0 /* starting */, false /* preserveWindows */);
@@ -415,16 +415,18 @@
         final DisplayContent dc =
                 mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
         dc.mBoundsAnimationController.setAnimationType(
-                controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS);
+                controller.shouldDeferCancelUntilNextTransition() ? FADE_IN : BOUNDS);
 
-        // Cancel running recents animation and screenshot previous task when the next
-        // transition starts in below cases:
-        // 1) The next launching task is not in recents animation task.
+        // We defer canceling the recents animation until the next app transition in the following
+        // cases:
+        // 1) The next launching task is not being animated by the recents animation
         // 2) The next task is home activity. (i.e. pressing home key to back home in recents).
         if ((!controller.isAnimatingTask(stack.getTaskStack().getTopChild())
                 || controller.isTargetApp(stack.getTopActivity().mAppWindowToken))
-                && controller.shouldCancelWithDeferredScreenshot()) {
-            controller.cancelOnNextTransitionStart();
+                && controller.shouldDeferCancelUntilNextTransition()) {
+            // Always prepare an app transition since we rely on the transition callbacks to cleanup
+            mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+            controller.setCancelOnNextTransitionStart();
         } else {
             // Just cancel directly to unleash from launcher when the next launching task is the
             // current top task.
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 163be1e..6ea4d58 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -97,10 +97,9 @@
     private final Runnable mFailsafeRunnable = () ->
             cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
 
-    final Object mLock = new Object();
-
     // The recents component app token that is shown behind the visibile tasks
     private AppWindowToken mTargetAppToken;
+    private DisplayContent mDisplayContent;
     private int mTargetActivityType;
     private Rect mMinimizedHomeBounds = new Rect();
 
@@ -124,25 +123,47 @@
 
     private boolean mLinkedToDeathOfRunner;
 
-    private boolean mCancelWithDeferredScreenshot;
-
+    // Whether to try to defer canceling from a stack order change until the next transition
+    private boolean mRequestDeferCancelUntilNextTransition;
+    // Whether to actually defer canceling until the next transition
     private boolean mCancelOnNextTransitionStart;
+    // Whether to take a screenshot when handling a deferred cancel
+    private boolean mCancelDeferredWithScreenshot;
 
     /**
      * Animates the screenshot of task that used to be controlled by RecentsAnimation.
-     * @see {@link #cancelOnNextTransitionStart}
+     * @see {@link #setCancelOnNextTransitionStart}
      */
     SurfaceAnimator mRecentScreenshotAnimator;
 
+    /**
+     * An app transition listener to cancel the recents animation only after the app transition
+     * starts or is canceled.
+     */
     final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
         @Override
         public int onAppTransitionStartingLocked(int transit, long duration,
                 long statusBarAnimationStartTime, long statusBarAnimationDuration) {
-            onTransitionStart();
-            mService.mRoot.getDisplayContent(mDisplayId).mAppTransition
-                    .unregisterListener(this);
+            continueDeferredCancel();
             return 0;
         }
+
+        @Override
+        public void onAppTransitionCancelledLocked(int transit) {
+            continueDeferredCancel();
+        }
+
+        private void continueDeferredCancel() {
+            mDisplayContent.mAppTransition.unregisterListener(this);
+            if (mCanceled) {
+                return;
+            }
+
+            if (mCancelOnNextTransitionStart) {
+                mCancelOnNextTransitionStart = false;
+                cancelAnimationWithScreenshot(mCancelDeferredWithScreenshot);
+            }
+        }
     };
 
     public interface RecentsAnimationCallbacks {
@@ -202,8 +223,7 @@
                         ? REORDER_MOVE_TO_TOP
                         : REORDER_MOVE_TO_ORIGINAL_POSITION,
                         true /* runSynchronously */, sendUserLeaveHint);
-                final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
-                dc.mBoundsAnimationController.setAnimationType(FADE_IN);
+                mDisplayContent.mBoundsAnimationController.setAnimationType(FADE_IN);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -240,8 +260,7 @@
                     }
 
                     mInputConsumerEnabled = enabled;
-                    final InputMonitor inputMonitor =
-                            mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+                    final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
                     inputMonitor.updateInputWindowsLw(true /*force*/);
                     mService.scheduleAnimationLocked();
                 }
@@ -282,15 +301,23 @@
         }
 
         @Override
+        @Deprecated
         public void setCancelWithDeferredScreenshot(boolean screenshot) {
-            synchronized (mLock) {
-                setCancelWithDeferredScreenshotLocked(screenshot);
+            synchronized (mService.mGlobalLock) {
+                setDeferredCancel(true /* deferred */, screenshot);
+            }
+        }
+
+        @Override
+        public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+            synchronized (mService.mGlobalLock) {
+                setDeferredCancel(defer, screenshot);
             }
         }
 
         @Override
         public void cleanupScreenshot() {
-            synchronized (mLock) {
+            synchronized (mService.mGlobalLock) {
                 if (mRecentScreenshotAnimator != null) {
                     mRecentScreenshotAnimator.cancelAnimation();
                     mRecentScreenshotAnimator = null;
@@ -312,10 +339,7 @@
         mCallbacks = callbacks;
         mDisplayId = displayId;
         mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
-    }
-
-    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
-        initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds);
+        mDisplayContent = service.mRoot.getDisplayContent(displayId);
     }
 
     /**
@@ -323,15 +347,15 @@
      * because it may call cancelAnimation() which needs to properly clean up the controller
      * in the window manager.
      */
-    @VisibleForTesting
-    void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
+    public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
         mTargetActivityType = targetActivityType;
-        dc.mAppTransition.registerListenerLocked(mAppTransitionListener);
+        mDisplayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
 
         // Make leashes for each of the visible/target tasks and add it to the recents animation to
         // be started
-        final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
-        final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
+        final ArrayList<Task> visibleTasks = mDisplayContent.getVisibleTasks();
+        final TaskStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
+                targetActivityType);
         if (targetStack != null) {
             for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
                 final Task t = targetStack.getChildAt(i);
@@ -365,29 +389,31 @@
         }
 
         // Adjust the wallpaper visibility for the showing target activity
-        final AppWindowToken recentsComponentAppToken = dc.getStack(WINDOWING_MODE_UNDEFINED,
-                targetActivityType).getTopChild().getTopFullscreenAppToken();
+        final AppWindowToken recentsComponentAppToken =
+                targetStack.getTopChild().getTopFullscreenAppToken();
         if (recentsComponentAppToken != null) {
             if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
                     + recentsComponentAppToken.getName() + ")");
             mTargetAppToken = recentsComponentAppToken;
             if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
-                dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-                dc.setLayoutNeeded();
+                mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+                mDisplayContent.setLayoutNeeded();
             }
         }
 
         // Save the minimized home height
-        final TaskStack dockedStack = dc.getSplitScreenPrimaryStackIgnoringVisibility();
-        dc.getDockedDividerController().getHomeStackBoundsInDockedMode(
-                dc.getConfiguration(),
+        final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+        mDisplayContent.getDockedDividerController().getHomeStackBoundsInDockedMode(
+                mDisplayContent.getConfiguration(),
                 dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(),
                 mMinimizedHomeBounds);
 
         mService.mWindowPlacerLocked.performSurfacePlacement();
 
         // Notify that the animation has started
-        mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+        if (mStatusBar != null) {
+            mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+        }
     }
 
     @VisibleForTesting
@@ -441,8 +467,7 @@
 
             // Perform layout if it was scheduled before to make sure that we get correct content
             // insets for the target app window after a rotation
-            final DisplayContent displayContent = mService.mRoot.getDisplayContent(mDisplayId);
-            displayContent.performLayout(false /* initial */, false /* updateInputWindows */);
+            mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
 
             final Rect minimizedHomeBounds = mTargetAppToken != null
                     && mTargetAppToken.inSplitScreenSecondaryWindowingMode()
@@ -480,9 +505,8 @@
         cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason);
     }
 
-    void cancelAnimationWithScreenShot() {
-        cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, true /* screenshot */,
-                "stackOrderChanged");
+    void cancelAnimationWithScreenshot(boolean screenshot) {
+        cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, screenshot, "stackOrderChanged");
     }
 
     private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
@@ -496,21 +520,29 @@
             }
             mService.mH.removeCallbacks(mFailsafeRunnable);
             mCanceled = true;
-            try {
-                if (screenshot) {
-                    // Screen shot previous task when next task starts transition.
-                    final Task task = mPendingAnimations.get(0).mTask;
-                    screenshotRecentTask(task, reorderMode, runSynchronously);
+
+            if (screenshot) {
+                // Screen shot previous task when next task starts transition and notify the runner.
+                // We will actually finish the animation once the runner calls cleanUpScreenshot().
+                final Task task = mPendingAnimations.get(0).mTask;
+                screenshotRecentTask(task, reorderMode, runSynchronously);
+                try {
                     mRunner.onAnimationCanceled(true /* deferredWithScreenshot */);
-                    return;
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to cancel recents animation", e);
                 }
-                mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to cancel recents animation", e);
+            } else {
+                // Otherwise, notify the runner and clean up the animation immediately
+                // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
+                // to the runner if we this actually triggers cancel twice on the caller
+                try {
+                    mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to cancel recents animation", e);
+                }
+                mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+                        false /* sendUserLeaveHint */);
             }
-            // Clean up and return to the previous app
-            mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
-                    false /* sendUserLeaveHint */);
         }
     }
 
@@ -523,27 +555,36 @@
      * screenshot, so that Launcher can still control the leash lifecycle & make the next app
      * transition animate smoothly without flickering.
      */
-    void cancelOnNextTransitionStart() {
+    void setCancelOnNextTransitionStart() {
         mCancelOnNextTransitionStart = true;
     }
 
-    void setCancelWithDeferredScreenshotLocked(boolean screenshot) {
-        mCancelWithDeferredScreenshot = screenshot;
+    /**
+     * Requests that we attempt to defer the cancel until the next app transition if we are
+     * canceling from a stack order change.  If {@param screenshot} is specified, then the system
+     * will replace the contents of the leash with a screenshot, which must be cleaned up when the
+     * runner calls cleanUpScreenshot().
+     */
+    void setDeferredCancel(boolean defer, boolean screenshot) {
+        mRequestDeferCancelUntilNextTransition = defer;
+        mCancelDeferredWithScreenshot = screenshot;
     }
 
-    boolean shouldCancelWithDeferredScreenshot() {
-        return mCancelWithDeferredScreenshot;
+    /**
+     * @return Whether we should defer the cancel from a stack order change until the next app
+     * transition.
+     */
+    boolean shouldDeferCancelUntilNextTransition() {
+        return mRequestDeferCancelUntilNextTransition;
     }
 
-    void onTransitionStart() {
-        if (mCanceled) {
-            return;
-        }
-
-        if (mCancelOnNextTransitionStart) {
-            mCancelOnNextTransitionStart = false;
-            cancelAnimationWithScreenShot();
-        }
+    /**
+     * @return Whether we should both defer the cancel from a stack order change until the next
+     * app transition, and also that the deferred cancel should replace the contents of the leash
+     * with a screenshot.
+     */
+    boolean shouldDeferCancelWithScreenshot() {
+        return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
     }
 
     void screenshotRecentTask(Task task, @ReorderMode int reorderMode, boolean runSynchronously) {
@@ -576,6 +617,7 @@
 
         // Clear any pending failsafe runnables
         mService.mH.removeCallbacks(mFailsafeRunnable);
+        mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener);
 
         // Clear references to the runner
         unlinkToDeathOfRunner();
@@ -589,21 +631,22 @@
         }
 
         // Update the input windows after the animation is complete
-        final InputMonitor inputMonitor =
-                mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+        final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
         inputMonitor.updateInputWindowsLw(true /*force*/);
 
         // We have deferred all notifications to the target app as a part of the recents animation,
         // so if we are actually transitioning there, notify again here
         if (mTargetAppToken != null) {
             if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
-                mService.mRoot.getDisplayContent(mDisplayId)
-                        .mAppTransition.notifyAppTransitionFinishedLocked(mTargetAppToken.token);
+                mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
+                        mTargetAppToken.token);
             }
         }
 
         // Notify that the animation has ended
-        mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+        if (mStatusBar != null) {
+            mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+        }
     }
 
     void scheduleFailsafe() {
@@ -630,8 +673,7 @@
 
         synchronized (mService.getWindowManagerLock()) {
             // Clear associated input consumers on runner death
-            final InputMonitor inputMonitor =
-                    mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+            final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
             inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
         }
     }
@@ -827,5 +869,11 @@
         pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
         pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
         pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
+        pw.print(innerPrefix); pw.println("mRequestDeferCancelUntilNextTransition="
+                + mRequestDeferCancelUntilNextTransition);
+        pw.print(innerPrefix); pw.println("mCancelOnNextTransitionStart="
+                + mCancelOnNextTransitionStart);
+        pw.print(innerPrefix); pw.println("mCancelDeferredWithScreenshot="
+                + mCancelDeferredWithScreenshot);
     }
 }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8a5f52f..a00bee0 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -248,8 +248,6 @@
             dc.configureDisplayPolicy();
         }
 
-        mWmService.reconfigureDisplayLocked(dc);
-
         return dc;
     }
 
@@ -267,7 +265,7 @@
             }
 
             displayContent.initializeDisplayOverrideConfiguration();
-            mWmService.reconfigureDisplayLocked(displayContent);
+            displayContent.reconfigureDisplayLocked();
 
             // We need to update global configuration as well if config of default display has
             // changed. Do it inline because ATMS#retrieveSettings() will soon update the
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index dc62877..b94a7dc 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -937,6 +937,7 @@
             }
         }
 
+        t.setEarlyWakeup();
         setSnapshotTransform(t, mSnapshotFinalMatrix, mExitTransformation.getAlpha());
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 7c7fdae..882f411 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -66,6 +66,7 @@
 import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
 import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
 import static com.android.server.am.TaskRecordProto.STACK_ID;
+import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
@@ -1113,16 +1114,14 @@
         return intent != null ? intent : affinityIntent;
     }
 
-    /** Returns the first non-finishing activity from the root. */
+    /** Returns the first non-finishing activity from the bottom. */
     ActivityRecord getRootActivity() {
-        for (int i = 0; i < mActivities.size(); i++) {
-            final ActivityRecord r = mActivities.get(i);
-            if (r.finishing) {
-                continue;
-            }
-            return r;
+        final int rootActivityIndex = findRootIndex(false /* effectiveRoot */);
+        if (rootActivityIndex == -1) {
+            // There are no non-finishing activities in the task.
+            return null;
         }
-        return null;
+        return mActivities.get(rootActivityIndex);
     }
 
     ActivityRecord getTopActivity() {
@@ -1237,27 +1236,6 @@
                 || topRunningActivityLocked() != null;
     }
 
-    /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
-    final void setFrontOfTask() {
-        boolean foundFront = false;
-        final int numActivities = mActivities.size();
-        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
-            final ActivityRecord r = mActivities.get(activityNdx);
-            if (foundFront || r.finishing) {
-                r.frontOfTask = false;
-            } else {
-                r.frontOfTask = true;
-                // Set frontOfTask false for every following activity.
-                foundFront = true;
-            }
-        }
-        if (!foundFront && numActivities > 0) {
-            // All activities of this task are finishing. As we ought to have a frontOfTask
-            // activity, make the bottom activity front.
-            mActivities.get(0).frontOfTask = true;
-        }
-    }
-
     /**
      * Reorder the history stack so that the passed activity is brought to the front.
      */
@@ -1272,8 +1250,6 @@
         // Make sure window manager is aware of the position change.
         mTask.positionChildAtTop(newTop.mAppWindowToken);
         updateEffectiveIntent();
-
-        setFrontOfTask();
     }
 
     void addActivityToTop(ActivityRecord r) {
@@ -1443,8 +1419,8 @@
                 mActivities.remove(activityNdx);
                 --activityNdx;
                 --numActivities;
-            } else if (mStack.finishActivityLocked(r, Activity.RESULT_CANCELED, null,
-                    reason, false, pauseImmediately)) {
+            } else if (r.finishActivityLocked(Activity.RESULT_CANCELED, null,
+                    reason, false /* oomAdj */, pauseImmediately) == FINISH_RESULT_REMOVED) {
                 --activityNdx;
                 --numActivities;
             }
@@ -1498,8 +1474,8 @@
                     if (opts != null) {
                         ret.updateOptionsLocked(opts);
                     }
-                    if (mStack != null && mStack.finishActivityLocked(
-                            r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
+                    if (r.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                            "clear-task-stack", false /* oomAdj */) == FINISH_RESULT_REMOVED) {
                         --activityNdx;
                         --numActivities;
                     }
@@ -1512,10 +1488,8 @@
                         && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
                         && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
                     if (!ret.finishing) {
-                        if (mStack != null) {
-                            mStack.finishActivityLocked(
-                                    ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
-                        }
+                        ret.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                                "clear-task-top", false /* oomAdj */);
                         return null;
                     }
                 }
@@ -1658,6 +1632,7 @@
 
     /** Updates the last task description values. */
     void updateTaskDescription() {
+        // TODO(AM refactor): Cleanup to use findRootIndex()
         // Traverse upwards looking for any break between main task activities and
         // utility activities.
         int activityNdx;
@@ -1736,8 +1711,19 @@
         }
     }
 
-    int findEffectiveRootIndex() {
-        int effectiveNdx = 0;
+    /**
+     * Find the index of the root activity in the task. It will be the first activity from the
+     * bottom that is not finishing.
+     *
+     * @param effectiveRoot Flag indicating whether 'effective root' should be returned - an
+     *                      activity that defines the task identity (its base intent). It's the
+     *                      first one that does not have
+     *                      {@link ActivityInfo#FLAG_RELINQUISH_TASK_IDENTITY}.
+     * @return index of the 'root' or 'effective' root in the list of activities, -1 if no eligible
+     *         activity was found.
+     */
+    int findRootIndex(boolean effectiveRoot) {
+        int effectiveNdx = -1;
         final int topActivityNdx = mActivities.size() - 1;
         for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
             final ActivityRecord r = mActivities.get(activityNdx);
@@ -1745,15 +1731,22 @@
                 continue;
             }
             effectiveNdx = activityNdx;
-            if ((r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+            if (!effectiveRoot || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
                 break;
             }
         }
         return effectiveNdx;
     }
 
+    // TODO (AM refactor): Invoke automatically when there is a change in children
+    @VisibleForTesting
     void updateEffectiveIntent() {
-        final int effectiveRootIndex = findEffectiveRootIndex();
+        int effectiveRootIndex = findRootIndex(true /* effectiveRoot */);
+        if (effectiveRootIndex == -1) {
+            // All activities in the task are either finishing or relinquish task identity.
+            // But we still want to update the intent, so let's use the bottom activity.
+            effectiveRootIndex = 0;
+        }
         final ActivityRecord r = mActivities.get(effectiveRootIndex);
         setIntent(r);
 
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index 1a57168..143543e 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -28,7 +28,7 @@
  * Class used by {@link RecentsAnimationController} to create a surface control with taking
  * screenshot of task when canceling recents animation.
  *
- * @see {@link RecentsAnimationController#cancelOnNextTransitionStart}
+ * @see {@link RecentsAnimationController#setCancelOnNextTransitionStart}
  */
 class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
     private static final String TAG = "TaskScreenshotAnim";
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index bd114d9..f9a6fe7 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -310,6 +310,7 @@
         }
         final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
         return new TaskSnapshot(
+                System.currentTimeMillis() /* id */,
                 appWindowToken.mActivityComponent, screenshotBuffer.getGraphicBuffer(),
                 screenshotBuffer.getColorSpace(),
                 appWindowToken.getTask().getConfiguration().orientation,
@@ -404,7 +405,9 @@
 
         // Note, the app theme snapshot is never translucent because we enforce a non-translucent
         // color above
-        return new TaskSnapshot(topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(),
+        return new TaskSnapshot(
+                System.currentTimeMillis() /* id */,
+                topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(),
                 hwBitmap.getColorSpace(), topChild.getTask().getConfiguration().orientation,
                 getInsets(mainWindow), ActivityManager.isLowRamDeviceStatic() /* reduced */,
                 mFullSnapshotScale, false /* isRealSnapshot */, task.getWindowingMode(),
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index fcd97c1..696e1c3 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -92,7 +92,7 @@
             // For legacy snapshots, restore the scale based on the reduced resolution state
             final float legacyScale = reducedResolution ? mPersister.getReducedScale() : 1f;
             final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale;
-            return new TaskSnapshot(topActivityComponent, buffer, bitmap.getColorSpace(),
+            return new TaskSnapshot(proto.id, topActivityComponent, buffer, bitmap.getColorSpace(),
                     proto.orientation,
                     new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
                     reducedResolution, scale, proto.isRealSnapshot, proto.windowingMode,
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 72fc189..32a1d90 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -343,6 +343,7 @@
             proto.isTranslucent = mSnapshot.isTranslucent();
             proto.topActivityComponent = mSnapshot.getTopActivityComponent().flattenToString();
             proto.scale = mSnapshot.getScale();
+            proto.id = mSnapshot.getId();
             final byte[] bytes = TaskSnapshotProto.toByteArray(proto);
             final File file = getProtoFile(mTaskId, mUserId);
             final AtomicFile atomicFile = new AtomicFile(file);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index eb45e73..79367a0 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -321,7 +321,9 @@
      */
     private void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds,
             boolean toFullscreen) {
-        mBoundsAnimatingRequested = true;
+        if (mAnimationType == BoundsAnimationController.BOUNDS) {
+            mBoundsAnimatingRequested = true;
+        }
         mBoundsAnimatingToFullscreen = toFullscreen;
         if (destBounds != null) {
             mBoundsAnimationTarget.set(destBounds);
@@ -1586,8 +1588,10 @@
                 return false;
             }
 
-            mBoundsAnimatingRequested = false;
-            mBoundsAnimating = true;
+            if (animationType == BoundsAnimationController.BOUNDS) {
+                mBoundsAnimatingRequested = false;
+                mBoundsAnimating = true;
+            }
             mAnimationType = animationType;
 
             // If we are changing UI mode, as in the PiP to fullscreen
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 6910ce9..05cfbd4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -263,11 +263,13 @@
 
     /**
      * Sets a callback for observing which windows are touchable for the purposes
-     * of accessibility.
+     * of accessibility on specified display.
      *
+     * @param displayId The logical display id.
      * @param callback The callback.
+     * @return {@code false} if display id is not valid.
      */
-    public abstract void setWindowsForAccessibilityCallback(
+    public abstract boolean setWindowsForAccessibilityCallback(int displayId,
             WindowsForAccessibilityCallback callback);
 
     /**
@@ -418,9 +420,11 @@
     public abstract boolean isStackVisibleLw(int windowingMode);
 
     /**
-     * Requests the window manager to resend the windows for accessibility.
+     * Requests the window manager to resend the windows for accessibility on specified display.
+     *
+     * @param displayId Display ID to be computed its windows for accessibility
      */
-    public abstract void computeWindowsForAccessibility();
+    public abstract void computeWindowsForAccessibility(int displayId);
 
     /**
      * Called after virtual display Id is updated by
@@ -507,4 +511,9 @@
      */
     public abstract void removeNonHighRefreshRatePackage(@NonNull String packageName);
 
+    /**
+     * Checks if this display is touchable.
+     */
+    public abstract boolean isTouchableDisplay(int displayId);
+
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f52bde9..fbdc54a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -79,7 +79,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
@@ -1432,7 +1431,7 @@
                     Binder.getCallingUid());
             win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
 
-            res = displayPolicy.prepareAddWindowLw(win, attrs);
+            res = displayPolicy.validateAddingWindowLw(attrs);
             if (res != WindowManagerGlobal.ADD_OKAY) {
                 return res;
             }
@@ -1508,6 +1507,7 @@
             boolean imMayMove = true;
 
             win.mToken.addWindow(win);
+            displayPolicy.addWindowLw(win, attrs);
             if (type == TYPE_INPUT_METHOD) {
                 displayContent.setInputMethodWindowLocked(win);
                 imMayMove = false;
@@ -1651,6 +1651,7 @@
 
             if (display != null) {
                 displayContent = mRoot.createDisplayContent(display, null /* activityDisplay */);
+                displayContent.reconfigureDisplayLocked();
             }
         }
 
@@ -1911,10 +1912,9 @@
                     mWindowPlacerLocked.performSurfacePlacement();
 
                     // We need to report touchable region changes to accessibility.
-                    if (mAccessibilityController != null
-                            && (w.getDisplayContent().getDisplayId() == DEFAULT_DISPLAY
-                                    || w.getDisplayContent().getParentWindow() != null)) {
-                        mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+                    if (mAccessibilityController != null) {
+                        mAccessibilityController.onSomeWindowResizedOrMovedLocked(
+                                w.getDisplayContent().getDisplayId());
                     }
                 }
             }
@@ -2044,11 +2044,10 @@
                     win.mAppToken.checkKeyguardFlagsChanged();
                 }
                 if (((attrChanges & LayoutParams.ACCESSIBILITY_TITLE_CHANGED) != 0)
-                        && (mAccessibilityController != null)
-                        && (win.getDisplayId() == DEFAULT_DISPLAY
-                                || win.getDisplayContent().getParentWindow() != null)) {
+                        && (mAccessibilityController != null)) {
                     // No move or resize, but the controller checks for title changes as well
-                    mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+                    mAccessibilityController.onSomeWindowResizedOrMovedLocked(
+                            win.getDisplayContent().getDisplayId());
                 }
 
                 if ((flagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
@@ -3751,7 +3750,7 @@
                         layoutNeeded = true;
                     }
                     if (rotationChanged || alwaysSendConfiguration) {
-                        displayContent.postNewConfigurationToHandler();
+                        displayContent.sendNewConfiguration();
                     }
                 }
 
@@ -4421,7 +4420,7 @@
             mDisplayReady = true;
             // Reconfigure all displays to make sure that forced properties and
             // DisplayWindowSettings are applied.
-            mRoot.forAllDisplays(this::reconfigureDisplayLocked);
+            mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
             mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
                     PackageManager.FEATURE_TOUCHSCREEN);
         }
@@ -4500,7 +4499,6 @@
         public static final int FORCE_GC = 15;
         public static final int ENABLE_SCREEN = 16;
         public static final int APP_FREEZE_TIMEOUT = 17;
-        public static final int SEND_NEW_CONFIGURATION = 18;
         public static final int REPORT_WINDOWS_CHANGE = 19;
 
         public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
@@ -4555,11 +4553,7 @@
                     AccessibilityController accessibilityController = null;
 
                     synchronized (mGlobalLock) {
-                        // TODO(multidisplay): Accessibility supported only of default display and
-                        // embedded displays.
-                        if (mAccessibilityController != null
-                                && (displayContent.isDefaultDisplay
-                                || displayContent.getParentWindow() != null)) {
+                        if (mAccessibilityController != null) {
                             accessibilityController = mAccessibilityController;
                         }
 
@@ -4582,7 +4576,8 @@
                     // First notify the accessibility manager for the change so it has
                     // the windows before the newly focused one starts firing eventgs.
                     if (accessibilityController != null) {
-                        accessibilityController.onWindowFocusChangedNotLocked();
+                        accessibilityController.onWindowFocusChangedNotLocked(
+                                displayContent.getDisplayId());
                     }
 
                     if (newFocus != null) {
@@ -4712,23 +4707,6 @@
                     break;
                 }
 
-                case SEND_NEW_CONFIGURATION: {
-                    final DisplayContent displayContent = (DisplayContent) msg.obj;
-                    removeMessages(SEND_NEW_CONFIGURATION, displayContent);
-                    if (displayContent.isReady()) {
-                        displayContent.sendNewConfiguration();
-                    } else {
-                        // Message could come after display has already been removed.
-                        if (DEBUG_CONFIGURATION) {
-                            final String reason = displayContent.getParent() == null
-                                    ? "detached" : "unready";
-                            Slog.w(TAG, "Trying to send configuration to " + reason + " display="
-                                    + displayContent);
-                        }
-                    }
-                    break;
-                }
-
                 case REPORT_WINDOWS_CHANGE: {
                     if (mWindowsChanged) {
                         synchronized (mGlobalLock) {
@@ -5183,29 +5161,6 @@
         return 0;
     }
 
-    void reconfigureDisplayLocked(@NonNull DisplayContent displayContent) {
-        if (!displayContent.isReady()) {
-            return;
-        }
-        displayContent.configureDisplayPolicy();
-        displayContent.setLayoutNeeded();
-
-        boolean configChanged = displayContent.updateOrientationFromAppTokens();
-        final Configuration currentDisplayConfig = displayContent.getConfiguration();
-        mTempConfiguration.setTo(currentDisplayConfig);
-        displayContent.computeScreenConfiguration(mTempConfiguration);
-        configChanged |= currentDisplayConfig.diff(mTempConfiguration) != 0;
-
-        if (configChanged) {
-            displayContent.mWaitingForConfig = true;
-            startFreezingDisplayLocked(0 /* exitAnim */,
-                    0 /* enterAnim */, displayContent);
-            displayContent.postNewConfigurationToHandler();
-        }
-
-        mWindowPlacerLocked.performSurfacePlacement();
-    }
-
     @Override
     public void setOverscan(int displayId, int left, int top, int right, int bottom) {
         if (mContext.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS)
@@ -5235,7 +5190,7 @@
 
         mDisplayWindowSettings.setOverscanLocked(displayInfo, left, top, right, bottom);
 
-        reconfigureDisplayLocked(displayContent);
+        displayContent.reconfigureDisplayLocked();
     }
 
     @Override
@@ -5547,7 +5502,7 @@
         }
 
         if (configChanged) {
-            displayContent.postNewConfigurationToHandler();
+            displayContent.sendNewConfiguration();
         }
         mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN);
     }
@@ -6757,6 +6712,12 @@
                     return;
                 }
                 getDisplayContentOrCreate(displayId, null).reparentDisplayContent(win, sc);
+                // Notifies AccessibilityController to re-compute the window observer of
+                // this embedded display
+                if (mAccessibilityController != null) {
+                    mAccessibilityController.handleWindowObserverOfEmbeddedDisplayLocked(displayId,
+                            win);
+                }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -6863,12 +6824,11 @@
             int lastWindowingMode = displayContent.getWindowingMode();
             mDisplayWindowSettings.setWindowingModeLocked(displayContent, mode);
 
-            reconfigureDisplayLocked(displayContent);
+            displayContent.reconfigureDisplayLocked();
 
             if (lastWindowingMode != displayContent.getWindowingMode()) {
                 // reconfigure won't detect this change in isolation because the windowing mode is
                 // already set on the display, so fire off a new config now.
-                mH.removeMessages(H.SEND_NEW_CONFIGURATION);
 
                 final long origId = Binder.clearCallingIdentity();
                 try {
@@ -6916,7 +6876,7 @@
 
             mDisplayWindowSettings.setRemoveContentModeLocked(displayContent, mode);
 
-            reconfigureDisplayLocked(displayContent);
+            displayContent.reconfigureDisplayLocked();
         }
     }
 
@@ -6955,7 +6915,7 @@
             mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(displayContent,
                     shouldShow);
 
-            reconfigureDisplayLocked(displayContent);
+            displayContent.reconfigureDisplayLocked();
         }
     }
 
@@ -6999,7 +6959,7 @@
 
             mDisplayWindowSettings.setShouldShowSystemDecorsLocked(displayContent, shouldShow);
 
-            reconfigureDisplayLocked(displayContent);
+            displayContent.reconfigureDisplayLocked();
         }
     }
 
@@ -7044,7 +7004,7 @@
 
             mDisplayWindowSettings.setShouldShowImeLocked(displayContent, shouldShow);
 
-            reconfigureDisplayLocked(displayContent);
+            displayContent.reconfigureDisplayLocked();
         }
     }
 
@@ -7168,16 +7128,20 @@
         }
 
         @Override
-        public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
+        public boolean setWindowsForAccessibilityCallback(int displayId,
+                WindowsForAccessibilityCallback callback) {
             synchronized (mGlobalLock) {
                 if (mAccessibilityController == null) {
                     mAccessibilityController = new AccessibilityController(
                             WindowManagerService.this);
                 }
-                mAccessibilityController.setWindowsForAccessibilityCallback(callback);
+                final boolean result =
+                        mAccessibilityController.setWindowsForAccessibilityCallbackLocked(
+                        displayId, callback);
                 if (!mAccessibilityController.hasCallbacksLocked()) {
                     mAccessibilityController = null;
                 }
+                return result;
             }
         }
 
@@ -7343,13 +7307,13 @@
         }
 
         @Override
-        public void computeWindowsForAccessibility() {
+        public void computeWindowsForAccessibility(int displayId) {
             final AccessibilityController accessibilityController;
             synchronized (mGlobalLock) {
                 accessibilityController = mAccessibilityController;
             }
             if (accessibilityController != null) {
-                accessibilityController.performComputeChangedWindowsNotLocked(true);
+                accessibilityController.performComputeChangedWindowsNotLocked(displayId, true);
             }
         }
 
@@ -7491,6 +7455,17 @@
                         .removeNonHighRefreshRatePackage(packageName));
             }
         }
+
+        @Override
+        public boolean isTouchableDisplay(int displayId) {
+            synchronized (mGlobalLock) {
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+                final Configuration configuration =
+                        displayContent != null ? displayContent.getConfiguration() : null;
+                return configuration != null
+                        && configuration.touchscreen == Configuration.TOUCHSCREEN_FINGER;
+            }
+        }
     }
 
     void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 932e44e..f74e2c0 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -629,8 +629,8 @@
         for (int i = 0; i < activities.size(); i++) {
             final ActivityRecord r = activities.get(i);
             if (!r.finishing && r.isInStackLocked()) {
-                r.getActivityStack().finishActivityLocked(r, Activity.RESULT_CANCELED,
-                        null, "finish-heavy", true);
+                r.finishActivityLocked(Activity.RESULT_CANCELED, null /* resultData */,
+                        "finish-heavy", true /* oomAdj */);
             }
         }
     }
@@ -734,7 +734,7 @@
             }
             // Don't consider any activities that are currently not in a state where they
             // can be destroyed.
-            if (r.visible || !r.stopped || !r.haveState
+            if (r.visible || !r.stopped || !r.hasSavedState()
                     || r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING)) {
                 if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
                 continue;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8b1baeb..9f9ef24 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -22,7 +22,6 @@
 import static android.app.AppOpsManager.OP_NONE;
 import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.SurfaceControl.Transaction;
 import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
 import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
@@ -1633,7 +1632,7 @@
                 || !mRelayoutCalled
                 || (atoken == null && mToken.isHidden())
                 || (atoken != null && atoken.hiddenRequested)
-                || isParentWindowHidden()
+                || isParentWindowGoneForLayout()
                 || (mAnimatingExit && !isAnimatingLw())
                 || mDestroying;
     }
@@ -1802,11 +1801,8 @@
             startMoveAnimation(left, top);
         }
 
-        // TODO (multidisplay): Accessibility supported only for the default display and
-        // embedded displays
-        if (mWmService.mAccessibilityController != null && (getDisplayId() == DEFAULT_DISPLAY
-                || getDisplayContent().getParentWindow() != null)) {
-            mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+        if (mWmService.mAccessibilityController != null) {
+            mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(getDisplayId());
         }
         updateLocationInParentDisplayIfNeeded();
 
@@ -2063,7 +2059,7 @@
             if (wasVisible) {
                 final DisplayContent displayContent = getDisplayContent();
                 if (displayContent.updateOrientationFromAppTokens()) {
-                    displayContent.postNewConfigurationToHandler();
+                    displayContent.sendNewConfiguration();
                 }
             }
             mWmService.updateFocusedWindowLocked(isFocused()
@@ -2393,10 +2389,11 @@
 
     void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
         // We need to turn on screen regardless of visibility.
-        boolean hasTurnScreenOnFlag = (mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0;
+        final boolean hasTurnScreenOnFlag = (mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0
+                || (mAppToken != null && mAppToken.mActivityRecord.canTurnScreenOn());
 
         // The screen will turn on if the following conditions are met
-        // 1. The window has the flag FLAG_TURN_SCREEN_ON
+        // 1. The window has the flag FLAG_TURN_SCREEN_ON or ActivityRecord#canTurnScreenOn.
         // 2. The WMS allows theater mode.
         // 3. No AWT or the AWT allows the screen to be turned on. This should only be true once
         // per resume to prevent the screen getting getting turned on for each relayout. Set
@@ -2410,7 +2407,7 @@
             boolean allowTheaterMode = mWmService.mAllowTheaterModeWakeFromLayout
                     || Settings.Global.getInt(mWmService.mContext.getContentResolver(),
                             Settings.Global.THEATER_MODE_ON, 0) == 0;
-            boolean canTurnScreenOn = mAppToken == null || mAppToken.canTurnScreenOn();
+            boolean canTurnScreenOn = mAppToken == null || mAppToken.currentLaunchCanTurnScreenOn();
 
             if (allowTheaterMode && canTurnScreenOn && !mPowerManagerWrapper.isInteractive()) {
                 if (DEBUG_VISIBILITY || DEBUG_POWER) {
@@ -2421,7 +2418,7 @@
             }
 
             if (mAppToken != null) {
-                mAppToken.setCanTurnScreenOn(false);
+                mAppToken.setCurrentLaunchCanTurnScreenOn(false);
             }
         }
 
@@ -3195,12 +3192,9 @@
                         outsets, reportDraw, mergedConfiguration, reportOrientation, displayId,
                         displayCutout);
             }
-
-            // TODO (multidisplay): Accessibility supported only for the default display and
-            // embedded displays
-            if (mWmService.mAccessibilityController != null && (getDisplayId() == DEFAULT_DISPLAY
-                    || getDisplayContent().getParentWindow() != null)) {
-                mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+            if (mWmService.mAccessibilityController != null) {
+                mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(
+                        getDisplayId());
             }
             updateLocationInParentDisplayIfNeeded();
 
@@ -3847,6 +3841,11 @@
         return parent != null && parent.mHidden;
     }
 
+    private boolean isParentWindowGoneForLayout() {
+        final WindowState parent = getParentWindow();
+        return parent != null && parent.isGoneForLayoutLw();
+    }
+
     void setWillReplaceWindow(boolean animate) {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final WindowState c = mChildren.get(i);
@@ -4295,12 +4294,8 @@
         if (isSelfAnimating()) {
             return;
         }
-
-        // TODO (multidisplay): Accessibility supported only for the default display and
-        // embedded displays
-        if (mWmService.mAccessibilityController != null && (getDisplayId() == DEFAULT_DISPLAY
-                || getDisplayContent().getParentWindow() != null)) {
-            mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+        if (mWmService.mAccessibilityController != null) {
+            mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(getDisplayId());
         }
 
         if (!isSelfOrAncestorWindowAnimatingExit()) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 73344ac..41840a4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -729,12 +729,7 @@
             if (!mService.mLimitedAlphaCompositing
                     || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
                     || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)))) {
-                //Slog.i(TAG_WM, "Applying alpha transform");
-                if (screenAnimation) {
-                    mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
-                }
-            } else {
-                //Slog.i(TAG_WM, "Not applying alpha transform");
+                mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
             }
 
             if ((DEBUG_ANIM || WindowManagerService.localLOGV)
@@ -1299,7 +1294,7 @@
                     mSurfaceController.mSurfaceControl);
         }
 
-        mPostDrawTransaction.apply();
+        SurfaceControl.mergeToGlobalTransaction(mPostDrawTransaction);
         return true;
     }
 
@@ -1508,6 +1503,12 @@
     }
 
     void detachChildren() {
+
+        // Do not detach children of starting windows, as their lifecycle is well under control and
+        // it may lead to issues in case we relaunch when we just added the starting window.
+        if (mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
+            return;
+        }
         if (mSurfaceController != null) {
             mSurfaceController.detachChildren();
         }
diff --git a/services/core/java/com/android/server/wm/utils/RegionUtils.java b/services/core/java/com/android/server/wm/utils/RegionUtils.java
index b1b3070..ce7776f 100644
--- a/services/core/java/com/android/server/wm/utils/RegionUtils.java
+++ b/services/core/java/com/android/server/wm/utils/RegionUtils.java
@@ -50,6 +50,20 @@
     /**
      * Applies actions on each rect contained within a {@code Region}.
      *
+     * @param region the given region.
+     * @param rectConsumer the action holder.
+     */
+    public static void forEachRect(Region region, Consumer<Rect> rectConsumer) {
+        final RegionIterator it = new RegionIterator(region);
+        final Rect rect = new Rect();
+        while (it.next(rect)) {
+            rectConsumer.accept(rect);
+        }
+    }
+
+    /**
+     * Applies actions on each rect contained within a {@code Region}.
+     *
      * Order is bottom to top, then right to left.
      *
      * @param region the given region.
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index fb3076b..466ca93 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -41,7 +41,6 @@
 #include <utils/Looper.h>
 #include <utils/threads.h>
 #include <utils/Trace.h>
-#include <utils/SortedVector.h>
 
 #include <binder/IServiceManager.h>
 
@@ -307,7 +306,7 @@
         wp<PointerController> pointerController;
 
         // Input devices to be disabled
-        SortedVector<int32_t> disabledInputDevices;
+        std::set<int32_t> disabledInputDevices;
 
         // Associated Pointer controller display.
         int32_t pointerDisplayId;
@@ -826,18 +825,19 @@
         }
     }
 
-    uint32_t changes = 0;
+    bool pointerGesturesEnabledChanged = false;
     { // acquire lock
         AutoMutex _l(mLock);
 
         if (mLocked.pointerGesturesEnabled != newPointerGesturesEnabled) {
             mLocked.pointerGesturesEnabled = newPointerGesturesEnabled;
-            changes |= InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT;
+            pointerGesturesEnabledChanged = true;
         }
     } // release lock
 
-    if (changes) {
-        mInputManager->getReader()->requestRefreshConfiguration(changes);
+    if (pointerGesturesEnabledChanged) {
+        mInputManager->getReader()->requestRefreshConfiguration(
+                InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT);
     }
 }
 
@@ -897,13 +897,13 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
-        ssize_t index = mLocked.disabledInputDevices.indexOf(deviceId);
-        bool currentlyEnabled = index < 0;
+        auto it = mLocked.disabledInputDevices.find(deviceId);
+        bool currentlyEnabled = it == mLocked.disabledInputDevices.end();
         if (!enabled && currentlyEnabled) {
-            mLocked.disabledInputDevices.add(deviceId);
+            mLocked.disabledInputDevices.insert(deviceId);
         }
         if (enabled && !currentlyEnabled) {
-            mLocked.disabledInputDevices.remove(deviceId);
+            mLocked.disabledInputDevices.erase(deviceId);
         }
     } // release lock
 
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index 98e4343..8b2cbbd 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -4,3 +4,11 @@
     api_dir: "schema",
     package_name: "com.android.server.pm.permission.configfile",
 }
+
+
+xsd_config {
+    name: "platform-compat-config",
+    srcs: ["platform-compat-config.xsd"],
+    api_dir: "platform-compat-schema",
+    package_name: "com.android.server.compat.config",
+}
diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat-config.xsd
new file mode 100644
index 0000000..ee39e50
--- /dev/null
+++ b/services/core/xsd/platform-compat-config.xsd
@@ -0,0 +1,51 @@
+<?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.
+  -->
+
+<!-- This defines the format of the XML file generated by
+  ~ com.android.compat.annotation.ChangeIdProcessor annotation processor (from
+  ~ tools/platform-compat), and is parsed in com/android/server/compat/CompatConfig.java.
+-->
+<xs:schema version="2.0" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+    <xs:complexType name="change">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute type="xs:long" name="id" use="required"/>
+                <xs:attribute type="xs:string" name="name" use="required"/>
+                <xs:attribute type="xs:boolean" name="disabled"/>
+                <xs:attribute type="xs:int" name="enableAfterTargetSdk"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:element name="config">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="compat-change" type="change" maxOccurs="unbounded"
+                            minOccurs="0"/>
+            </xs:sequence>
+        </xs:complexType>
+        <xs:unique name="UniqueId">
+            <xs:selector xpath="compat-change" />
+            <xs:field xpath="@id" />
+        </xs:unique>
+    </xs:element>
+</xs:schema>
+
+
+
+
diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat-schema/current.txt
new file mode 100644
index 0000000..8456785
--- /dev/null
+++ b/services/core/xsd/platform-compat-schema/current.txt
@@ -0,0 +1,31 @@
+// Signature format: 2.0
+package com.android.server.compat.config {
+
+  public class Change {
+    ctor public Change();
+    method public boolean getDisabled();
+    method public int getEnableAfterTargetSdk();
+    method public long getId();
+    method public String getName();
+    method public String getValue();
+    method public void setDisabled(boolean);
+    method public void setEnableAfterTargetSdk(int);
+    method public void setId(long);
+    method public void setName(String);
+    method public void setValue(String);
+  }
+
+  public class Config {
+    ctor public Config();
+    method public java.util.List<com.android.server.compat.config.Change> getCompatChange();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static com.android.server.compat.config.Config read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/services/core/xsd/platform-compat-schema/last_current.txt b/services/core/xsd/platform-compat-schema/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/core/xsd/platform-compat-schema/last_current.txt
diff --git a/services/core/xsd/platform-compat-schema/last_removed.txt b/services/core/xsd/platform-compat-schema/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/core/xsd/platform-compat-schema/last_removed.txt
diff --git a/services/core/xsd/platform-compat-schema/removed.txt b/services/core/xsd/platform-compat-schema/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/core/xsd/platform-compat-schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index de8612a..68c9bad 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -196,6 +196,7 @@
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.os.storage.StorageManager;
+import android.permission.IPermissionManager;
 import android.permission.PermissionControllerManager;
 import android.provider.CalendarContract;
 import android.provider.ContactsContract.QuickContact;
@@ -492,6 +493,7 @@
     final Context mContext;
     final Injector mInjector;
     final IPackageManager mIPackageManager;
+    final IPermissionManager mIPermissionManager;
     final UserManager mUserManager;
     final UserManagerInternal mUserManagerInternal;
     final UsageStatsManagerInternal mUsageStatsManagerInternal;
@@ -1974,6 +1976,10 @@
             return AppGlobals.getPackageManager();
         }
 
+        IPermissionManager getIPermissionManager() {
+            return AppGlobals.getPermissionManager();
+        }
+
         IBackupManager getIBackupManager() {
             return IBackupManager.Stub.asInterface(
                     ServiceManager.getService(Context.BACKUP_SERVICE));
@@ -2217,6 +2223,7 @@
         mUsageStatsManagerInternal = Preconditions.checkNotNull(
                 injector.getUsageStatsManagerInternal());
         mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
+        mIPermissionManager = Preconditions.checkNotNull(injector.getIPermissionManager());
         mTelephonyManager = Preconditions.checkNotNull(injector.getTelephonyManager());
 
         mLocalService = new LocalService();
@@ -8217,7 +8224,7 @@
         saveSettingsLocked(userId);
 
         try {
-            mIPackageManager.updatePermissionFlagsForAllApps(
+            mIPermissionManager.updatePermissionFlagsForAllApps(
                     PackageManager.FLAG_PERMISSION_POLICY_FIXED,
                     0  /* flagValues */, userId);
             pushUserRestrictions(userId);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a04875f..9fe44dc 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -87,6 +87,7 @@
 import com.android.server.broadcastradio.BroadcastRadioService;
 import com.android.server.camera.CameraServiceProxy;
 import com.android.server.clipboard.ClipboardService;
+import com.android.server.compat.PlatformCompat;
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.contentcapture.ContentCaptureManagerInternal;
 import com.android.server.coverage.CoverageService;
@@ -1098,6 +1099,11 @@
             t.traceBegin("SignedConfigService");
             SignedConfigService.registerUpdateReceiver(mSystemContext);
             t.traceEnd();
+
+            t.traceBegin("PlatformCompat");
+            ServiceManager.addService("platform_compat", new PlatformCompat(context));
+            t.traceEnd();
+
         } catch (RuntimeException e) {
             Slog.e("System", "******************************************");
             Slog.e("System", "************ Failure starting core service", e);
diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp
new file mode 100644
index 0000000..3ce514a
--- /dev/null
+++ b/services/robotests/Android.bp
@@ -0,0 +1,53 @@
+// 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.
+
+//##################################################################
+// FrameworksServicesLib app just for Robolectric test target      #
+//##################################################################
+
+android_app {
+    name: "FrameworksServicesLib",
+    platform_apis: true,
+
+    privileged: true,
+
+    static_libs: [
+        "services.core",
+        "services.net",
+    ],
+}
+
+//##################################################################
+// FrameworksServicesLib Robolectric test target.                  #
+//##################################################################
+android_robolectric_test {
+    name: "FrameworksServicesRoboTests",
+
+    srcs: ["src/**/*.java"],
+
+    java_resource_dirs: ["config"],
+
+    // Include the testing libraries
+    libs: [
+        "platform-test-annotations",
+        "testng",
+    ],
+
+    instrumentation_for: "FrameworksServicesLib",
+}
+
+filegroup {
+    name: "FrameworksServicesRoboShadows",
+    srcs: ["src/com/android/server/testing/shadows/**/*.java"],
+}
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
deleted file mode 100644
index 0cf0d34..0000000
--- a/services/robotests/Android.mk
+++ /dev/null
@@ -1,89 +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.
-
-###################################################################
-# FrameworksServicesLib app just for Robolectric test target      #
-###################################################################
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := FrameworksServicesLib
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    services.core \
-    services.net
-
-include $(BUILD_PACKAGE)
-
-###################################################################
-# FrameworksServicesLib Robolectric test target.                  #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := FrameworksServicesRoboTests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/res
-
-LOCAL_JAVA_RESOURCE_DIRS := config
-
-# Include the testing libraries
-LOCAL_JAVA_LIBRARIES := \
-    platform-test-annotations \
-    robolectric_android-all-stub \
-    Robolectric_all-target \
-    mockito-robolectric-prebuilt \
-    truth-prebuilt \
-    testng
-
-LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-###################################################################
-# FrameworksServicesLib runner target to run the previous target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := RunFrameworksServicesRoboTests
-
-LOCAL_JAVA_LIBRARIES := \
-    FrameworksServicesRoboTests \
-    platform-test-annotations \
-    robolectric_android-all-stub \
-    Robolectric_all-target \
-    mockito-robolectric-prebuilt \
-    truth-prebuilt \
-    testng
-
-LOCAL_TEST_PACKAGE := FrameworksServicesLib
-
-LOCAL_ROBOTEST_FILES := $(call find-files-in-subdirs,$(LOCAL_PATH)/src,*Test.java,.)
-
-include external/robolectric-shadows/run_robotests.mk
-
-###################################################################
-# include subdir Android.mk files
-###################################################################
-include $(CLEAR_VARS)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/robotests/AndroidManifest.xml b/services/robotests/AndroidManifest.xml
new file mode 100644
index 0000000..828c8fa
--- /dev/null
+++ b/services/robotests/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          coreApp="true"
+          package="com.android.server.robotests">
+
+    <application/>
+
+</manifest>
diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp
new file mode 100644
index 0000000..9d384e9
--- /dev/null
+++ b/services/robotests/backup/Android.bp
@@ -0,0 +1,53 @@
+// 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.
+
+//##################################################################
+// BackupFrameworksServicesLib app just for Robolectric test target      #
+//##################################################################
+android_app {
+    name: "BackupFrameworksServicesLib",
+    platform_apis: true,
+
+    privileged: true,
+
+    static_libs: [
+        "bmgr",
+        "bu",
+        "services.backup",
+        "services.core",
+        "services.net",
+    ],
+}
+
+//##################################################################
+// BackupFrameworksServicesLib Robolectric test target.                  #
+//##################################################################
+android_robolectric_test {
+    name: "BackupFrameworksServicesRoboTests",
+    srcs: [
+        "src/**/*.java",
+        ":FrameworksServicesRoboShadows",
+    ],
+
+    java_resource_dirs: ["config"],
+
+    // Include the testing libraries
+    libs: [
+        "platform-test-annotations",
+        "testng",
+    ],
+
+    instrumentation_for: "BackupFrameworksServicesLib",
+
+}
diff --git a/services/robotests/backup/Android.mk b/services/robotests/backup/Android.mk
deleted file mode 100644
index bd4ebbd..0000000
--- a/services/robotests/backup/Android.mk
+++ /dev/null
@@ -1,84 +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)
-
-###################################################################
-# BackupFrameworksServicesLib app just for Robolectric test target      #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := BackupFrameworksServicesLib
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    bmgr \
-    bu \
-    services.backup \
-    services.core \
-    services.net
-
-include $(BUILD_PACKAGE)
-
-###################################################################
-# BackupFrameworksServicesLib Robolectric test target.                  #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := BackupFrameworksServicesRoboTests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    $(call all-java-files-under, ../src/com/android/server/testing/shadows)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_JAVA_RESOURCE_DIRS := config
-
-# Include the testing libraries
-LOCAL_JAVA_LIBRARIES := \
-    platform-test-annotations \
-    robolectric_android-all-stub \
-    Robolectric_all-target \
-    mockito-robolectric-prebuilt \
-    truth-prebuilt \
-    testng
-
-LOCAL_INSTRUMENTATION_FOR := BackupFrameworksServicesLib
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-###################################################################
-# BackupFrameworksServicesLib runner target to run the previous target. #
-###################################################################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := RunBackupFrameworksServicesRoboTests
-
-LOCAL_JAVA_LIBRARIES := \
-    BackupFrameworksServicesRoboTests \
-    platform-test-annotations \
-    robolectric_android-all-stub \
-    Robolectric_all-target \
-    mockito-robolectric-prebuilt \
-    truth-prebuilt \
-    testng
-
-LOCAL_TEST_PACKAGE := BackupFrameworksServicesLib
-
-include external/robolectric-shadows/run_robotests.mk
diff --git a/services/robotests/backup/AndroidManifest.xml b/services/robotests/backup/AndroidManifest.xml
new file mode 100644
index 0000000..0932378
--- /dev/null
+++ b/services/robotests/backup/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          coreApp="true"
+          package="com.android.server.backup.robotests">
+
+    <application/>
+
+</manifest>
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 06c83a2..6feac52 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -53,6 +53,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.longThat;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
@@ -129,9 +130,12 @@
         ConnectivityService connectivityService;
         LocationManager locationManager;
         ConstraintController constraintController;
+        // Freeze time for testing.
+        long nowElapsed;
 
         InjectorForTest(Context ctx) {
             super(ctx);
+            nowElapsed = SystemClock.elapsedRealtime();
         }
 
         @Override
@@ -156,6 +160,11 @@
         }
 
         @Override
+        long getElapsedRealtime() {
+            return nowElapsed;
+        }
+
+        @Override
         LocationManager getLocationManager() {
             return locationManager;
         }
@@ -494,11 +503,44 @@
         mDeviceIdleController.becomeActiveLocked("testing", 0);
         verifyStateConditions(STATE_ACTIVE);
 
+        setAlarmSoon(false);
         setChargingOn(false);
         setScreenOn(false);
 
         mDeviceIdleController.becomeInactiveIfAppropriateLocked();
         verifyStateConditions(STATE_INACTIVE);
+        verify(mDeviceIdleController)
+                .scheduleAlarmLocked(eq(mConstants.INACTIVE_TIMEOUT), eq(false));
+    }
+
+    @Test
+    public void testStateActiveToStateInactive_UpcomingAlarm() {
+        final long timeUntilAlarm = mConstants.MIN_TIME_TO_ALARM / 2;
+        // Set an upcoming alarm that will prevent full idle.
+        doReturn(mInjector.getElapsedRealtime() + timeUntilAlarm)
+                .when(mAlarmManager).getNextWakeFromIdleTime();
+
+        InOrder inOrder = inOrder(mDeviceIdleController);
+
+        enterDeepState(STATE_ACTIVE);
+        setQuickDozeEnabled(false);
+        setChargingOn(false);
+        setScreenOn(false);
+
+        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+        verifyStateConditions(STATE_INACTIVE);
+        inOrder.verify(mDeviceIdleController)
+                .scheduleAlarmLocked(eq(timeUntilAlarm + mConstants.INACTIVE_TIMEOUT), eq(false));
+
+        enterDeepState(STATE_ACTIVE);
+        setQuickDozeEnabled(true);
+        setChargingOn(false);
+        setScreenOn(false);
+
+        mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+        verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+        inOrder.verify(mDeviceIdleController).scheduleAlarmLocked(
+                eq(timeUntilAlarm + mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
     }
 
     @Test
@@ -515,42 +557,68 @@
 
     @Test
     public void testTransitionFromAnyStateToStateQuickDozeDelay() {
+        setAlarmSoon(false);
+        InOrder inOrder = inOrder(mDeviceIdleController);
+
         enterDeepState(STATE_ACTIVE);
         setQuickDozeEnabled(true);
         setChargingOn(false);
         setScreenOn(false);
         verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+        inOrder.verify(mDeviceIdleController)
+                .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
 
         enterDeepState(STATE_INACTIVE);
         setQuickDozeEnabled(true);
         verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+        inOrder.verify(mDeviceIdleController)
+                .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
 
         enterDeepState(STATE_IDLE_PENDING);
         setQuickDozeEnabled(true);
         verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+        inOrder.verify(mDeviceIdleController)
+                .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
 
         enterDeepState(STATE_SENSING);
         setQuickDozeEnabled(true);
         verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+        inOrder.verify(mDeviceIdleController)
+                .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
 
         enterDeepState(STATE_LOCATING);
         setQuickDozeEnabled(true);
         verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+        inOrder.verify(mDeviceIdleController)
+                .scheduleAlarmLocked(eq(mConstants.QUICK_DOZE_DELAY_TIMEOUT), eq(false));
 
         // IDLE should stay as IDLE.
         enterDeepState(STATE_IDLE);
+        // Clear out any alarm setting from the order before checking for this section.
+        inOrder.verify(mDeviceIdleController, atLeastOnce())
+                .scheduleAlarmLocked(anyLong(), anyBoolean());
         setQuickDozeEnabled(true);
         verifyStateConditions(STATE_IDLE);
+        inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean());
 
         // IDLE_MAINTENANCE should stay as IDLE_MAINTENANCE.
         enterDeepState(STATE_IDLE_MAINTENANCE);
+        // Clear out any alarm setting from the order before checking for this section.
+        inOrder.verify(mDeviceIdleController, atLeastOnce())
+                .scheduleAlarmLocked(anyLong(), anyBoolean());
         setQuickDozeEnabled(true);
         verifyStateConditions(STATE_IDLE_MAINTENANCE);
+        inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean());
 
+        // State is already QUICK_DOZE_DELAY. No work should be done.
         enterDeepState(STATE_QUICK_DOZE_DELAY);
+        // Clear out any alarm setting from the order before checking for this section.
+        inOrder.verify(mDeviceIdleController, atLeastOnce())
+                .scheduleAlarmLocked(anyLong(), anyBoolean());
         setQuickDozeEnabled(true);
         mDeviceIdleController.becomeInactiveIfAppropriateLocked();
         verifyStateConditions(STATE_QUICK_DOZE_DELAY);
+        inOrder.verify(mDeviceIdleController, never()).scheduleAlarmLocked(anyLong(), anyBoolean());
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
index 73b3b8b..a785300 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
@@ -19,6 +19,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE;
 import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR;
 import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION;
 
@@ -28,6 +29,7 @@
 
 import android.hardware.display.ColorDisplayManager;
 import android.os.SystemProperties;
+import android.view.Display;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -79,7 +81,7 @@
 
     @Test
     public void setColorMode_natural() {
-        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix);
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo("0" /* managed */);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -88,7 +90,7 @@
 
     @Test
     public void setColorMode_boosted() {
-        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix);
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix, -1);
 
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo("0" /* managed */);
@@ -98,7 +100,7 @@
 
     @Test
     public void setColorMode_saturated() {
-        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix);
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo("1" /* unmanaged */);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -107,7 +109,7 @@
 
     @Test
     public void setColorMode_automatic() {
-        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix);
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo("2" /* enhanced */);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -116,7 +118,7 @@
 
     @Test
     public void setColorMode_vendor() {
-        mDtm.setColorMode(0x100, mNightDisplayMatrix);
+        mDtm.setColorMode(0x100, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo(Integer.toString(0x100) /* pass-through */);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
@@ -125,10 +127,38 @@
 
     @Test
     public void setColorMode_outOfBounds() {
-        mDtm.setColorMode(0x50, mNightDisplayMatrix);
+        mDtm.setColorMode(0x50, mNightDisplayMatrix, -1);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR))
                 .isEqualTo(null);
         assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
                 .isEqualTo(null);
     }
+
+    @Test
+    public void setColorMode_withoutColorSpace() {
+        String magicPropertyValue = "magic";
+
+        // Start with a known state, which we expect to remain unmodified
+        SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
+
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
+                Display.COLOR_MODE_INVALID);
+        assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
+                .isEqualTo(magicPropertyValue);
+    }
+
+    @Test
+    public void setColorMode_withColorSpace() {
+        String magicPropertyValue = "magic";
+        int testPropertyValue = Display.COLOR_MODE_SRGB;
+
+        // Start with a known state, which we expect to get modified
+        SystemProperties.set(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE, magicPropertyValue);
+
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix,
+                testPropertyValue);
+        assertThat(mSystemProperties.get(PERSISTENT_PROPERTY_COMPOSITION_COLOR_MODE))
+                .isEqualTo(Integer.toString(testPropertyValue));
+    }
+
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
index 70b7bb6..3614763 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
@@ -71,7 +71,6 @@
     private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests";
     private static final int SOURCE_USER_ID = 0;
 
-    private TimeController.TcConstants mConstants;
     private TimeController mTimeController;
 
     private MockitoSession mMockingSession;
@@ -111,7 +110,6 @@
 
         // Initialize real objects.
         mTimeController = new TimeController(mJobSchedulerService);
-        mConstants = mTimeController.getTcConstants();
         spyOn(mTimeController);
     }
 
@@ -159,18 +157,7 @@
     }
 
     @Test
-    public void testMaybeStartTrackingJobLocked_DelayInOrder_NoSkipping() {
-        mConstants.SKIP_NOT_READY_JOBS = false;
-        mTimeController.onConstantsUpdatedLocked();
-
-        runTestMaybeStartTrackingJobLocked_DelayInOrder();
-    }
-
-    @Test
-    public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_AllReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
-
+    public void testMaybeStartTrackingJobLocked_DelayInOrder_AllReady() {
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
 
         runTestMaybeStartTrackingJobLocked_DelayInOrder();
@@ -201,9 +188,7 @@
     }
 
     @Test
-    public void testMaybeStartTrackingJobLocked_DelayInOrder_WithSkipping_SomeNotReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+    public void testMaybeStartTrackingJobLocked_DelayInOrder_SomeNotReady() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus("testMaybeStartTrackingJobLocked_DelayInOrder",
@@ -235,18 +220,7 @@
     }
 
     @Test
-    public void testMaybeStartTrackingJobLocked_DelayReverseOrder_NoSkipping() {
-        mConstants.SKIP_NOT_READY_JOBS = false;
-        mTimeController.onConstantsUpdatedLocked();
-
-        runTestMaybeStartTrackingJobLocked_DelayReverseOrder();
-    }
-
-    @Test
-    public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_AllReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
-
+    public void testMaybeStartTrackingJobLocked_DelayReverseOrder_AllReady() {
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
 
         runTestMaybeStartTrackingJobLocked_DelayReverseOrder();
@@ -279,9 +253,7 @@
     }
 
     @Test
-    public void testMaybeStartTrackingJobLocked_DelayReverseOrder_WithSkipping_SomeNotReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+    public void testMaybeStartTrackingJobLocked_DelayReverseOrder_SomeNotReady() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus("testMaybeStartTrackingJobLocked_DelayReverseOrder",
@@ -315,18 +287,7 @@
     }
 
     @Test
-    public void testMaybeStartTrackingJobLocked_DeadlineInOrder_NoSkipping() {
-        mConstants.SKIP_NOT_READY_JOBS = false;
-        mTimeController.onConstantsUpdatedLocked();
-
-        runTestMaybeStartTrackingJobLocked_DeadlineInOrder();
-    }
-
-    @Test
-    public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_AllReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
-
+    public void testMaybeStartTrackingJobLocked_DeadlineInOrder_AllReady() {
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
 
         runTestMaybeStartTrackingJobLocked_DeadlineInOrder();
@@ -357,9 +318,7 @@
     }
 
     @Test
-    public void testMaybeStartTrackingJobLocked_DeadlineInOrder_WithSkipping_SomeNotReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+    public void testMaybeStartTrackingJobLocked_DeadlineInOrder_SomeNotReady() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus("testMaybeStartTrackingJobLocked_DeadlineInOrder",
@@ -391,18 +350,7 @@
     }
 
     @Test
-    public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_NoSkipping() {
-        mConstants.SKIP_NOT_READY_JOBS = false;
-        mTimeController.onConstantsUpdatedLocked();
-
-        runTestMaybeStartTrackingJobLocked_DeadlineReverseOrder();
-    }
-
-    @Test
-    public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_AllReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
-
+    public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_AllReady() {
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
 
         runTestMaybeStartTrackingJobLocked_DeadlineReverseOrder();
@@ -438,9 +386,7 @@
     }
 
     @Test
-    public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_WithSkipping_SomeNotReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.onConstantsUpdatedLocked();
+    public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_SomeNotReady() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus(
@@ -478,62 +424,7 @@
     }
 
     @Test
-    public void testJobSkipToggling() {
-        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
-
-        JobStatus jobLatest = createJobStatus(
-                "testMaybeStartTrackingJobLocked_DeadlineReverseOrder",
-                createJob().setOverrideDeadline(HOUR_IN_MILLIS));
-        JobStatus jobEarliest = createJobStatus(
-                "testMaybeStartTrackingJobLocked_DeadlineReverseOrder",
-                createJob().setOverrideDeadline(5 * MINUTE_IN_MILLIS));
-
-        doReturn(true).when(mTimeController)
-                .wouldBeReadyWithConstraintLocked(eq(jobLatest), anyInt());
-        doReturn(false).when(mTimeController)
-                .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
-
-        // Starting off with the skipping off, we should still set an alarm for the earlier job.
-        mConstants.SKIP_NOT_READY_JOBS = false;
-        mTimeController.recheckAlarmsLocked();
-        InOrder inOrder = inOrder(mAlarmManager);
-
-        mTimeController.maybeStartTrackingJobLocked(jobEarliest, null);
-        mTimeController.maybeStartTrackingJobLocked(jobLatest, null);
-        inOrder.verify(mAlarmManager, times(1))
-                .set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
-                        eq(TAG_DEADLINE), any(), any(), any());
-
-        // Turn it on, use alarm for later job.
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.recheckAlarmsLocked();
-
-        inOrder.verify(mAlarmManager, times(1))
-                .set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(), anyLong(), eq(TAG_DEADLINE),
-                        any(), any(), any());
-
-        // Back off, use alarm for earlier job.
-        mConstants.SKIP_NOT_READY_JOBS = false;
-        mTimeController.recheckAlarmsLocked();
-
-        inOrder.verify(mAlarmManager, times(1))
-                .set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
-                        eq(TAG_DEADLINE), any(), any(), any());
-    }
-
-    @Test
-    public void testCheckExpiredDelaysAndResetAlarm_NoSkipping() {
-        mConstants.SKIP_NOT_READY_JOBS = false;
-        mTimeController.recheckAlarmsLocked();
-
-        runTestCheckExpiredDelaysAndResetAlarm();
-    }
-
-    @Test
-    public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_AllReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.recheckAlarmsLocked();
-
+    public void testCheckExpiredDelaysAndResetAlarm_AllReady() {
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
 
         runTestCheckExpiredDelaysAndResetAlarm();
@@ -589,9 +480,7 @@
     }
 
     @Test
-    public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_SomeNotReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.recheckAlarmsLocked();
+    public void testCheckExpiredDelaysAndResetAlarm_SomeNotReady() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus("testCheckExpiredDelaysAndResetAlarm",
@@ -639,18 +528,7 @@
     }
 
     @Test
-    public void testCheckExpiredDeadlinesAndResetAlarm_NoSkipping() {
-        mConstants.SKIP_NOT_READY_JOBS = false;
-        mTimeController.recheckAlarmsLocked();
-
-        runTestCheckExpiredDeadlinesAndResetAlarm();
-    }
-
-    @Test
-    public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_AllReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.recheckAlarmsLocked();
-
+    public void testCheckExpiredDeadlinesAndResetAlarm_AllReady() {
         doReturn(true).when(mTimeController).wouldBeReadyWithConstraintLocked(any(), anyInt());
 
         runTestCheckExpiredDeadlinesAndResetAlarm();
@@ -706,9 +584,7 @@
     }
 
     @Test
-    public void testCheckExpiredDeadlinesAndResetAlarm_WithSkipping_SomeNotReady() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.recheckAlarmsLocked();
+    public void testCheckExpiredDeadlinesAndResetAlarm_SomeNotReady() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
         JobStatus jobLatest = createJobStatus("testCheckExpiredDeadlinesAndResetAlarm",
@@ -756,28 +632,14 @@
     }
 
     @Test
-    public void testEvaluateStateLocked_SkippingOff() {
-        mConstants.SKIP_NOT_READY_JOBS = false;
-        mTimeController.recheckAlarmsLocked();
-        JobStatus job = createJobStatus("testEvaluateStateLocked_SkippingOff",
-                createJob().setOverrideDeadline(HOUR_IN_MILLIS));
-
-        mTimeController.evaluateStateLocked(job);
-        verify(mAlarmManager, never())
-                .set(anyInt(), anyLong(), anyLong(), anyLong(), anyString(), any(), any(), any());
-    }
-
-    @Test
-    public void testEvaluateStateLocked_SkippingOn_Delay() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.recheckAlarmsLocked();
+    public void testEvaluateStateLocked_Delay() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
-        JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Delay",
+        JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_Delay",
                 createJob().setMinimumLatency(HOUR_IN_MILLIS));
-        JobStatus jobMiddle = createJobStatus("testEvaluateStateLocked_SkippingOn_Delay",
+        JobStatus jobMiddle = createJobStatus("testEvaluateStateLocked_Delay",
                 createJob().setMinimumLatency(30 * MINUTE_IN_MILLIS));
-        JobStatus jobEarliest = createJobStatus("testEvaluateStateLocked_SkippingOn_Delay",
+        JobStatus jobEarliest = createJobStatus("testEvaluateStateLocked_Delay",
                 createJob().setMinimumLatency(5 * MINUTE_IN_MILLIS));
 
         doReturn(false).when(mTimeController)
@@ -827,16 +689,14 @@
     }
 
     @Test
-    public void testEvaluateStateLocked_SkippingOn_Deadline() {
-        mConstants.SKIP_NOT_READY_JOBS = true;
-        mTimeController.recheckAlarmsLocked();
+    public void testEvaluateStateLocked_Deadline() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
 
-        JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_SkippingOn_Deadline",
+        JobStatus jobLatest = createJobStatus("testEvaluateStateLocked_Deadline",
                 createJob().setOverrideDeadline(HOUR_IN_MILLIS));
-        JobStatus jobMiddle = createJobStatus("testEvaluateStateLocked_SkippingOn_Deadline",
+        JobStatus jobMiddle = createJobStatus("testEvaluateStateLocked_Deadline",
                 createJob().setOverrideDeadline(30 * MINUTE_IN_MILLIS));
-        JobStatus jobEarliest = createJobStatus("testEvaluateStateLocked_SkippingOn_Deadline",
+        JobStatus jobEarliest = createJobStatus("testEvaluateStateLocked_Deadline",
                 createJob().setOverrideDeadline(5 * MINUTE_IN_MILLIS));
 
         doReturn(false).when(mTimeController)
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index e9e96c9..1ad7b6e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -72,6 +72,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.devicepolicy.MockUtils;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import com.google.android.collect.Lists;
 
@@ -132,9 +133,10 @@
     @Mock private UnaryOperator<List<ScoredNetwork>> mScanResultsFilter;
     @Mock private WifiInfo mWifiInfo;
     @Mock private NetworkScoreService.ScoringServiceConnection mServiceConnection;
-    @Mock private PackageManagerInternal mPackageManagerInternal;
+    @Mock private PermissionManagerServiceInternal mPermissionManagerInternal;
     @Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
-    @Captor private ArgumentCaptor<PackageManagerInternal.PackagesProvider> mPackagesProviderCaptor;
+    @Captor private
+    ArgumentCaptor<PermissionManagerServiceInternal.PackagesProvider> mPackagesProviderCaptor;
 
     private ContentResolver mContentResolver;
     private NetworkScoreService mNetworkScoreService;
@@ -162,7 +164,8 @@
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
         mHandlerThread = new HandlerThread("NetworkScoreServiceTest");
         mHandlerThread.start();
-        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
+        LocalServices.addService(
+                PermissionManagerServiceInternal.class, mPermissionManagerInternal);
         mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager,
                 networkScorerAppData -> mServiceConnection, mHandlerThread.getLooper());
         WifiConfiguration configuration = new WifiConfiguration();
@@ -196,7 +199,7 @@
         Settings.Global.putString(mContentResolver,
                 Settings.Global.USE_OPEN_WIFI_PACKAGE, "com.some.app");
 
-        verify(mPackageManagerInternal)
+        verify(mPermissionManagerInternal)
                 .setUseOpenWifiAppPackagesProvider(mPackagesProviderCaptor.capture());
 
         String[] packages = mPackagesProviderCaptor.getValue().getPackages(0);
@@ -209,7 +212,7 @@
         Settings.Global.putString(mContentResolver,
                 Settings.Global.USE_OPEN_WIFI_PACKAGE, "com.some.other.app");
 
-        verify(mPackageManagerInternal, timeout(500))
+        verify(mPermissionManagerInternal, timeout(500))
                 .grantDefaultPermissionsToDefaultUseOpenWifiApp("com.some.other.app", 0);
     }
 
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 ba2959f..2f9f9bb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -23,21 +23,25 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.GestureDescription;
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.view.Display;
 
 import com.android.server.wm.WindowManagerInternal;
 
@@ -50,6 +54,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 
 
 /**
@@ -73,6 +78,9 @@
     @Mock GlobalActionPerformer mMockGlobalActionPerformer;
     @Mock KeyEventDispatcher mMockKeyEventDispatcher;
     @Mock MagnificationController mMockMagnificationController;
+    @Mock IBinder mMockIBinder;
+    @Mock IAccessibilityServiceClient mMockServiceClient;
+    @Mock MotionEventInjector mMockMotionEventInjector;
 
     MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
 
@@ -82,15 +90,22 @@
         when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mMockKeyEventDispatcher);
         when(mMockSystemSupport.getMagnificationController())
                 .thenReturn(mMockMagnificationController);
+        when(mMockSystemSupport.getMotionEventInjectorForDisplayLocked(
+                Display.DEFAULT_DISPLAY)).thenReturn(mMockMotionEventInjector);
 
         when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
         mMockResolveInfo.serviceInfo = mock(ServiceInfo.class);
         mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
 
+        when(mMockIBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
+        when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
+                true);
+
         mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
                 COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
                 mMockSecurityPolicy, mMockSystemSupport, mMockWindowManagerInternal,
                 mMockGlobalActionPerformer, mMockA11yWindowManager);
+        when(mMockSecurityPolicy.canPerformGestures(mConnection)).thenReturn(true);
     }
 
     @After
@@ -115,25 +130,23 @@
 
     @Test
     public void bindConnectUnbind_linksAndUnlinksToServiceDeath() throws RemoteException {
-        IBinder mockBinder = mock(IBinder.class);
         setServiceBinding(COMPONENT_NAME);
         mConnection.bindLocked();
-        mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
-        verify(mockBinder).linkToDeath(eq(mConnection), anyInt());
+        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+        verify(mMockIBinder).linkToDeath(eq(mConnection), anyInt());
         mConnection.unbindLocked();
-        verify(mockBinder).unlinkToDeath(eq(mConnection), anyInt());
+        verify(mMockIBinder).unlinkToDeath(eq(mConnection), anyInt());
     }
 
     @Test
     public void connectedServiceCrashedAndRestarted_crashReportedInServiceInfo() {
-        IBinder mockBinder = mock(IBinder.class);
         setServiceBinding(COMPONENT_NAME);
         mConnection.bindLocked();
-        mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
         assertFalse(mConnection.getServiceInfo().crashed);
         mConnection.binderDied();
         assertTrue(mConnection.getServiceInfo().crashed);
-        mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
         mHandler.sendAllMessages();
         assertFalse(mConnection.getServiceInfo().crashed);
     }
@@ -145,10 +158,9 @@
 
     @Test
     public void binderDied_keysGetFlushed() {
-        IBinder mockBinder = mock(IBinder.class);
         setServiceBinding(COMPONENT_NAME);
         mConnection.bindLocked();
-        mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
         mConnection.binderDied();
         assertTrue(mConnection.getServiceInfo().crashed);
         verify(mMockKeyEventDispatcher).flush(mConnection);
@@ -157,17 +169,63 @@
     @Test
     public void connectedService_notInEnabledServiceList_doNotInitClient()
             throws RemoteException {
-        IBinder mockBinder = mock(IBinder.class);
-        IAccessibilityServiceClient mockClient = mock(IAccessibilityServiceClient.class);
-        when(mockBinder.queryLocalInterface(any())).thenReturn(mockClient);
         when(mMockUserState.getEnabledServicesLocked())
                 .thenReturn(Collections.emptySet());
         setServiceBinding(COMPONENT_NAME);
 
         mConnection.bindLocked();
-        mConnection.onServiceConnected(COMPONENT_NAME, mockBinder);
+        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
         mHandler.sendAllMessages();
         verify(mMockSystemSupport, times(2)).onClientChangeLocked(false);
-        verify(mockClient, times(0)).init(any(), anyInt(), any());
+        verify(mMockServiceClient, times(0)).init(any(), anyInt(), any());
     }
+
+    @Test
+    public void sendGesture_touchableDisplay_injectEvents()
+            throws RemoteException {
+        setServiceBinding(COMPONENT_NAME);
+        mConnection.bindLocked();
+        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+        ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+        List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+        when(parceledListSlice.getList()).thenReturn(gestureSteps);
+        mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
+
+        verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0);
+    }
+
+    @Test
+    public void sendGesture_untouchableDisplay_performGestureResultFailed()
+            throws RemoteException {
+        when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
+                false);
+        setServiceBinding(COMPONENT_NAME);
+        mConnection.bindLocked();
+        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+        ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+        List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+        when(parceledListSlice.getList()).thenReturn(gestureSteps);
+        mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
+
+        verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0);
+        verify(mMockServiceClient).onPerformGestureResult(0, false);
+    }
+
+    @Test
+    public void sendGesture_invalidDisplay_performGestureResultFailed()
+            throws RemoteException {
+        setServiceBinding(COMPONENT_NAME);
+        mConnection.bindLocked();
+        mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+        ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
+        List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
+        when(parceledListSlice.getList()).thenReturn(gestureSteps);
+        mConnection.dispatchGesture(0, parceledListSlice, Display.INVALID_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 22408cc..7e64caf 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -33,6 +33,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -42,6 +43,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.SparseArray;
+import android.view.Display;
 import android.view.IWindow;
 import android.view.WindowInfo;
 import android.view.accessibility.AccessibilityEvent;
@@ -142,7 +144,9 @@
     public void startTrackingWindows_shouldEnableWindowManagerCallback() {
         // AccessibilityWindowManager#startTrackingWindows already invoked in setup
         assertTrue(mA11yWindowManager.isTrackingWindowsLocked());
-        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(any());
+        // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
+        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
+                eq(Display.DEFAULT_DISPLAY), any());
     }
 
     @Test
@@ -152,7 +156,9 @@
 
         mA11yWindowManager.stopTrackingWindows();
         assertFalse(mA11yWindowManager.isTrackingWindowsLocked());
-        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(any());
+        // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY
+        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
+                eq(Display.DEFAULT_DISPLAY), any());
     }
 
     @Test
@@ -238,7 +244,7 @@
         windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
         windowInfo.token = token.asBinder();
         windowInfo.layer = 0;
-        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
         mWindowInfos.set(0, windowInfo);
 
         mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
@@ -305,67 +311,73 @@
     }
 
     @Test
-    public void computePartialInteractiveRegionForWindow_wholeWindowVisible_returnWholeRegion() {
+    public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
         // Updates top 2 z-order WindowInfo are whole visible.
         WindowInfo windowInfo = mWindowInfos.get(0);
-        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
         windowInfo = mWindowInfos.get(1);
-        windowInfo.boundsInScreen.set(0, SCREEN_HEIGHT / 2,
-                SCREEN_WIDTH, SCREEN_HEIGHT);
+        windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT);
         mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
 
         final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(0).getId();
 
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
-                windowId, outBounds);
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
         assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
         assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
 
         windowId = a11yWindows.get(1).getId();
 
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
-                windowId, outBounds);
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
         assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
         assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
     }
 
     @Test
-    public void computePartialInteractiveRegionForWindow_halfWindowVisible_returnHalfRegion() {
+    public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
         // Updates z-order #1 WindowInfo is half visible
         WindowInfo windowInfo = mWindowInfos.get(0);
-        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
-        windowInfo = mWindowInfos.get(1);
-        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
 
         mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
         final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(1).getId();
 
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
-                windowId, outBounds);
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
         assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
         assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
     }
 
     @Test
-    public void computePartialInteractiveRegionForWindow_windowNotVisible_returnEmptyRegion() {
-        // Updates z-order #1 WindowInfo is not visible
+    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 Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertTrue(outBounds.getBounds().isEmpty());
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
+        // 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.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-        windowInfo = mWindowInfos.get(1);
-        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+        windowInfo.regionInScreen.set(region);
         mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
 
         final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
         final Region outBounds = new Region();
         int windowId = a11yWindows.get(1).getId();
 
-        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
-                windowId, outBounds);
-        assertTrue(outBounds.getBounds().isEmpty());
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertFalse(outBounds.getBounds().isEmpty());
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT - 400));
     }
 
     @Test
@@ -588,7 +600,7 @@
         windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
         windowInfo.token = windowToken.asBinder();
         windowInfo.layer = layer;
-        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
         mWindowInfos.add(windowInfo);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
index d854582..210de53 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/UiAutomationManagerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.accessibility;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -31,6 +33,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.hardware.display.DisplayManager;
 import android.os.IBinder;
 import android.view.accessibility.AccessibilityEvent;
 
@@ -78,6 +81,11 @@
 
         when(mMockAccessibilityServiceClient.asBinder()).thenReturn(mMockServiceAsBinder);
 
+        final Context context = getInstrumentation().getTargetContext();
+        when(mMockContext.getSystemService(Context.DISPLAY_SERVICE)).thenReturn(
+                context.getSystemService(
+                        DisplayManager.class));
+
         mMessageCapturingHandler = new MessageCapturingHandler(null);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index e6c484a..d008ca6 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -142,4 +142,32 @@
         CompatConfig pc = new CompatConfig();
         assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
     }
+
+    @Test
+    public void testSystemAppDisabledChangeEnabled() {
+        CompatConfig pc = new CompatConfig();
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true)); // disabled
+        ApplicationInfo sysApp = makeAppInfo("system.app", 1);
+        sysApp.flags |= ApplicationInfo.FLAG_SYSTEM;
+        assertThat(pc.isChangeEnabled(1234L, sysApp)).isTrue();
+    }
+
+    @Test
+    public void testSystemAppOverrideIgnored() {
+        CompatConfig pc = new CompatConfig();
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
+        pc.addOverride(1234L, "system.app", false);
+        ApplicationInfo sysApp = makeAppInfo("system.app", 1);
+        sysApp.flags |= ApplicationInfo.FLAG_SYSTEM;
+        assertThat(pc.isChangeEnabled(1234L, sysApp)).isTrue();
+    }
+
+    @Test
+    public void testSystemAppTargetSdkIgnored() {
+        CompatConfig pc = new CompatConfig();
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false));
+        ApplicationInfo sysApp = makeAppInfo("system.app", 1);
+        sysApp.flags |= ApplicationInfo.FLAG_SYSTEM;
+        assertThat(pc.isChangeEnabled(1234L, sysApp)).isTrue();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 2ce4c54..ce83df7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -37,6 +37,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
+import android.permission.IPermissionManager;
 import android.security.KeyChain;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
@@ -199,6 +200,11 @@
         }
 
         @Override
+        IPermissionManager getIPermissionManager() {
+            return services.ipermissionManager;
+        }
+
+        @Override
         IBackupManager getIBackupManager() {
             return services.ibackupManager;
         }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 8f0aeea..f6f365e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -52,6 +52,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
+import android.permission.IPermissionManager;
 import android.provider.Settings;
 import android.security.KeyChain;
 import android.telephony.TelephonyManager;
@@ -97,6 +98,7 @@
     public ActivityManagerInternal activityManagerInternal;
     public ActivityTaskManagerInternal activityTaskManagerInternal;
     public final IPackageManager ipackageManager;
+    public final IPermissionManager ipermissionManager;
     public final IBackupManager ibackupManager;
     public final IAudioService iaudioService;
     public final LockPatternUtils lockPatternUtils;
@@ -137,6 +139,7 @@
         activityManagerInternal = mock(ActivityManagerInternal.class);
         activityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
         ipackageManager = mock(IPackageManager.class);
+        ipermissionManager = mock(IPermissionManager.class);
         ibackupManager = mock(IBackupManager.class);
         iaudioService = mock(IAudioService.class);
         lockPatternUtils = mock(LockPatternUtils.class);
diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index fb2913b..a19b387 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -18,13 +18,19 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.Resources;
 import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.Time;
 import android.os.Handler;
@@ -33,6 +39,7 @@
 import android.provider.Settings.Secure;
 import android.provider.Settings.System;
 import android.test.mock.MockContentResolver;
+import android.view.Display;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -73,6 +80,8 @@
     private ColorDisplayService mCds;
     private ColorDisplayService.BinderService mBinderService;
 
+    private Resources mResourcesSpy;
+
     @BeforeClass
     public static void setDtm() {
         final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
@@ -84,6 +93,9 @@
         mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
         doReturn(mContext).when(mContext).getApplicationContext();
 
+        mResourcesSpy = Mockito.spy(mContext.getResources());
+        when(mContext.getResources()).thenReturn(mResourcesSpy);
+
         mUserId = ActivityManager.getCurrentUser();
 
         final MockContentResolver cr = new MockContentResolver(mContext);
@@ -1050,6 +1062,80 @@
         assertDwbActive(true);
     }
 
+    @Test
+    public void compositionColorSpaces_noResources() {
+        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        reset(dtm);
+
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+            .thenReturn(new int[] {});
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+            .thenReturn(new int[] {});
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        startService();
+        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
+                eq(Display.COLOR_MODE_INVALID));
+    }
+
+    @Test
+    public void compositionColorSpaces_invalidResources() {
+        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        reset(dtm);
+
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+            .thenReturn(new int[] {
+               ColorDisplayManager.COLOR_MODE_NATURAL,
+               // Missing second color mode
+            });
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+            .thenReturn(new int[] {
+               Display.COLOR_MODE_SRGB,
+               Display.COLOR_MODE_DISPLAY_P3
+            });
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        startService();
+        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
+                eq(Display.COLOR_MODE_INVALID));
+    }
+
+    @Test
+    public void compositionColorSpaces_validResources_validColorMode() {
+        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        reset(dtm);
+
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+            .thenReturn(new int[] {
+               ColorDisplayManager.COLOR_MODE_NATURAL
+            });
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+            .thenReturn(new int[] {
+               Display.COLOR_MODE_SRGB,
+            });
+        setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+        startService();
+        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(),
+                eq(Display.COLOR_MODE_SRGB));
+    }
+
+    @Test
+    public void compositionColorSpaces_validResources_invalidColorMode() {
+        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        reset(dtm);
+
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
+            .thenReturn(new int[] {
+               ColorDisplayManager.COLOR_MODE_NATURAL
+            });
+        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
+            .thenReturn(new int[] {
+               Display.COLOR_MODE_SRGB,
+            });
+        setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
+        startService();
+        verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(),
+                eq(Display.COLOR_MODE_INVALID));
+    }
+
     /**
      * Configures Night display to use a custom schedule.
      *
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index ce1edcd..09ae3a2 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -559,7 +559,25 @@
                 .build();
         mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
 
-        // RestrictBackground should be on, following its previous state
+        // RestrictBackground should be on, as before.
+        assertTrue(mService.getRestrictBackground());
+
+        stateOn = new PowerSaveState.Builder()
+                .setGlobalBatterySaverEnabled(true)
+                .setBatterySaverEnabled(true)
+                .build();
+        mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
+
+        // RestrictBackground should be on.
+        assertTrue(mService.getRestrictBackground());
+
+        stateOff = new PowerSaveState.Builder()
+                .setGlobalBatterySaverEnabled(false)
+                .setBatterySaverEnabled(false)
+                .build();
+        mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
+
+        // RestrictBackground should be on, as it was enabled manually before battery saver.
         assertTrue(mService.getRestrictBackground());
     }
 
@@ -585,6 +603,20 @@
 
         // RestrictBackground should be off, following its previous state
         assertFalse(mService.getRestrictBackground());
+
+        PowerSaveState stateOnRestrictOff = new PowerSaveState.Builder()
+                .setGlobalBatterySaverEnabled(true)
+                .setBatterySaverEnabled(false)
+                .build();
+
+        mService.updateRestrictBackgroundByLowPowerModeUL(stateOnRestrictOff);
+
+        assertFalse(mService.getRestrictBackground());
+
+        mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
+
+        // RestrictBackground should still be off.
+        assertFalse(mService.getRestrictBackground());
     }
 
     @Test
@@ -602,11 +634,49 @@
 
         // User turns off RestrictBackground manually
         setRestrictBackground(false);
-        PowerSaveState stateOff = new PowerSaveState.Builder().setBatterySaverEnabled(
-                false).build();
+        // RestrictBackground should be off because user changed it manually
+        assertFalse(mService.getRestrictBackground());
+
+        PowerSaveState stateOff = new PowerSaveState.Builder()
+                .setGlobalBatterySaverEnabled(false)
+                .setBatterySaverEnabled(false)
+                .build();
         mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
 
-        // RestrictBackground should be off because user changes it manually
+        // RestrictBackground should remain off.
+        assertFalse(mService.getRestrictBackground());
+    }
+
+    @Test
+    public void updateRestrictBackgroundByLowPowerMode_RestrictOnWithGlobalOff()
+            throws Exception {
+        setRestrictBackground(false);
+        PowerSaveState stateOn = new PowerSaveState.Builder()
+                .setGlobalBatterySaverEnabled(false)
+                .setBatterySaverEnabled(true)
+                .build();
+
+        mService.updateRestrictBackgroundByLowPowerModeUL(stateOn);
+
+        // RestrictBackground should be turned on because of battery saver.
+        assertTrue(mService.getRestrictBackground());
+
+        PowerSaveState stateRestrictOff = new PowerSaveState.Builder()
+                .setGlobalBatterySaverEnabled(true)
+                .setBatterySaverEnabled(false)
+                .build();
+        mService.updateRestrictBackgroundByLowPowerModeUL(stateRestrictOff);
+
+        // RestrictBackground should be off, returning to its state before battery saver's change.
+        assertFalse(mService.getRestrictBackground());
+
+        PowerSaveState stateOff = new PowerSaveState.Builder()
+                .setGlobalBatterySaverEnabled(false)
+                .setBatterySaverEnabled(false)
+                .build();
+        mService.updateRestrictBackgroundByLowPowerModeUL(stateOff);
+
+        // RestrictBackground should still be off, back in its pre-battery saver state.
         assertFalse(mService.getRestrictBackground());
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
new file mode 100644
index 0000000..470d4fa
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
@@ -0,0 +1,122 @@
+/*
+ * 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.content.pm.PackageParser;
+
+import com.android.internal.util.ArrayUtils;
+
+class PackageBuilder {
+    final PackageParser.Package mPkg;
+
+    PackageBuilder(String packageName) {
+        mPkg = new PackageParser.Package(packageName);
+    }
+
+    PackageBuilder setApplicationInfoCodePath(String codePath) {
+        mPkg.applicationInfo.setCodePath(codePath);
+        return this;
+    }
+
+    PackageBuilder setApplicationInfoResourcePath(String resourcePath) {
+        mPkg.applicationInfo.setResourcePath(resourcePath);
+        return this;
+    }
+
+    PackageBuilder setCodePath(String codePath) {
+        mPkg.codePath = codePath;
+        return this;
+    }
+
+    PackageBuilder setBaseCodePath(String baseCodePath) {
+        mPkg.baseCodePath = baseCodePath;
+        return this;
+    }
+
+    PackageBuilder addUsesStaticLibrary(String name, long version) {
+        mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name);
+        mPkg.usesStaticLibrariesVersions =
+                ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version);
+        return this;
+    }
+
+    PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) {
+        mPkg.applicationInfo.nativeLibraryRootDir = dir;
+        return this;
+    }
+
+    PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) {
+        mPkg.staticSharedLibVersion = staticSharedLibVersion;
+        mPkg.staticSharedLibName = staticSharedLibName;
+        return this;
+    }
+
+    PackageBuilder setManifestPackageName(String manifestPackageName) {
+        mPkg.manifestPackageName = manifestPackageName;
+        return this;
+    }
+
+    PackageBuilder setVersionCodeMajor(int versionCodeMajor) {
+        mPkg.mVersionCodeMajor = versionCodeMajor;
+        return this;
+    }
+
+    PackageBuilder setVersionCode(int versionCode) {
+        mPkg.mVersionCode = versionCode;
+        return this;
+    }
+
+    PackageBuilder addSplitCodePath(String splitCodePath) {
+        mPkg.splitCodePaths =
+                ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath);
+        return this;
+    }
+
+    PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) {
+        mPkg.applicationInfo.volumeUuid = volumeUuid;
+        return this;
+    }
+
+    PackageBuilder addLibraryName(String libraryName) {
+        mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName);
+        return this;
+    }
+
+    PackageBuilder setRealPackageName(String realPackageName) {
+        mPkg.mRealPackage = realPackageName;
+        return this;
+    }
+
+    PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) {
+        mPkg.cpuAbiOverride = cpuAbiOverride;
+        return this;
+    }
+
+    PackageBuilder addPermissionRequest(String permissionName) {
+        mPkg.requestedPermissions.add(permissionName);
+        return this;
+    }
+
+    PackageParser.Package build() {
+        return mPkg;
+    }
+
+    public PackageBuilder addApplicationInfoFlag(int flag) {
+        mPkg.applicationInfo.flags |= flag;
+        return this;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 95ec3d9..fc7cfec 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -115,7 +115,7 @@
 
     @Test
     public void testPartitions() throws Exception {
-        String[] partitions = { "system", "vendor", "odm", "oem", "product", "product_services" };
+        String[] partitions = { "system", "vendor", "odm", "oem", "product", "system_ext" };
         String[] appdir = { "app", "priv-app" };
         for (int i = 0; i < partitions.length; i++) {
             for (int j = 0; j < appdir.length; j++) {
@@ -128,7 +128,7 @@
                 Assert.assertEquals(i == 1 || i == 2, PackageManagerService.locationIsVendor(path));
                 Assert.assertEquals(i == 3, PackageManagerService.locationIsOem(path));
                 Assert.assertEquals(i == 4, PackageManagerService.locationIsProduct(path));
-                Assert.assertEquals(i == 5, PackageManagerService.locationIsProductServices(path));
+                Assert.assertEquals(i == 5, PackageManagerService.locationIsSystemExt(path));
             }
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 13a8eb1..e33d8ca 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
@@ -557,6 +558,9 @@
         pkg.mRequiredForAllUsers = true;
         pkg.visibleToInstantApps = true;
         pkg.use32bitAbi = true;
+        pkg.mForceQueryable = true;
+        pkg.mQueriesPackages = new ArrayList<>(Arrays.asList("foo27"));
+        pkg.mQueriesIntents = new ArrayList<>(Arrays.asList(new Intent("foo28")));
     }
 
     private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
new file mode 100644
index 0000000..b42cfd8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -0,0 +1,154 @@
+/*
+ * 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.content.pm.PackageUserState;
+import android.util.SparseArray;
+
+import java.io.File;
+import java.util.List;
+
+class PackageSettingBuilder {
+    private String mName;
+    private String mRealName;
+    private String mCodePath;
+    private String mResourcePath;
+    private String mLegacyNativeLibraryPathString;
+    private String mPrimaryCpuAbiString;
+    private String mSecondaryCpuAbiString;
+    private String mCpuAbiOverrideString;
+    private long mPVersionCode;
+    private int mPkgFlags;
+    private int mPrivateFlags;
+    private String mParentPackageName;
+    private List<String> mChildPackageNames;
+    private int mSharedUserId;
+    private String[] mUsesStaticLibraries;
+    private long[] mUsesStaticLibrariesVersions;
+    private String mVolumeUuid;
+    private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
+
+    public PackageSettingBuilder setName(String name) {
+        this.mName = name;
+        return this;
+    }
+
+    public PackageSettingBuilder setRealName(String realName) {
+        this.mRealName = realName;
+        return this;
+    }
+
+    public PackageSettingBuilder setCodePath(String codePath) {
+        this.mCodePath = codePath;
+        return this;
+    }
+
+    public PackageSettingBuilder setResourcePath(String resourcePath) {
+        this.mResourcePath = resourcePath;
+        return this;
+    }
+
+    public PackageSettingBuilder setLegacyNativeLibraryPathString(
+            String legacyNativeLibraryPathString) {
+        this.mLegacyNativeLibraryPathString = legacyNativeLibraryPathString;
+        return this;
+    }
+
+    public PackageSettingBuilder setPrimaryCpuAbiString(String primaryCpuAbiString) {
+        this.mPrimaryCpuAbiString = primaryCpuAbiString;
+        return this;
+    }
+
+    public PackageSettingBuilder setSecondaryCpuAbiString(String secondaryCpuAbiString) {
+        this.mSecondaryCpuAbiString = secondaryCpuAbiString;
+        return this;
+    }
+
+    public PackageSettingBuilder setCpuAbiOverrideString(String cpuAbiOverrideString) {
+        this.mCpuAbiOverrideString = cpuAbiOverrideString;
+        return this;
+    }
+
+    public PackageSettingBuilder setPVersionCode(long pVersionCode) {
+        this.mPVersionCode = pVersionCode;
+        return this;
+    }
+
+    public PackageSettingBuilder setPkgFlags(int pkgFlags) {
+        this.mPkgFlags = pkgFlags;
+        return this;
+    }
+
+    public PackageSettingBuilder setPrivateFlags(int privateFlags) {
+        this.mPrivateFlags = privateFlags;
+        return this;
+    }
+
+    public PackageSettingBuilder setParentPackageName(String parentPackageName) {
+        this.mParentPackageName = parentPackageName;
+        return this;
+    }
+
+    public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) {
+        this.mChildPackageNames = childPackageNames;
+        return this;
+    }
+
+    public PackageSettingBuilder setSharedUserId(int sharedUserId) {
+        this.mSharedUserId = sharedUserId;
+        return this;
+    }
+
+    public PackageSettingBuilder setUsesStaticLibraries(String[] usesStaticLibraries) {
+        this.mUsesStaticLibraries = usesStaticLibraries;
+        return this;
+    }
+
+    public PackageSettingBuilder setUsesStaticLibrariesVersions(
+            long[] usesStaticLibrariesVersions) {
+        this.mUsesStaticLibrariesVersions = usesStaticLibrariesVersions;
+        return this;
+    }
+
+    public PackageSettingBuilder setVolumeUuid(String volumeUuid) {
+        this.mVolumeUuid = volumeUuid;
+        return this;
+    }
+
+    public PackageSettingBuilder setInstantAppUserState(int userId, boolean isInstant) {
+        if (mUserStates.indexOfKey(userId) < 0) {
+            mUserStates.put(userId, new PackageUserState());
+        }
+        mUserStates.get(userId).instantApp = isInstant;
+        return this;
+    }
+
+    public PackageSetting build() {
+        final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
+                new File(mCodePath), new File(mResourcePath),
+                mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
+                mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
+                mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
+                mUsesStaticLibrariesVersions);
+        packageSetting.volumeUuid = this.mVolumeUuid;
+        for (int i = 0; i < mUserStates.size(); i++) {
+            packageSetting.setUserState(mUserStates.keyAt(i), mUserStates.valueAt(i));
+        }
+        return packageSetting;
+
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
new file mode 100644
index 0000000..34a3f86
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -0,0 +1,105 @@
+/*
+ * 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.content.pm.PackageParser;
+import android.os.UserHandle;
+
+class ScanRequestBuilder {
+    private final PackageParser.Package mPkg;
+    private PackageParser.Package mOldPkg;
+    private SharedUserSetting mSharedUserSetting;
+    private PackageSetting mPkgSetting;
+    private PackageSetting mDisabledPkgSetting;
+    private PackageSetting mOriginalPkgSetting;
+    private String mRealPkgName;
+    private int mParseFlags;
+    private int mScanFlags;
+    private UserHandle mUser;
+    private boolean mIsPlatformPackage;
+
+    ScanRequestBuilder(PackageParser.Package pkg) {
+        this.mPkg = pkg;
+    }
+
+    public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) {
+        this.mOldPkg = oldPkg;
+        return this;
+    }
+
+    public ScanRequestBuilder setSharedUserSetting(SharedUserSetting sharedUserSetting) {
+        this.mSharedUserSetting = sharedUserSetting;
+        return this;
+    }
+
+    public ScanRequestBuilder setPkgSetting(PackageSetting pkgSetting) {
+        this.mPkgSetting = pkgSetting;
+        return this;
+    }
+
+    public ScanRequestBuilder setDisabledPkgSetting(PackageSetting disabledPkgSetting) {
+        this.mDisabledPkgSetting = disabledPkgSetting;
+        return this;
+    }
+
+    public ScanRequestBuilder setOriginalPkgSetting(PackageSetting originalPkgSetting) {
+        this.mOriginalPkgSetting = originalPkgSetting;
+        return this;
+    }
+
+    public ScanRequestBuilder setRealPkgName(String realPkgName) {
+        this.mRealPkgName = realPkgName;
+        return this;
+    }
+
+    public ScanRequestBuilder setParseFlags(int parseFlags) {
+        this.mParseFlags = parseFlags;
+        return this;
+    }
+
+    public ScanRequestBuilder addParseFlag(int parseFlag) {
+        this.mParseFlags |= parseFlag;
+        return this;
+    }
+
+    public ScanRequestBuilder setScanFlags(int scanFlags) {
+        this.mScanFlags = scanFlags;
+        return this;
+    }
+
+    public ScanRequestBuilder addScanFlag(int scanFlag) {
+        this.mScanFlags |= scanFlag;
+        return this;
+    }
+
+    public ScanRequestBuilder setUser(UserHandle user) {
+        this.mUser = user;
+        return this;
+    }
+
+    public ScanRequestBuilder setIsPlatformPackage(boolean isPlatformPackage) {
+        this.mIsPlatformPackage = isPlatformPackage;
+        return this;
+    }
+
+    PackageManagerService.ScanRequest build() {
+        return new PackageManagerService.ScanRequest(
+                mPkg, mSharedUserSetting, mOldPkg, mPkgSetting, mDisabledPkgSetting,
+                mOriginalPkgSetting, mRealPkgName, mParseFlags, mScanFlags, mIsPlatformPackage,
+                mUser);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
new file mode 100644
index 0000000..cc70ef8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -0,0 +1,520 @@
+/*
+ * 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 android.content.pm.SharedLibraryInfo.TYPE_DYNAMIC;
+import static android.content.pm.SharedLibraryInfo.TYPE_STATIC;
+import static android.content.pm.SharedLibraryInfo.VERSION_UNDEFINED;
+
+import static com.android.server.pm.PackageManagerService.SCAN_AS_FULL_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
+import static com.android.server.pm.PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE;
+import static com.android.server.pm.PackageManagerService.SCAN_NEW_INSTALL;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.collection.IsArrayContainingInOrder.arrayContaining;
+import static org.hamcrest.core.Is.is;
+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.Mockito.when;
+
+import android.Manifest;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
+import android.platform.test.annotations.Presubmit;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.File;
+
+@RunWith(MockitoJUnitRunner.class)
+@Presubmit
+public class ScanTests {
+
+    private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
+
+    @Mock
+    PackageAbiHelper mMockPackageAbiHelper;
+    @Mock
+    UserManagerInternal mMockUserManager;
+
+    @Before
+    public void setupDefaultUser() {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+    }
+
+    @Test
+    public void newInstallSimpleAllNominal() throws Exception {
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+                        .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);
+    }
+
+    @Test
+    public void newInstallForAllUsers() throws Exception {
+        final int[] userIds = {0, 10, 11};
+        when(mMockUserManager.getUserIds()).thenReturn(userIds);
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setRealPkgName(null)
+                        .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
+                        .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+                        .build();
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        for (int uid : userIds) {
+            assertThat(scanResult.pkgSetting.readUserState(uid).installed, is(true));
+        }
+    }
+
+    @Test
+    public void installRealPackageName() throws Exception {
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setRealPkgName("com.package.real")
+                        .build();
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.pkgSetting.realName, is("com.package.real"));
+
+        final PackageManagerService.ScanRequest scanRequestNoRealPkg =
+                createBasicScanRequestBuilder(
+                        createBasicPackage(DUMMY_PACKAGE_NAME)
+                                .setRealPackageName("com.package.real").build())
+                        .build();
+
+        final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
+        assertThat(scanResultNoReal.pkgSetting.realName, nullValue());
+    }
+
+    @Test
+    public void updateSimpleNominal() throws Exception {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+        final PackageSetting pkgSetting = createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                .setPrimaryCpuAbiString("primaryCpuAbi")
+                .setSecondaryCpuAbiString("secondaryCpuAbi")
+                .build();
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
+                        .setPkgSetting(pkgSetting)
+                        .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.existingSettingCopied, is(true));
+
+        // ensure we don't overwrite the existing pkgSetting, in case something post-scan fails
+        assertNotSame(pkgSetting, scanResult.pkgSetting);
+
+        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+
+        assertThat(scanResult.pkgSetting.primaryCpuAbiString, is("primaryCpuAbi"));
+        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);
+    }
+
+    @Test
+    public void updateInstantSimpleNominal() throws Exception {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+        final PackageSetting existingPkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setInstantAppUserState(0, true)
+                        .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setPkgSetting(existingPkgSetting)
+                        .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+    }
+
+    @Test
+    public void installStaticSharedLibrary() throws Exception {
+        final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123")
+                .setStaticSharedLib("static.lib", 123L)
+                .setManifestPackageName("static.lib.pkg")
+                .setVersionCodeMajor(1)
+                .setVersionCode(234)
+                .setBaseCodePath("/some/path.apk")
+                .addSplitCodePath("/some/other/path.apk")
+                .build();
+
+        final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(
+                pkg).setUser(UserHandle.of(0)).build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.staticSharedLibraryInfo.getPackageName(), is("static.lib.pkg.123"));
+        assertThat(scanResult.staticSharedLibraryInfo.getName(), is("static.lib"));
+        assertThat(scanResult.staticSharedLibraryInfo.getLongVersion(), is(123L));
+        assertThat(scanResult.staticSharedLibraryInfo.getType(), is(TYPE_STATIC));
+        assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getPackageName(),
+                is("static.lib.pkg"));
+        assertThat(scanResult.staticSharedLibraryInfo.getDeclaringPackage().getLongVersionCode(),
+                is(pkg.getLongVersionCode()));
+        assertThat(scanResult.staticSharedLibraryInfo.getAllCodePaths(),
+                hasItems("/some/path.apk", "/some/other/path.apk"));
+        assertThat(scanResult.staticSharedLibraryInfo.getDependencies(), nullValue());
+        assertThat(scanResult.staticSharedLibraryInfo.getDependentPackages(), empty());
+    }
+
+    @Test
+    public void installDynamicLibraries() throws Exception {
+        final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg")
+                .setManifestPackageName("dynamic.lib.pkg")
+                .addLibraryName("liba")
+                .addLibraryName("libb")
+                .setVersionCodeMajor(1)
+                .setVersionCode(234)
+                .setBaseCodePath("/some/path.apk")
+                .addSplitCodePath("/some/other/path.apk")
+                .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        final SharedLibraryInfo dynamicLib0 = scanResult.dynamicSharedLibraryInfos.get(0);
+        assertThat(dynamicLib0.getPackageName(), is("dynamic.lib.pkg"));
+        assertThat(dynamicLib0.getName(), is("liba"));
+        assertThat(dynamicLib0.getLongVersion(), is((long) VERSION_UNDEFINED));
+        assertThat(dynamicLib0.getType(), is(TYPE_DYNAMIC));
+        assertThat(dynamicLib0.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+        assertThat(dynamicLib0.getDeclaringPackage().getLongVersionCode(),
+                is(pkg.getLongVersionCode()));
+        assertThat(dynamicLib0.getAllCodePaths(),
+                hasItems("/some/path.apk", "/some/other/path.apk"));
+        assertThat(dynamicLib0.getDependencies(), nullValue());
+        assertThat(dynamicLib0.getDependentPackages(), empty());
+
+        final SharedLibraryInfo dynamicLib1 = scanResult.dynamicSharedLibraryInfos.get(1);
+        assertThat(dynamicLib1.getPackageName(), is("dynamic.lib.pkg"));
+        assertThat(dynamicLib1.getName(), is("libb"));
+        assertThat(dynamicLib1.getLongVersion(), is((long) VERSION_UNDEFINED));
+        assertThat(dynamicLib1.getType(), is(TYPE_DYNAMIC));
+        assertThat(dynamicLib1.getDeclaringPackage().getPackageName(), is("dynamic.lib.pkg"));
+        assertThat(dynamicLib1.getDeclaringPackage().getLongVersionCode(),
+                is(pkg.getLongVersionCode()));
+        assertThat(dynamicLib1.getAllCodePaths(),
+                hasItems("/some/path.apk", "/some/other/path.apk"));
+        assertThat(dynamicLib1.getDependencies(), nullValue());
+        assertThat(dynamicLib1.getDependentPackages(), empty());
+    }
+
+    @Test
+    public void volumeUuidChangesOnUpdate() throws Exception {
+        final PackageSetting pkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setVolumeUuid("someUuid")
+                        .build();
+
+        final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .setApplicationInfoVolumeUuid("someNewUuid")
+                .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(
+                new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
+
+        assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid"));
+    }
+
+    @Test
+    public void scanFirstBoot_derivesAbis() throws Exception {
+        final PackageSetting pkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
+
+        final PackageParser.Package basicPackage =
+                createBasicPackage(DUMMY_PACKAGE_NAME)
+                        .setCpuAbiOVerride("testOverride")
+                        .build();
+
+
+        executeScan(new ScanRequestBuilder(basicPackage)
+                .setPkgSetting(pkgSetting)
+                .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
+                .build());
+
+        verify(mMockPackageAbiHelper).derivePackageAbi(basicPackage, "testOverride", true);
+    }
+
+    @Test
+    public void scanWithOriginalPkgSetting_packageNameChanges() throws Exception {
+        final PackageSetting originalPkgSetting =
+                createBasicPackageSettingBuilder("original.package").build();
+
+        final PackageParser.Package basicPackage =
+                createBasicPackage(DUMMY_PACKAGE_NAME)
+                        .build();
+
+
+        final PackageManagerService.ScanResult result =
+                executeScan(new ScanRequestBuilder(basicPackage)
+                        .setOriginalPkgSetting(originalPkgSetting)
+                        .build());
+
+        assertThat(result.request.pkg.packageName, is("original.package"));
+    }
+
+    @Test
+    public void updateInstant_changeToFull() throws Exception {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+        final PackageSetting existingPkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setInstantAppUserState(0, true)
+                        .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setPkgSetting(existingPkgSetting)
+                        .addScanFlag(SCAN_AS_FULL_APP)
+                        .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
+    }
+
+    @Test
+    public void updateFull_changeToInstant() throws Exception {
+        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
+
+        final PackageSetting existingPkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setInstantAppUserState(0, false)
+                        .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setPkgSetting(existingPkgSetting)
+                        .addScanFlag(SCAN_AS_INSTANT_APP)
+                        .build();
+
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, true /*isInstant*/);
+    }
+
+    @Test
+    public void updateSystemApp_applicationInfoFlagSet() throws Exception {
+        final PackageSetting existingPkgSetting =
+                createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME)
+                        .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                        .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                        .setPkgSetting(existingPkgSetting)
+                        .setDisabledPkgSetting(existingPkgSetting)
+                        .addScanFlag(SCAN_NEW_INSTALL)
+                        .build();
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.request.pkg.applicationInfo.flags,
+                hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
+    }
+
+    @Test
+    public void factoryTestFlagSet() throws Exception {
+        final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .addPermissionRequest(Manifest.permission.FACTORY_TEST)
+                .build();
+
+        final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
+                createBasicScanRequestBuilder(basicPackage).build(),
+                new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+                true /*isUnderFactoryTest*/,
+                System.currentTimeMillis());
+
+        assertThat(scanResult.request.pkg.applicationInfo.flags,
+                hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
+    }
+
+    @Test
+    public void scanSystemApp_isOrphanedTrue() throws Exception {
+        final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM)
+                .build();
+
+        final PackageManagerService.ScanRequest scanRequest =
+                createBasicScanRequestBuilder(pkg)
+                        .build();
+
+        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
+
+        assertThat(scanResult.pkgSetting.isOrphaned, is(true));
+    }
+
+    private static Matcher<Integer> hasFlag(final int flag) {
+        return new BaseMatcher<Integer>() {
+            @Override public void describeTo(Description description) {
+                description.appendText("flags ");
+            }
+
+            @Override public boolean matches(Object item) {
+                return ((int) item & flag) != 0;
+            }
+
+            @Override
+            public void describeMismatch(Object item, Description mismatchDescription) {
+                mismatchDescription
+                        .appendValue(item)
+                        .appendText(" does not contain flag ")
+                        .appendValue(flag);
+            }
+        };
+    }
+
+    private PackageManagerService.ScanResult executeScan(
+            PackageManagerService.ScanRequest scanRequest) throws PackageManagerException {
+        return PackageManagerService.scanPackageOnlyLI(
+                scanRequest,
+                new PackageManagerService.Injector(mMockUserManager, mMockPackageAbiHelper),
+                false /*isUnderFactoryTest*/,
+                System.currentTimeMillis());
+    }
+
+    private static String createResourcePath(String packageName) {
+        return "/data/app/" + packageName + "-randompath/base.apk";
+    }
+
+    private static String createCodePath(String packageName) {
+        return "/data/app/" + packageName + "-randompath";
+    }
+
+    private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) {
+        return new PackageSettingBuilder()
+                .setName(packageName)
+                .setCodePath(createCodePath(packageName))
+                .setResourcePath(createResourcePath(packageName));
+    }
+
+    private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) {
+        return new ScanRequestBuilder(pkg)
+                .setUser(UserHandle.of(0));
+    }
+
+
+    private static PackageBuilder createBasicPackage(String packageName) {
+        return new PackageBuilder(packageName)
+                .setCodePath("/data/tmp/randompath")
+                .setApplicationInfoCodePath(createCodePath(packageName))
+                .setApplicationInfoResourcePath(createResourcePath(packageName))
+                .setApplicationInfoVolumeUuid("volumeUuid")
+                .setBaseCodePath("/data/tmp/randompath/base.apk")
+                .addUsesStaticLibrary("some.static.library", 234L)
+                .addUsesStaticLibrary("some.other.static.library", 456L)
+                .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
+                .setVersionCodeMajor(1)
+                .setVersionCode(2345);
+    }
+
+    private static void assertBasicPackageScanResult(
+            PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant) {
+        assertThat(scanResult.success, is(true));
+
+        final PackageSetting pkgSetting = scanResult.pkgSetting;
+        assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
+
+        final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
+        verifyBasicApplicationInfo(scanResult, applicationInfo);
+
+    }
+
+    private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
+            String packageName, boolean isInstant, PackageSetting pkgSetting) {
+        assertThat(pkgSetting.pkg.packageName, is(packageName));
+        assertThat(pkgSetting.getInstantApp(0), is(isInstant));
+        assertThat(pkgSetting.usesStaticLibraries,
+                arrayContaining("some.static.library", "some.other.static.library"));
+        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,
+            ApplicationInfo applicationInfo) {
+        assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
+
+        final int uid = applicationInfo.uid;
+        assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
+
+        final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
+                applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
+                scanResult.request.pkg.packageName).getAbsolutePath();
+        assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
+        assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 6061d51..8c3373f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -156,7 +156,7 @@
         mService.setUsageStats(mUsageStats);
         mService.setAccessibilityManager(accessibilityManager);
         mService.mScreenOn = false;
-        mService.mInCall = false;
+        mService.mInCallStateOffHook = false;
         mService.mNotificationPulseEnabled = true;
     }
 
@@ -681,7 +681,7 @@
         mService.buzzBeepBlinkLocked(r);
         Mockito.reset(mRingtonePlayer);
 
-        mService.mInCall = true;
+        mService.mInCallStateOffHook = true;
         mService.buzzBeepBlinkLocked(r);
 
         verify(mService, times(1)).playInCallNotification();
@@ -1137,7 +1137,7 @@
 
     @Test
     public void testLightsInCall() {
-        mService.mInCall = true;
+        mService.mInCallStateOffHook = true;
         NotificationRecord r = getLightsNotification();
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index f5002ac..3b336eb 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -7,10 +7,12 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -159,4 +161,25 @@
         verify(mSliceService).removePinnedSlice(eq(TEST_URI));
         assertFalse(mPinnedSliceManager.hasPinOrListener());
     }
+
+    @Test
+    public void testPinFailed() throws Exception {
+        // Throw exception when trying to pin
+        doAnswer(invocation -> {
+            throw new Exception("Pin failed");
+        }).when(mIContentProvider).call(
+                anyString(), anyString(), anyString(), eq(null), any());
+
+        TestableLooper.get(this).processAllMessages();
+
+        // When pinned for the first time, a pinned message should be sent.
+        mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
+        TestableLooper.get(this).processAllMessages();
+
+        verify(mIContentProvider).call(anyString(), anyString(), eq(SliceProvider.METHOD_PIN),
+                eq(null), argThat(b -> {
+                    assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
+                    return true;
+                }));
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index efbae2b..7b252cb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.Process.NOBODY_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_90;
@@ -30,16 +31,22 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
+import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
+import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
 import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
+import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -54,9 +61,13 @@
 import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.PauseActivityItem;
+import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.platform.test.annotations.Presubmit;
 import android.util.MergedConfiguration;
 import android.util.MutableBoolean;
@@ -67,6 +78,7 @@
 
 import androidx.test.filters.MediumTest;
 
+import com.android.internal.R;
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Before;
@@ -194,7 +206,7 @@
     public void testRestartProcessIfVisible() {
         doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
         mActivity.visible = true;
-        mActivity.haveState = false;
+        mActivity.setSavedState(null /* savedState */);
         mActivity.setState(ActivityStack.ActivityState.RESUMED, "testRestart");
         prepareFixedAspectRatioUnresizableActivity();
 
@@ -611,6 +623,134 @@
         assertNull(mActivity.pendingOptions);
     }
 
+    @Test
+    public void testCanLaunchHomeActivityFromChooser() {
+        ComponentName chooserComponent = ComponentName.unflattenFromString(
+                Resources.getSystem().getString(R.string.config_chooserActivity));
+        ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
+                chooserComponent).build();
+        assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
+    }
+
+    /**
+     * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and
+     * that it is cleared after activity is resumed.
+     */
+    @Test
+    public void testHasSavedState() {
+        assertTrue(mActivity.hasSavedState());
+
+        ActivityRecord.activityResumedLocked(mActivity.appToken);
+        assertFalse(mActivity.hasSavedState());
+        assertNull(mActivity.getSavedState());
+    }
+
+    /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */
+    @Test
+    public void testUpdateSavedState() {
+        mActivity.setSavedState(null /* savedState */);
+        assertFalse(mActivity.hasSavedState());
+        assertNull(mActivity.getSavedState());
+
+        final Bundle savedState = new Bundle();
+        savedState.putString("test", "string");
+        mActivity.setSavedState(savedState);
+        assertTrue(mActivity.hasSavedState());
+        assertEquals(savedState, mActivity.getSavedState());
+    }
+
+    /** Verify the correct updates of saved state when activity client reports stop. */
+    @Test
+    public void testUpdateSavedState_activityStopped() {
+        final Bundle savedState = new Bundle();
+        savedState.putString("test", "string");
+        final PersistableBundle persistentSavedState = new PersistableBundle();
+        persistentSavedState.putString("persist", "string");
+
+        // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
+        mActivity.setState(STOPPING, "test");
+        mActivity.activityStoppedLocked(savedState, persistentSavedState, "desc");
+        assertTrue(mActivity.hasSavedState());
+        assertEquals(savedState, mActivity.getSavedState());
+        assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
+
+        // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
+        // states should not be overridden.
+        mActivity.setState(STOPPING, "test");
+        mActivity.activityStoppedLocked(null /* savedState */, null /* persistentSavedState */,
+                "desc");
+        assertTrue(mActivity.hasSavedState());
+        assertEquals(savedState, mActivity.getSavedState());
+        assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
+    }
+
+    /**
+     * Verify that activity finish request is not performed if activity is finishing or is in
+     * incorrect state.
+     */
+    @Test
+    public void testFinishActivityLocked_cancelled() {
+        // Mark activity as finishing
+        mActivity.finishing = true;
+        assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED,
+                mActivity.finishActivityLocked(0 /* resultCode */, null /* resultData */, "test",
+                        false /* oomAdj */));
+        assertTrue(mActivity.finishing);
+        assertTrue(mActivity.isInStackLocked());
+
+        // Remove activity from task
+        mActivity.finishing = false;
+        mActivity.setTask(null);
+        assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
+                mActivity.finishActivityLocked(0 /* resultCode */, null /* resultData */, "test",
+                        false /* oomAdj */));
+        assertFalse(mActivity.finishing);
+    }
+
+    /**
+     * Verify that activity finish request is requested, but not executed immediately if activity is
+     * not ready yet.
+     */
+    @Test
+    public void testFinishActivityLocked_requested() {
+        mActivity.finishing = false;
+        assertEquals("Currently resumed activity be paused removal", FINISH_RESULT_REQUESTED,
+                mActivity.finishActivityLocked(0 /* resultCode */, null /* resultData */, "test",
+                        false /* oomAdj */));
+        assertTrue(mActivity.finishing);
+        assertTrue(mActivity.isInStackLocked());
+
+        // First request to finish activity must schedule a "destroy" request to the client.
+        // Activity must be removed from history after the client reports back or after timeout.
+        mActivity.finishing = false;
+        mActivity.setState(STOPPED, "test");
+        assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED,
+                mActivity.finishActivityLocked(0 /* resultCode */, null /* resultData */, "test",
+                        false /* oomAdj */));
+        assertTrue(mActivity.finishing);
+        assertTrue(mActivity.isInStackLocked());
+    }
+
+    /**
+     * Verify that activity finish request removes activity immediately if it's ready.
+     */
+    @Test
+    public void testFinishActivityLocked_removed() {
+        // Prepare the activity record to be ready for immediate removal. It should be invisible and
+        // have no process. Otherwise, request to finish it will send a message to client first.
+        mActivity.setState(STOPPED, "test");
+        mActivity.visible = false;
+        mActivity.nowVisible = false;
+        // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
+        // this will cause NPE when updating task's process.
+        mActivity.app = null;
+        assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED,
+                mActivity.finishActivityLocked(0 /* resultCode */, null /* resultData */, "test",
+                        false /* oomAdj */));
+        assertTrue(mActivity.finishing);
+        assertFalse(mActivity.isInStackLocked());
+    }
+
     /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
     private void prepareFixedAspectRatioUnresizableActivity() {
         setupDisplayContentForCompatDisplayInsets();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index bde0ef6..e5278d8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.Activity.RESULT_CANCELED;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -892,7 +893,7 @@
         firstActivity.app = null;
 
         // second activity will be immediately removed as it has no state.
-        secondActivity.haveState = false;
+        secondActivity.setSavedState(null /* savedState */);
 
         assertEquals(2, mTask.mActivities.size());
 
@@ -908,7 +909,7 @@
 
         activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
         activity.launchCount = 1;
-        activity.haveState = false;
+        activity.setSavedState(null /* savedState */);
 
         mStack.handleAppDiedLocked(activity.app);
 
@@ -922,7 +923,7 @@
 
         activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
         activity.launchCount = 3;
-        activity.haveState = false;
+        activity.setSavedState(null /* savedState */);
 
         mStack.handleAppDiedLocked(activity.app);
 
@@ -936,7 +937,7 @@
 
         activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
         activity.launchCount = 1;
-        activity.haveState = false;
+        activity.setSavedState(null /* savedState */);
 
         mStack.handleAppDiedLocked(activity.app);
 
@@ -950,7 +951,7 @@
 
         activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
         activity.launchCount = 3;
-        activity.haveState = false;
+        activity.setSavedState(null /* savedState */);
 
         mStack.handleAppDiedLocked(activity.app);
 
@@ -969,7 +970,7 @@
         homeStask.removeTask(homeTask, "testAdjustFocusedStack", REMOVE_TASK_MODE_DESTROYING);
 
         // Finish the only activity.
-        mStack.finishActivityLocked(topActivity, 0 /* resultCode */, null /* resultData */,
+        topActivity.finishActivityLocked(RESULT_CANCELED /* resultCode */, null /* resultData */,
                 "testAdjustFocusedStack", false /* oomAdj */);
         // Although home stack is empty, it should still be the focused stack.
         assertEquals(homeStask, mDefaultDisplay.getFocusedStack());
@@ -1014,7 +1015,7 @@
         assertNotNull(activity);
         activity.setState(PAUSED, "finishCurrentActivity");
         activity.makeFinishingLocked();
-        stack.finishCurrentActivityLocked(activity, ActivityStack.FINISH_AFTER_VISIBLE,
+        activity.finishCurrentActivityLocked(ActivityRecord.FINISH_AFTER_VISIBLE,
                 false /* oomAdj */, "finishCurrentActivity");
         return activity;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 1684f97..6a3c81a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -32,6 +32,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -49,10 +50,12 @@
 import static org.mockito.Mockito.when;
 
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.Surface;
 import android.view.WindowManager;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -273,4 +276,37 @@
         win.mHasSurface = true;
         return win;
     }
+
+    @Test
+    @FlakyTest(bugId = 131005232)
+    public void testOverlappingWithNavBar() {
+        final WindowState targetWin = createApplicationWindow();
+        final WindowFrames winFrame = targetWin.getWindowFrames();
+        winFrame.mFrame.set(new Rect(100, 100, 200, 200));
+
+        final WindowState navigationBar = createNavigationBarWindow();
+
+        navigationBar.getFrameLw().set(new Rect(100, 200, 200, 300));
+
+        assertFalse("Freeform is overlapping with navigation bar",
+                DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
+
+        winFrame.mFrame.set(new Rect(100, 101, 200, 201));
+        assertTrue("Freeform should be overlapping with navigation bar (bottom)",
+                DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
+
+        winFrame.mFrame.set(new Rect(99, 200, 199, 300));
+        assertTrue("Freeform should be overlapping with navigation bar (right)",
+                DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
+
+        winFrame.mFrame.set(new Rect(199, 200, 299, 300));
+        assertTrue("Freeform should be overlapping with navigation bar (left)",
+                DisplayPolicy.isOverlappingWithNavBar(targetWin, navigationBar));
+    }
+
+    private WindowState createNavigationBarWindow() {
+        final WindowState win = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
+        win.mHasSurface = true;
+        return win;
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index a735b09..2933b4a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -102,7 +102,8 @@
         mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs, Binder.getCallingPid(),
                 Binder.getCallingUid());
         assertEquals(WindowManagerGlobal.ADD_OKAY,
-                mDisplayPolicy.prepareAddWindowLw(win, win.mAttrs));
+                mDisplayPolicy.validateAddingWindowLw(win.mAttrs));
+        mDisplayPolicy.addWindowLw(win, win.mAttrs);
         win.mHasSurface = true;
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 2bffc16..bfede51 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -23,7 +23,6 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeastOnce;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -624,11 +623,8 @@
         assertFalse(dc.mWaitingForConfig);
 
         // Notify WM that the displays are ready and check that they are reconfigured.
-        spyOn(mWm);
         mWm.displayReady();
         waitUntilHandlersIdle();
-        verify(mWm, atLeastOnce()).reconfigureDisplayLocked(eq(mPrimaryDisplay));
-        verify(mWm, atLeastOnce()).reconfigureDisplayLocked(eq(dc));
 
         final Configuration config = new Configuration();
         mPrimaryDisplay.computeScreenConfiguration(config);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 26cd63c..cd292b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -25,6 +25,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
@@ -35,10 +36,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 
 import android.os.Binder;
@@ -79,6 +82,7 @@
             // Hold the lock to protect the stubbing from being accessed by other threads.
             spyOn(mWm.mRoot);
             doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+            doReturn(mDisplayContent).when(mWm.mRoot).getDisplayContent(anyInt());
         }
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
@@ -135,7 +139,7 @@
         hiddenAppWindow.setHidden(true);
         mDisplayContent.getConfiguration().windowConfiguration.setRotation(
                 mDisplayContent.getRotation());
-        mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+        mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
 
         // Ensure that we are animating the target activity as well
         assertTrue(mController.isAnimatingTask(homeAppWindow.getTask()));
@@ -144,7 +148,7 @@
     }
 
     @Test
-    public void testCancelAnimationWithScreenShot() throws Exception {
+    public void testDeferCancelAnimation() throws Exception {
         mWm.setRecentsAnimationController(mController);
         final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -156,8 +160,31 @@
         mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
         assertTrue(mController.isAnimatingTask(appWindow.getTask()));
 
-        mController.setCancelWithDeferredScreenshotLocked(true);
-        mController.cancelAnimationWithScreenShot();
+        mController.setDeferredCancel(true /* deferred */, false /* screenshot */);
+        mController.cancelAnimationWithScreenshot(false /* screenshot */);
+        verify(mMockRunner).onAnimationCanceled(false /* deferredWithScreenshot */);
+        assertNull(mController.mRecentScreenshotAnimator);
+
+        // Simulate the app transition finishing
+        mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0, 0, 0);
+        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
+    }
+
+    @Test
+    public void testDeferCancelAnimationWithScreenShot() throws Exception {
+        mWm.setRecentsAnimationController(mController);
+        final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+        appWindow.addWindow(win1);
+        assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow);
+        assertEquals(appWindow.findMainWindow(), win1);
+
+        mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
+        assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+
+        mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
+        mController.cancelAnimationWithScreenshot(true /* screenshot */);
         verify(mMockRunner).onAnimationCanceled(true /* deferredWithScreenshot */);
         assertNotNull(mController.mRecentScreenshotAnimator);
         assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
@@ -185,7 +212,7 @@
 
         // Assume appWindow transition should animate when no
         // IRecentsAnimationController#setCancelWithDeferredScreenshot called.
-        assertFalse(mController.shouldCancelWithDeferredScreenshot());
+        assertFalse(mController.shouldDeferCancelWithScreenshot());
         assertTrue(appWindow.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 9630b7d..0e119e3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -274,12 +274,13 @@
 
         // Assume recents animation already started, set a state that cancel recents animation
         // with screenshot.
-        doReturn(true).when(mRecentsAnimationController).shouldCancelWithDeferredScreenshot();
+        doReturn(true).when(mRecentsAnimationController).shouldDeferCancelUntilNextTransition();
+        doReturn(true).when(mRecentsAnimationController).shouldDeferCancelWithScreenshot();
         // Start another fullscreen activity.
         fullscreenStack2.moveToFront("Activity start");
 
-        // Ensure that the recents animation was canceled by cancelOnNextTransitionStart().
-        verify(mRecentsAnimationController, times(1)).cancelOnNextTransitionStart();
+        // Ensure that the recents animation was canceled by setCancelOnNextTransitionStart().
+        verify(mRecentsAnimationController, times(1)).setCancelOnNextTransitionStart();
     }
 
     @Test
@@ -315,7 +316,7 @@
         // Ensure that the recents animation was NOT canceled
         verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously(
                 eq(REORDER_KEEP_IN_PLACE), any());
-        verify(mRecentsAnimationController, times(0)).cancelOnNextTransitionStart();
+        verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart();
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index d0ee634..df7c9a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -177,7 +177,9 @@
         final Display display = mWindowManagerService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
         // Display creation is driven by the ActivityManagerService via
         // ActivityStackSupervisor. We emulate those steps here.
-        mWindowManagerService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
+        DisplayContent displayContent = mWindowManagerService.mRoot
+                .createDisplayContent(display, mock(ActivityDisplay.class));
+        displayContent.reconfigureDisplayLocked();
 
         mMockTracker.stopTracking();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 0ecd878..a0302f6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -16,11 +16,13 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -29,6 +31,9 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.hamcrest.Matchers.not;
@@ -36,6 +41,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -51,6 +57,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.DisplayMetrics;
@@ -443,6 +450,342 @@
                 task.isSameIntentFilter(defaultActivity));
     }
 
+    /** Test that root activity index is reported correctly for several activities in the task. */
+    @Test
+    public void testFindRootIndex() {
+        final TaskRecord task = getTestTask();
+        // Add an extra activity on top of the root one
+        new ActivityBuilder(mService).setTask(task).build();
+
+        assertEquals("The root activity in the task must be reported.",
+                0, task.findRootIndex(false /* effectiveRoot*/));
+    }
+
+    /**
+     * Test that root activity index is reported correctly for several activities in the task when
+     * the activities on the bottom are finishing.
+     */
+    @Test
+    public void testFindRootIndex_finishing() {
+        final TaskRecord task = getTestTask();
+        // Add extra two activities and mark the two on the bottom as finishing.
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.finishing = true;
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        activity1.finishing = true;
+        new ActivityBuilder(mService).setTask(task).build();
+
+        assertEquals("The first non-finishing activity in the task must be reported.",
+                2, task.findRootIndex(false /* effectiveRoot*/));
+    }
+
+    /**
+     * Test that root activity index is reported correctly for several activities in the task when
+     * looking for the 'effective root'.
+     */
+    @Test
+    public void testFindRootIndex_effectiveRoot() {
+        final TaskRecord task = getTestTask();
+        // Add an extra activity on top of the root one
+        new ActivityBuilder(mService).setTask(task).build();
+
+        assertEquals("The root activity in the task must be reported.",
+                0, task.findRootIndex(true /* effectiveRoot*/));
+    }
+
+    /**
+     * Test that root activity index is reported correctly when looking for the 'effective root' in
+     * case when bottom activities are relinquishing task identity or finishing.
+     */
+    @Test
+    public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() {
+        final TaskRecord task = getTestTask();
+        // Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
+        // one above as finishing.
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        activity1.finishing = true;
+        new ActivityBuilder(mService).setTask(task).build();
+
+        assertEquals("The first non-finishing activity and non-relinquishing task identity "
+                        + "must be reported.", 2, task.findRootIndex(true /* effectiveRoot*/));
+    }
+
+    /**
+     * Test that root activity index is reported correctly when looking for the 'effective root'
+     * for the case when there is only a single activity that also has relinquishTaskIdentity set.
+     */
+    @Test
+    public void testFindRootIndex_effectiveRoot_relinquishingAndSingleActivity() {
+        final TaskRecord task = getTestTask();
+        // Set relinquishTaskIdentity for the only activity in the task
+        task.getChildAt(0).info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+
+        assertEquals("The root activity in the task must be reported.",
+                0, task.findRootIndex(true /* effectiveRoot*/));
+    }
+
+    /**
+     * Test that the topmost activity index is reported correctly when looking for the
+     * 'effective root' for the case when all activities have relinquishTaskIdentity set.
+     */
+    @Test
+    public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
+        final TaskRecord task = getTestTask();
+        // Set relinquishTaskIdentity for all activities in the task
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+
+        assertEquals("The topmost activity in the task must be reported.",
+                task.getChildCount() - 1, task.findRootIndex(true /* effectiveRoot*/));
+    }
+
+    /** Test that bottom-most activity is reported in {@link TaskRecord#getRootActivity()}. */
+    @Test
+    public void testGetRootActivity() {
+        final TaskRecord task = getTestTask();
+        // Add an extra activity on top of the root one
+        new ActivityBuilder(mService).setTask(task).build();
+
+        assertEquals("The root activity in the task must be reported.",
+                task.getChildAt(0), task.getRootActivity());
+    }
+
+    /**
+     * Test that first non-finishing activity is reported in {@link TaskRecord#getRootActivity()}.
+     */
+    @Test
+    public void testGetRootActivity_finishing() {
+        final TaskRecord task = getTestTask();
+        // Add an extra activity on top of the root one
+        new ActivityBuilder(mService).setTask(task).build();
+        // Mark the root as finishing
+        task.getChildAt(0).finishing = true;
+
+        assertEquals("The first non-finishing activity in the task must be reported.",
+                task.getChildAt(1), task.getRootActivity());
+    }
+
+    /**
+     * Test that relinquishTaskIdentity flag is ignored in {@link TaskRecord#getRootActivity()}.
+     */
+    @Test
+    public void testGetRootActivity_relinquishTaskIdentity() {
+        final TaskRecord task = getTestTask();
+        // Mark the bottom-most activity with FLAG_RELINQUISH_TASK_IDENTITY.
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+        // Add an extra activity on top of the root one.
+        new ActivityBuilder(mService).setTask(task).build();
+
+        assertEquals("The root activity in the task must be reported.",
+                task.getChildAt(0), task.getRootActivity());
+    }
+
+    /**
+     * Test that no activity is reported in {@link TaskRecord#getRootActivity()} when all activities
+     * in the task are finishing.
+     */
+    @Test
+    public void testGetRootActivity_allFinishing() {
+        final TaskRecord task = getTestTask();
+        // Mark the bottom-most activity as finishing.
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.finishing = true;
+        // Add an extra activity on top of the root one and mark it as finishing
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        activity1.finishing = true;
+
+        assertNull("No activity must be reported if all are finishing", task.getRootActivity());
+    }
+
+    /**
+     * Test that first non-finishing activity is the root of task.
+     */
+    @Test
+    public void testIsRootActivity() {
+        final TaskRecord task = getTestTask();
+        // Mark the bottom-most activity as finishing.
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.finishing = true;
+        // Add an extra activity on top of the root one.
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+
+        assertFalse("Finishing activity must not be the root of task", activity0.isRootOfTask());
+        assertTrue("Non-finishing activity must be the root of task", activity1.isRootOfTask());
+    }
+
+    /**
+     * Test that if all activities in the task are finishing, then the one on the bottom is the
+     * root of task.
+     */
+    @Test
+    public void testIsRootActivity_allFinishing() {
+        final TaskRecord task = getTestTask();
+        // Mark the bottom-most activity as finishing.
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.finishing = true;
+        // Add an extra activity on top of the root one and mark it as finishing
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        activity1.finishing = true;
+
+        assertTrue("Bottom activity must be the root of task", activity0.isRootOfTask());
+        assertFalse("Finishing activity on top must not be the root of task",
+                activity1.isRootOfTask());
+    }
+
+    /**
+     * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)}.
+     */
+    @Test
+    public void testGetTaskForActivity() {
+        final TaskRecord task0 = getTestTask();
+        final ActivityRecord activity0 = task0.getChildAt(0);
+
+        final TaskRecord task1 = getTestTask();
+        final ActivityRecord activity1 = task0.getChildAt(0);
+
+        assertEquals(task0.taskId,
+                ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
+        assertEquals(task1.taskId,
+                ActivityRecord.getTaskForActivityLocked(activity1.appToken,  false /* onlyRoot */));
+    }
+
+    /**
+     * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with finishing
+     * activity.
+     */
+    @Test
+    public void testGetTaskForActivity_onlyRoot_finishing() {
+        final TaskRecord task = getTestTask();
+        // Make the current root activity finishing
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.finishing = true;
+        // Add an extra activity on top - this will be the new root
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        // Add one more on top
+        final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+
+        assertEquals(task.taskId,
+                ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
+        assertEquals(task.taskId,
+                ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
+        assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
+                ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
+    }
+
+    /**
+     * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with activity that
+     * relinquishes task identity.
+     */
+    @Test
+    public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
+        final TaskRecord task = getTestTask();
+        // Make the current root activity relinquish task identity
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+        // Add an extra activity on top - this will be the new root
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        // Add one more on top
+        final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+
+        assertEquals(task.taskId,
+                ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
+        assertEquals(task.taskId,
+                ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
+        assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
+                ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
+    }
+
+    /**
+     * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} allowing non-root
+     * entries.
+     */
+    @Test
+    public void testGetTaskForActivity_notOnlyRoot() {
+        final TaskRecord task = getTestTask();
+        // Mark the bottom-most activity as finishing.
+        final ActivityRecord activity0 = task.getChildAt(0);
+        activity0.finishing = true;
+
+        // Add an extra activity on top of the root one and make it relinquish task identity
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+
+        // Add one more activity on top
+        final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+
+        assertEquals(task.taskId,
+                ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
+        assertEquals(task.taskId,
+                ActivityRecord.getTaskForActivityLocked(activity1.appToken, false /* onlyRoot */));
+        assertEquals(task.taskId,
+                ActivityRecord.getTaskForActivityLocked(activity2.appToken, false /* onlyRoot */));
+    }
+
+    /**
+     * Test {@link TaskRecord#updateEffectiveIntent()}.
+     */
+    @Test
+    public void testUpdateEffectiveIntent() {
+        // Test simple case with a single activity.
+        final TaskRecord task = getTestTask();
+        final ActivityRecord activity0 = task.getChildAt(0);
+
+        spyOn(task);
+        task.updateEffectiveIntent();
+        verify(task).setIntent(eq(activity0));
+    }
+
+    /**
+     * Test {@link TaskRecord#updateEffectiveIntent()} with root activity marked as finishing. This
+     * should make the task use the second activity when updating the intent.
+     */
+    @Test
+    public void testUpdateEffectiveIntent_rootFinishing() {
+        // Test simple case with a single activity.
+        final TaskRecord task = getTestTask();
+        final ActivityRecord activity0 = task.getChildAt(0);
+        // Mark the bottom-most activity as finishing.
+        activity0.finishing = true;
+        // Add an extra activity on top of the root one
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+
+        spyOn(task);
+        task.updateEffectiveIntent();
+        verify(task).setIntent(eq(activity1));
+    }
+
+    /**
+     * Test {@link TaskRecord#updateEffectiveIntent()} when all activities are finishing or
+     * relinquishing task identity. In this case the root activity should still be used when
+     * updating the intent (legacy behavior).
+     */
+    @Test
+    public void testUpdateEffectiveIntent_allFinishing() {
+        // Test simple case with a single activity.
+        final TaskRecord task = getTestTask();
+        final ActivityRecord activity0 = task.getChildAt(0);
+        // Mark the bottom-most activity as finishing.
+        activity0.finishing = true;
+        // Add an extra activity on top of the root one and make it relinquish task identity
+        final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+        activity1.finishing = true;
+
+        // Task must still update the intent using the root activity (preserving legacy behavior).
+        spyOn(task);
+        task.updateEffectiveIntent();
+        verify(task).setIntent(eq(activity0));
+    }
+
+    private TaskRecord getTestTask() {
+        final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
+        return stack.getChildAt(0);
+    }
+
     private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
             Rect expectedConfigBounds) {
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index f958867..b29453a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -64,6 +64,7 @@
         assertTrueForFiles(files, File::exists, " must exist");
         final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* reduced */);
         assertNotNull(snapshot);
+        assertEquals(MOCK_SNAPSHOT_ID, snapshot.getId());
         assertEquals(TEST_INSETS, snapshot.getContentInsets());
         assertNotNull(snapshot.getSnapshot());
         assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index e004cd3..f749622 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -45,6 +45,7 @@
 
     private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
     static final File FILES_DIR = getInstrumentation().getTargetContext().getFilesDir();
+    static final long MOCK_SNAPSHOT_ID = 12345678;
 
     TaskSnapshotPersister mPersister;
     TaskSnapshotLoader mLoader;
@@ -129,7 +130,7 @@
             Canvas c = buffer.lockCanvas();
             c.drawColor(Color.RED);
             buffer.unlockCanvasAndPost(c);
-            return new TaskSnapshot(new ComponentName("", ""), buffer,
+            return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""), buffer,
                     ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, TEST_INSETS,
                     mReducedResolution, mScale, mIsRealSnapshot,
                     mWindowingMode, mSystemUiVisibility, mIsTranslucent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 4ca01ec..74db820 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -64,7 +64,9 @@
             int windowFlags, Rect taskBounds) {
         final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888,
                 GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER);
-        final TaskSnapshot snapshot = new TaskSnapshot(new ComponentName("", ""), buffer,
+        final TaskSnapshot snapshot = new TaskSnapshot(
+                System.currentTimeMillis(),
+                new ComponentName("", ""), buffer,
                 ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, contentInsets, false,
                 1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
                 0 /* systemUiVisibility */, false /* isTranslucent */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 1b57c79..36698ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -302,43 +302,38 @@
 
     @Test
     public void testPrepareWindowToDisplayDuringRelayout() {
-        testPrepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        testPrepareWindowToDisplayDuringRelayout(true /*wasVisible*/);
-
-        // Call prepareWindowToDisplayDuringRelayout for a window without FLAG_TURN_SCREEN_ON
-        // before calling prepareWindowToDisplayDuringRelayout for windows with flag in the same
-        // appWindowToken.
+        // Call prepareWindowToDisplayDuringRelayout for a window without FLAG_TURN_SCREEN_ON before
+        // calling setCurrentLaunchCanTurnScreenOn for windows with flag in the same appWindowToken.
         final AppWindowToken appWindowToken = createAppWindowToken(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         final WindowState first = createWindow(null, TYPE_APPLICATION, appWindowToken, "first");
         final WindowState second = createWindow(null, TYPE_APPLICATION, appWindowToken, "second");
         second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 
-        reset(sPowerManagerWrapper);
-        first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
-        assertTrue(appWindowToken.canTurnScreenOn());
-
-        reset(sPowerManagerWrapper);
-        second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
-        assertFalse(appWindowToken.canTurnScreenOn());
+        testPrepareWindowToDisplayDuringRelayout(first, false /* expectedWakeupCalled */,
+                true /* expectedCurrentLaunchCanTurnScreenOn */);
+        testPrepareWindowToDisplayDuringRelayout(second, true /* expectedWakeupCalled */,
+                false /* expectedCurrentLaunchCanTurnScreenOn */);
 
         // Call prepareWindowToDisplayDuringRelayout for two window that have FLAG_TURN_SCREEN_ON
         // from the same appWindowToken. Only one should trigger the wakeup.
-        appWindowToken.setCanTurnScreenOn(true);
+        appWindowToken.setCurrentLaunchCanTurnScreenOn(true);
         first.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
         second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 
-        reset(sPowerManagerWrapper);
-        first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
-        assertFalse(appWindowToken.canTurnScreenOn());
+        testPrepareWindowToDisplayDuringRelayout(first, true /* expectedWakeupCalled */,
+                false /* expectedCurrentLaunchCanTurnScreenOn */);
+        testPrepareWindowToDisplayDuringRelayout(second, false /* expectedWakeupCalled */,
+                false /* expectedCurrentLaunchCanTurnScreenOn */);
 
-        reset(sPowerManagerWrapper);
-        second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
-        assertFalse(appWindowToken.canTurnScreenOn());
+        // Without window flags, the state of ActivityRecord.canTurnScreenOn should still be able to
+        // turn on the screen.
+        appWindowToken.setCurrentLaunchCanTurnScreenOn(true);
+        first.mAttrs.flags &= ~WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
+        doReturn(true).when(appWindowToken.mActivityRecord).canTurnScreenOn();
+
+        testPrepareWindowToDisplayDuringRelayout(first, true /* expectedWakeupCalled */,
+                false /* expectedCurrentLaunchCanTurnScreenOn */);
 
         // Call prepareWindowToDisplayDuringRelayout for a windows that are not children of an
         // appWindowToken. Both windows have the FLAG_TURNS_SCREEN_ON so both should call wakeup
@@ -360,6 +355,22 @@
         verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
     }
 
+    private void testPrepareWindowToDisplayDuringRelayout(WindowState appWindow,
+            boolean expectedWakeupCalled, boolean expectedCurrentLaunchCanTurnScreenOn) {
+        reset(sPowerManagerWrapper);
+        appWindow.prepareWindowToDisplayDuringRelayout(false /* wasVisible */);
+
+        if (expectedWakeupCalled) {
+            verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
+        } else {
+            verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
+        }
+        // If wakeup is expected to be called, the currentLaunchCanTurnScreenOn should be false
+        // because the state will be consumed.
+        assertThat(appWindow.mAppToken.currentLaunchCanTurnScreenOn(),
+                is(expectedCurrentLaunchCanTurnScreenOn));
+    }
+
     @Test
     public void testCanAffectSystemUiFlags() {
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
@@ -487,15 +498,6 @@
         assertThat(app.getWmDisplayCutout().getDisplayCutout(), is(cutout.inset(7, 10, 5, 20)));
     }
 
-    private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) {
-        reset(sPowerManagerWrapper);
-        final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
-        root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
-
-        root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
-    }
-
     @Test
     public void testVisibilityChangeSwitchUser() {
         final WindowState window = createWindow(null, TYPE_APPLICATION, "app");
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 3a702cb9..dc461d1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -435,7 +435,9 @@
             // Display creation is driven by DisplayWindowController via ActivityStackSupervisor.
             // We skip those steps here.
             final ActivityDisplay mockAd = mock(ActivityDisplay.class);
-            return mWm.mRoot.createDisplayContent(display, mockAd);
+            final DisplayContent displayContent = mWm.mRoot.createDisplayContent(display, mockAd);
+            displayContent.reconfigureDisplayLocked();
+            return displayContent;
         }
     }
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index 63bf7e7..3e88d93 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -44,7 +44,7 @@
 
         final long token = proto.start(IntervalStatsProto.STRINGPOOL);
         List<String> stringPool;
-        if (proto.isNextField(IntervalStatsProto.StringPool.SIZE)) {
+        if (proto.nextField(IntervalStatsProto.StringPool.SIZE)) {
             stringPool = new ArrayList(proto.readInt(IntervalStatsProto.StringPool.SIZE));
         } else {
             stringPool = new ArrayList();
@@ -66,12 +66,12 @@
 
         final long token = proto.start(fieldId);
         UsageStats stats;
-        if (proto.isNextField(IntervalStatsProto.UsageStats.PACKAGE_INDEX)) {
+        if (proto.nextField(IntervalStatsProto.UsageStats.PACKAGE_INDEX)) {
             // Fast path reading the package name index. Most cases this should work since it is
             // written first
             stats = statsOut.getOrCreateUsageStats(
                     stringPool.get(proto.readInt(IntervalStatsProto.UsageStats.PACKAGE_INDEX) - 1));
-        } else if (proto.isNextField(IntervalStatsProto.UsageStats.PACKAGE)) {
+        } else if (proto.nextField(IntervalStatsProto.UsageStats.PACKAGE)) {
             // No package index, try package name instead
             stats = statsOut.getOrCreateUsageStats(
                     proto.readString(IntervalStatsProto.UsageStats.PACKAGE));
@@ -177,7 +177,7 @@
         }
         String action = null;
         ArrayMap<String, Integer> counts;
-        if (proto.isNextField(IntervalStatsProto.UsageStats.ChooserAction.NAME)) {
+        if (proto.nextField(IntervalStatsProto.UsageStats.ChooserAction.NAME)) {
             // Fast path reading the action name. Most cases this should work since it is written
             // first
             action = proto.readString(IntervalStatsProto.UsageStats.ChooserAction.NAME);
@@ -244,7 +244,7 @@
         boolean configActive = false;
         final Configuration config = new Configuration();
         ConfigurationStats configStats;
-        if (proto.isNextField(IntervalStatsProto.Configuration.CONFIG)) {
+        if (proto.nextField(IntervalStatsProto.Configuration.CONFIG)) {
             // Fast path reading the configuration. Most cases this should work since it is
             // written first
             config.readFromProto(proto, IntervalStatsProto.Configuration.CONFIG);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 94352b2..9933756 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -104,8 +104,8 @@
     // This is an indirect indication of the microphone being open in some other application.
     private boolean mServiceDisabled = false;
 
-    // Whether we have ANY recognition (keyphrase or generic) running.
-    private boolean mRecognitionRunning = false;
+    // Whether ANY recognition (keyphrase or generic) has been requested.
+    private boolean mRecognitionRequested = false;
 
     private PowerSaveModeListener mPowerSaveModeListener;
 
@@ -252,11 +252,6 @@
                 }
             }
 
-            // Initialize power save, call active state monitoring logic.
-            if (!mRecognitionRunning) {
-                initializeTelephonyAndPowerStateListeners();
-            }
-
             // If the existing SoundModel is different (for the same UUID for Generic and same
             // keyphrase ID for voice), ensure that it is unloaded and stopped before proceeding.
             // This works for both keyphrase and generic models. This logic also ensures that a
@@ -326,8 +321,16 @@
             modelData.setRecognitionConfig(recognitionConfig);
             modelData.setSoundModel(soundModel);
 
-            return startRecognitionLocked(modelData,
+            int status = startRecognitionLocked(modelData,
                     false /* Don't notify for synchronous calls */);
+
+                                // Initialize power save, call active state monitoring logic.
+            if (status == STATUS_OK && !mRecognitionRequested) {
+                initializeTelephonyAndPowerStateListeners();
+                mRecognitionRequested = true;
+            }
+
+            return status;
         }
     }
 
@@ -450,7 +453,7 @@
             modelData.clearCallback();
             modelData.setRecognitionConfig(null);
 
-            if (!computeRecognitionRunningLocked()) {
+            if (!computeRecognitionRequestedLocked()) {
                 internalClearGlobalStateLocked();
             }
 
@@ -1196,20 +1199,20 @@
     }
 
     // Computes whether we have any recognition running at all (voice or generic). Sets
-    // the mRecognitionRunning variable with the result.
-    private boolean computeRecognitionRunningLocked() {
+    // the mRecognitionRequested variable with the result.
+    private boolean computeRecognitionRequestedLocked() {
         if (mModuleProperties == null || mModule == null) {
-            mRecognitionRunning = false;
-            return mRecognitionRunning;
+            mRecognitionRequested = false;
+            return mRecognitionRequested;
         }
         for (ModelData modelData : mModelDataMap.values()) {
-            if (modelData.isModelStarted()) {
-                mRecognitionRunning = true;
-                return mRecognitionRunning;
+            if (modelData.isRequested()) {
+                mRecognitionRequested = true;
+                return mRecognitionRequested;
             }
         }
-        mRecognitionRunning = false;
-        return mRecognitionRunning;
+        mRecognitionRequested = false;
+        return mRecognitionRequested;
     }
 
     // This class encapsulates the callbacks, state, handles and any other information that
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index e1ffb0f..b2fde54 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -33,7 +33,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.ShortcutServiceInternal;
@@ -79,6 +78,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.UiThread;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.soundtrigger.SoundTriggerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
@@ -120,10 +120,10 @@
         mUserManager = Preconditions.checkNotNull(
                 context.getSystemService(UserManager.class));
 
-        PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
-        packageManagerInternal.setVoiceInteractionPackagesProvider(
-                new PackageManagerInternal.PackagesProvider() {
+        PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
+                PermissionManagerServiceInternal.class);
+        permissionManagerInternal.setVoiceInteractionPackagesProvider(
+                new PermissionManagerServiceInternal.PackagesProvider() {
             @Override
             public String[] getPackages(int userId) {
                 mServiceStub.initForUser(userId);
diff --git a/startop/apps/test/Android.bp b/startop/apps/test/Android.bp
index 7a1678a..a4906d7 100644
--- a/startop/apps/test/Android.bp
+++ b/startop/apps/test/Android.bp
@@ -23,4 +23,5 @@
         "src/FrameLayoutInflationActivity.java",
         "src/TextViewInflationActivity.java",
     ],
+    platform_apis: true,
 }
diff --git a/startop/scripts/app_startup/app_startup_runner.py b/startop/scripts/app_startup/app_startup_runner.py
index 9a608af..7cba780 100755
--- a/startop/scripts/app_startup/app_startup_runner.py
+++ b/startop/scripts/app_startup/app_startup_runner.py
@@ -27,28 +27,40 @@
 #
 
 import argparse
-import asyncio
 import csv
 import itertools
 import os
 import sys
 import tempfile
-import time
-from typing import Any, Callable, Dict, Generic, Iterable, List, NamedTuple, TextIO, Tuple, TypeVar, Optional, Union
+from typing import Any, Callable, Iterable, List, NamedTuple, TextIO, Tuple, \
+    TypeVar, Union
+
+# 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
 
 # The following command line options participate in the combinatorial generation.
 # All other arguments have a global effect.
-_COMBINATORIAL_OPTIONS=['packages', 'readaheads', 'compiler_filters']
-_TRACING_READAHEADS=['mlock', 'fadvise']
-_FORWARD_OPTIONS={'loop_count': '--count'}
-_RUN_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'run_app_with_prefetch')
+_COMBINATORIAL_OPTIONS = ['package', 'readahead', 'compiler_filter', 'activity']
+_TRACING_READAHEADS = ['mlock', 'fadvise']
+_FORWARD_OPTIONS = {'loop_count': '--count'}
+_RUN_SCRIPT = os.path.join(os.path.dirname(os.path.realpath(__file__)),
+                           'run_app_with_prefetch.py')
 
-RunCommandArgs = NamedTuple('RunCommandArgs', [('package', str), ('readahead', str), ('compiler_filter', Optional[str])])
-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 = 2 # take the regular --timeout and multiply by 2; systrace starts up slowly.
+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
+# by 2; systrace starts up slowly.
 
-_UNLOCK_SCREEN_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'unlock_screen')
+_UNLOCK_SCREEN_SCRIPT = os.path.join(
+    os.path.dirname(os.path.realpath(__file__)), 'unlock_screen')
 
 # This must be the only mutable global variable. All other global variables are constants to avoid magic literals.
 _debug = False  # See -d/--debug flag.
@@ -56,105 +68,70 @@
 
 # Type hinting names.
 T = TypeVar('T')
-NamedTupleMeta = Callable[..., T]  # approximation of a (S : NamedTuple<T> where S() == T) metatype.
+NamedTupleMeta = Callable[
+    ..., T]  # approximation of a (S : NamedTuple<T> where S() == T) metatype.
 
 def parse_options(argv: List[str] = None):
   """Parse command line arguments and return an argparse Namespace object."""
-  parser = argparse.ArgumentParser(description="Run one or more Android applications under various settings in order to measure startup time.")
+  parser = argparse.ArgumentParser(description="Run one or more Android "
+                                               "applications under various "
+                                               "settings in order to measure "
+                                               "startup time.")
   # argparse considers args starting with - and -- optional in --help, even though required=True.
   # by using a named argument group --help will clearly say that it's required instead of optional.
   required_named = parser.add_argument_group('required named arguments')
-  required_named.add_argument('-p', '--package', action='append', dest='packages', help='package of the application', required=True)
-  required_named.add_argument('-r', '--readahead', action='append', dest='readaheads', help='which readahead mode to use', choices=('warm', 'cold', 'mlock', 'fadvise'), required=True)
+  required_named.add_argument('-p', '--package', action='append',
+                              dest='packages',
+                              help='package of the application', required=True)
+  required_named.add_argument('-r', '--readahead', action='append',
+                              dest='readaheads',
+                              help='which readahead mode to use',
+                              choices=('warm', 'cold', 'mlock', 'fadvise'),
+                              required=True)
 
   # optional arguments
   # use a group here to get the required arguments to appear 'above' the optional arguments in help.
   optional_named = parser.add_argument_group('optional named arguments')
-  optional_named.add_argument('-c', '--compiler-filter', action='append', dest='compiler_filters', help='which compiler filter to use. if omitted it does not enforce the app\'s compiler filter', choices=('speed', 'speed-profile', 'quicken'))
-  optional_named.add_argument('-s', '--simulate', dest='simulate', action='store_true', help='Print which commands will run, but don\'t run the apps')
-  optional_named.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output')
-  optional_named.add_argument('-o', '--output', dest='output', action='store', help='Write CSV output to file.')
-  optional_named.add_argument('-t', '--timeout', dest='timeout', action='store', type=int, help='Timeout after this many seconds when executing a single run.')
-  optional_named.add_argument('-lc', '--loop-count', dest='loop_count', default=1, type=int, action='store', help='How many times to loop a single run.')
-  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('-c', '--compiler-filter', action='append',
+                              dest='compiler_filters',
+                              help='which compiler filter to use. if omitted it does not enforce the app\'s compiler filter',
+                              choices=('speed', 'speed-profile', 'quicken'))
+  optional_named.add_argument('-s', '--simulate', dest='simulate',
+                              action='store_true',
+                              help='Print which commands will run, but don\'t run the apps')
+  optional_named.add_argument('-d', '--debug', dest='debug',
+                              action='store_true',
+                              help='Add extra debugging output')
+  optional_named.add_argument('-o', '--output', dest='output', action='store',
+                              help='Write CSV output to file.')
+  optional_named.add_argument('-t', '--timeout', dest='timeout', action='store',
+                              type=int, default=10,
+                              help='Timeout after this many seconds when executing a single run.')
+  optional_named.add_argument('-lc', '--loop-count', dest='loop_count',
+                              default=1, type=int, action='store',
+                              help='How many times to loop a single run.')
+  optional_named.add_argument('-in', '--inodes', dest='inodes', type=str,
+                              action='store',
+                              help='Path to inodes file (system/extras/pagecache/pagecache.py -d inodes)')
 
   return parser.parse_args(argv)
 
-# TODO: refactor this with a common library file with analyze_metrics.py
-def _debug_print(*args, **kwargs):
-  """Print the args to sys.stderr if the --debug/-d flag was passed in."""
+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:
-    print(*args, **kwargs, file=sys.stderr)
-
-def _expand_gen_repr(args):
-  """Like repr but any generator-like object has its iterator consumed
-  and then called repr on."""
-  new_args_list = []
-  for i in args:
-    # detect iterable objects that do not have their own override of __str__
-    if hasattr(i, '__iter__'):
-      to_str = getattr(i, '__str__')
-      if to_str.__objclass__ == object:
-        # the repr for a generator is just type+address, expand it out instead.
-        new_args_list.append([_expand_gen_repr([j])[0] for j in i])
-        continue
-    # normal case: uses the built-in to-string
-    new_args_list.append(i)
-  return new_args_list
-
-def _debug_print_gen(*args, **kwargs):
-  """Like _debug_print but will turn any iterable args into a list."""
-  if not _debug:
-    return
-
-  new_args_list = _expand_gen_repr(args)
-  _debug_print(*new_args_list, **kwargs)
-
-def _debug_print_nd(*args, **kwargs):
-  """Like _debug_print but will turn any NamedTuple-type args into a string."""
-  if not _debug:
-    return
-
-  new_args_list = []
-  for i in args:
-    if hasattr(i, '_field_types'):
-      new_args_list.append("%s: %s" %(i.__name__, i._field_types))
-    else:
-      new_args_list.append(i)
-
-  _debug_print(*new_args_list, **kwargs)
-
-def dict_lookup_any_key(dictionary: dict, *keys: List[Any]):
-  for k in keys:
-    if k in dictionary:
-      return dictionary[k]
-  raise KeyError("None of the keys %s were in the dictionary" %(keys))
-
-def generate_run_combinations(named_tuple: NamedTupleMeta[T], opts_dict: Dict[str, List[Optional[str]]])\
-    -> Iterable[T]:
-  """
-  Create all possible combinations given the values in opts_dict[named_tuple._fields].
-
-  :type T: type annotation for the named_tuple type.
-  :param named_tuple: named tuple type, whose fields are used to make combinations for
-  :param opts_dict: dictionary of keys to value list. keys correspond to the named_tuple fields.
-  :return: an iterable over named_tuple instances.
-  """
-  combinations_list = []
-  for k in named_tuple._fields:
-    # the key can be either singular or plural , e.g. 'package' or 'packages'
-    val = dict_lookup_any_key(opts_dict, k, k + "s")
-
-    # treat {'x': None} key value pairs as if it was [None]
-    # otherwise itertools.product throws an exception about not being able to iterate None.
-    combinations_list.append(val or [None])
-
-  _debug_print("opts_dict: ", opts_dict)
-  _debug_print_nd("named_tuple: ", named_tuple)
-  _debug_print("combinations_list: ", combinations_list)
-
-  for combo in itertools.product(*combinations_list):
-    yield named_tuple(*combo)
+    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' """
@@ -176,230 +153,26 @@
     args.append(value)
   return args
 
-def generate_group_run_combinations(run_combinations: Iterable[NamedTuple], dst_nt: NamedTupleMeta[T])\
-    -> Iterable[Tuple[T, Iterable[NamedTuple]]]:
+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 group_by_keys(src_nt):
-    src_d = src_nt._asdict()
-    # now remove the keys that aren't legal in dst.
-    for illegal_key in set(src_d.keys()) - set(dst_nt._fields):
-      if illegal_key in src_d:
-        del src_d[illegal_key]
+  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)
 
-    return dst_nt(**src_d)
-
-  for args_list_it in itertools.groupby(run_combinations, group_by_keys):
-    (group_key_value, args_it) = args_list_it
-    yield (group_key_value, args_it)
-
-class DataFrame:
-  """Table-like class for storing a 2D cells table with named columns."""
-  def __init__(self, data: Dict[str, List[object]] = {}):
-    """
-    Create a new DataFrame from a dictionary (keys = headers,
-    values = columns).
-    """
-    self._headers = [i for i in data.keys()]
-    self._rows = []
-
-    row_num = 0
-
-    def get_data_row(idx):
-      r = {}
-      for header, header_data in data.items():
-
-        if not len(header_data) > idx:
-          continue
-
-        r[header] = header_data[idx]
-
-      return r
-
-    while True:
-      row_dict = get_data_row(row_num)
-      if len(row_dict) == 0:
-        break
-
-      self._append_row(row_dict.keys(), row_dict.values())
-      row_num = row_num + 1
-
-  def concat_rows(self, other: 'DataFrame') -> None:
-    """
-    In-place concatenate rows of other into the rows of the
-    current DataFrame.
-
-    None is added in pre-existing cells if new headers
-    are introduced.
-    """
-    other_datas = other._data_only()
-
-    other_headers = other.headers
-
-    for d in other_datas:
-      self._append_row(other_headers, d)
-
-  def _append_row(self, headers: List[str], data: List[object]):
-    new_row = {k:v for k,v in zip(headers, data)}
-    self._rows.append(new_row)
-
-    for header in headers:
-      if not header in self._headers:
-        self._headers.append(header)
-
-  def __repr__(self):
-#     return repr(self._rows)
-    repr = ""
-
-    header_list = self._headers_only()
-
-    row_format = u""
-    for header in header_list:
-      row_format = row_format + u"{:>%d}" %(len(header) + 1)
-
-    repr = row_format.format(*header_list) + "\n"
-
-    for v in self._data_only():
-      repr = repr + row_format.format(*v) + "\n"
-
-    return repr
-
-  def __eq__(self, other):
-    if isinstance(other, self.__class__):
-      return self.headers == other.headers and self.data_table == other.data_table
-    else:
-      print("wrong instance", other.__class__)
-      return False
-
-  @property
-  def headers(self) -> List[str]:
-    return [i for i in self._headers_only()]
-
-  @property
-  def data_table(self) -> List[List[object]]:
-    return list(self._data_only())
-
-  @property
-  def data_table_transposed(self) -> List[List[object]]:
-    return list(self._transposed_data())
-
-  @property
-  def data_row_len(self) -> int:
-    return len(self._rows)
-
-  def data_row_at(self, idx) -> List[object]:
-    """
-    Return a single data row at the specified index (0th based).
-
-    Accepts negative indices, e.g. -1 is last row.
-    """
-    row_dict = self._rows[idx]
-    l = []
-
-    for h in self._headers_only():
-      l.append(row_dict.get(h)) # Adds None in blank spots.
-
-    return l
-
-  def copy(self) -> 'DataFrame':
-    """
-    Shallow copy of this DataFrame.
-    """
-    return self.repeat(count=0)
-
-  def repeat(self, count: int) -> 'DataFrame':
-    """
-    Returns a new DataFrame where each row of this dataframe is repeated count times.
-    A repeat of a row is adjacent to other repeats of that same row.
-    """
-    df = DataFrame()
-    df._headers = self._headers.copy()
-
-    rows = []
-    for row in self._rows:
-      for i in range(count):
-        rows.append(row.copy())
-
-    df._rows = rows
-
-    return df
-
-  def merge_data_columns(self, other: 'DataFrame'):
-    """
-    Merge self and another DataFrame by adding the data from other column-wise.
-    For any headers that are the same, data from 'other' is preferred.
-    """
-    for h in other._headers:
-      if not h in self._headers:
-        self._headers.append(h)
-
-    append_rows = []
-
-    for self_dict, other_dict in itertools.zip_longest(self._rows, other._rows):
-      if not self_dict:
-        d = {}
-        append_rows.append(d)
-      else:
-        d = self_dict
-
-      d_other = other_dict
-      if d_other:
-        for k,v in d_other.items():
-          d[k] = v
-
-    for r in append_rows:
-      self._rows.append(r)
-
-  def data_row_reduce(self, fnc) -> 'DataFrame':
-    """
-    Reduces the data row-wise by applying the fnc to each row (column-wise).
-    Empty cells are skipped.
-
-    fnc(Iterable[object]) -> object
-    fnc is applied over every non-empty cell in that column (descending row-wise).
-
-    Example:
-      DataFrame({'a':[1,2,3]}).data_row_reduce(sum) == DataFrame({'a':[6]})
-
-    Returns a new single-row DataFrame.
-    """
-    df = DataFrame()
-    df._headers = self._headers.copy()
-
-    def yield_by_column(header_key):
-      for row_dict in self._rows:
-        val = row_dict.get(header_key)
-        if val:
-          yield val
-
-    new_row_dict = {}
-    for h in df._headers:
-      cell_value = fnc(yield_by_column(h))
-      new_row_dict[h] = cell_value
-
-    df._rows = [new_row_dict]
-    return df
-
-  def _headers_only(self):
-    return self._headers
-
-  def _data_only(self):
-    row_len = len(self._rows)
-
-    for i in range(row_len):
-      yield self.data_row_at(i)
-
-  def _transposed_data(self):
-    return zip(*self._data_only())
-
-def parse_run_script_csv_file_flat(csv_file: TextIO) -> List[int]:
-  """Parse a CSV file full of integers into a flat int list."""
-  csv_reader = csv.reader(csv_file)
-  arr = []
-  for row in csv_reader:
-    for i in row:
-      if i:
-        arr.append(int(i))
-  return arr
+  return collector_passed, collector_tmp_output_file
 
 def parse_run_script_csv_file(csv_file: TextIO) -> DataFrame:
   """Parse a CSV file full of integers into a DataFrame."""
@@ -433,160 +206,52 @@
 
   return DataFrame(d)
 
-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
-
-async def _run_command(*args : List[str], timeout: Optional[int] = None) -> Tuple[int, bytes]:
-  # start child process
-  # NOTE: universal_newlines parameter is not supported
-  process = await asyncio.create_subprocess_exec(*args,
-      stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT)
-
-  script_output = b""
-
-  _debug_print("[PID]", process.pid)
-
-#hack
-#  stdout, stderr = await process.communicate()
-#  return (process.returncode, stdout)
-
-  timeout_remaining = timeout
-  time_started = time.time()
-
-  # read line (sequence of bytes ending with b'\n') asynchronously
-  while True:
-    try:
-      line = await asyncio.wait_for(process.stdout.readline(), timeout_remaining)
-      _debug_print("[STDOUT]", line)
-      script_output += line
-
-      if timeout_remaining:
-        time_elapsed = time.time() - time_started
-        timeout_remaining = timeout - time_elapsed
-    except asyncio.TimeoutError:
-      _debug_print("[TIMEDOUT] Process ", process.pid)
-
-#      if process.returncode is not None:
-#        #_debug_print("[WTF] can-write-eof?", process.stdout.can_write_eof())
-#
-#        _debug_print("[TIMEDOUT] Process already terminated")
-#        (remaining_stdout, remaining_stderr) = await process.communicate()
-#        script_output += remaining_stdout
-#
-#        code = await process.wait()
-#        return (code, script_output)
-
-      _debug_print("[TIMEDOUT] Sending SIGTERM.")
-      process.terminate()
-
-      # 1 second timeout for process to handle SIGTERM nicely.
-      try:
-       (remaining_stdout, remaining_stderr) = await asyncio.wait_for(process.communicate(), 5)
-       script_output += remaining_stdout
-      except asyncio.TimeoutError:
-        _debug_print("[TIMEDOUT] Sending SIGKILL.")
-        process.kill()
-
-      # 1 second timeout to finish with SIGKILL.
-      try:
-        (remaining_stdout, remaining_stderr) = await asyncio.wait_for(process.communicate(), 5)
-        script_output += remaining_stdout
-      except asyncio.TimeoutError:
-        # give up, this will leave a zombie process.
-        _debug_print("[TIMEDOUT] SIGKILL failed for process ", process.pid)
-        time.sleep(100)
-        #await process.wait()
-
-      return (-1, script_output)
-    else:
-      if not line: # EOF
-        break
-
-      #if process.returncode is not None:
-      #  _debug_print("[WTF] can-write-eof?", process.stdout.can_write_eof())
-      #  process.stdout.write_eof()
-
-      #if process.stdout.at_eof():
-      #  break
-
-  code = await process.wait() # wait for child process to exit
-  return (code, script_output)
-
-def execute_arbitrary_command(cmd: List[str], simulate: bool, timeout: Optional[int]) -> Tuple[bool, str]:
-  if simulate:
-    print(" ".join(cmd))
-    return (True, "")
-  else:
-    _debug_print("[EXECUTE]", cmd)
-
-    # block until either command finishes or the timeout occurs.
-    loop = asyncio.get_event_loop()
-    (return_code, script_output) = loop.run_until_complete(_run_command(*cmd, timeout=timeout))
-
-    script_output = script_output.decode() # convert bytes to str
-
-    passed = (return_code == 0)
-    _debug_print("[$?]", return_code)
-    if not passed:
-      print("[FAILED, code:%s]" %(return_code), script_output, file=sys.stderr)
-
-    return (passed, script_output)
-
-def execute_run_combos(grouped_run_combos: Iterable[Tuple[CollectorPackageInfo, Iterable[RunCommandArgs]]], simulate: bool, inodes_path: str, timeout: int, loop_count: int, need_trace: bool):
+def execute_run_combos(
+    grouped_run_combos: Iterable[Tuple[CollectorPackageInfo, Iterable[
+      run_app_with_prefetch.RunCommandArgs]]],
+    simulate: bool,
+    inodes_path: str,
+    timeout: int):
   # nothing will work if the screen isn't unlocked first.
-  execute_arbitrary_command([_UNLOCK_SCREEN_SCRIPT], simulate, timeout)
+  cmd_utils.execute_arbitrary_command([_UNLOCK_SCREEN_SCRIPT],
+                                      timeout,
+                                      simulate=simulate,
+                                      shell=False)
 
   for collector_info, run_combos in grouped_run_combos:
-    #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)
+    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)
 
-    with collector_tmp_output_file:
-      collector_passed = True
-      if need_trace:
-        collector_timeout = timeout and _COLLECTOR_TIMEOUT_MULTIPLIER * timeout
-        (collector_passed, collector_script_output) = execute_arbitrary_command(collector_cmd, simulate, collector_timeout)
-        # TODO: consider to print a ; collector wrote file to <...> into the CSV file so we know it was ran.
+      print_utils.debug_print(combos)
+      output = run_app_with_prefetch.run_test(combos)
 
-      for combos in run_combos:
-        args = as_run_command(combos)
+      yield DataFrame(dict((x, [y]) for x, y in output)) if output else None
 
-        cmd, tmp_output_file = make_script_command_with_temp_output(_RUN_SCRIPT, args, count=loop_count, input=collector_tmp_output_file.name)
-        with tmp_output_file:
-          (passed, script_output) = execute_arbitrary_command(cmd, simulate, timeout)
-          parsed_output = simulate and DataFrame({'fake_ms':[1,2,3]}) or parse_run_script_csv_file(tmp_output_file)
-          yield (passed, script_output, parsed_output)
-
-def gather_results(commands: Iterable[Tuple[bool, str, DataFrame]], key_list: List[str], value_list: List[Tuple[str, ...]]):
-  _debug_print("gather_results: key_list = ", key_list)
-#  yield key_list + ["time(ms)"]
-
+def gather_results(commands: Iterable[Tuple[DataFrame]],
+                   key_list: List[str], value_list: List[Tuple[str, ...]]):
+  print_utils.debug_print("gather_results: key_list = ", key_list)
   stringify_none = lambda s: s is None and "<none>" or s
+  #  yield key_list + ["time(ms)"]
+  for (run_result_list, values) in itertools.zip_longest(commands, value_list):
+    print_utils.debug_print("run_result_list = ", run_result_list)
+    print_utils.debug_print("values = ", values)
 
-  for ((passed, script_output, run_result_list), values) in itertools.zip_longest(commands, value_list):
-    _debug_print("run_result_list = ", run_result_list)
-    _debug_print("values = ", values)
-    if not passed:
+    if not run_result_list:
       continue
 
     # RunCommandArgs(package='com.whatever', readahead='warm', compiler_filter=None)
     # -> {'package':['com.whatever'], 'readahead':['warm'], 'compiler_filter':[None]}
-    values_dict = {k:[v] for k,v in values._asdict().items()}
+    values_dict = {}
+    for k, v in values._asdict().items():
+      if not k in key_list:
+        continue
+      values_dict[k] = [stringify_none(v)]
 
     values_df = DataFrame(values_dict)
     # project 'values_df' to be same number of rows as run_result_list.
@@ -598,7 +263,6 @@
     yield values_df
 
 def eval_and_save_to_csv(output, annotated_result_values):
-
   printed_header = False
 
   csv_writer = csv.writer(output)
@@ -610,9 +274,22 @@
       # TODO: what about when headers change?
 
     for data_row in row.data_table:
+      data_row = [d for d in data_row]
       csv_writer.writerow(data_row)
 
-    output.flush() # see the output live.
+    output.flush()  # see the output live.
+
+def coerce_to_list(opts: dict):
+  """Tranform values of the dictionary to list.
+  For example:
+  1 -> [1], None -> [None], [1,2,3] -> [1,2,3]
+  [[1],[2]] -> [[1],[2]], {1:1, 2:2} -> [{1:1, 2:2}]
+  """
+  result = {}
+  for key in opts:
+    val = opts[key]
+    result[key] = val if issubclass(type(val), list) else [val]
+  return result
 
 def main():
   global _debug
@@ -621,26 +298,34 @@
   _debug = opts.debug
   if _DEBUG_FORCE is not None:
     _debug = _DEBUG_FORCE
-  _debug_print("parsed options: ", opts)
-  need_trace = not not set(opts.readaheads).intersection(set(_TRACING_READAHEADS))
-  if need_trace and not opts.inodes:
-    print("Error: Missing -in/--inodes, required when using a readahead of %s" %(_TRACING_READAHEADS), file=sys.stderr)
-    return 1
+
+  print_utils.DEBUG = _debug
+  cmd_utils.SIMULATE = opts.simulate
+
+  print_utils.debug_print("parsed options: ", opts)
 
   output_file = opts.output and open(opts.output, 'w') or sys.stdout
 
-  combos = lambda: generate_run_combinations(RunCommandArgs, vars(opts))
-  _debug_print_gen("run combinations: ", combos())
+  combos = lambda: args_utils.generate_run_combinations(
+      run_app_with_prefetch.RunCommandArgs,
+      coerce_to_list(vars(opts)),
+      opts.loop_count)
+  print_utils.debug_print_gen("run combinations: ", combos())
 
-  grouped_combos = lambda: generate_group_run_combinations(combos(), CollectorPackageInfo)
-  _debug_print_gen("grouped run combinations: ", grouped_combos())
+  grouped_combos = lambda: args_utils.generate_group_run_combinations(combos(),
+                                                                      CollectorPackageInfo)
 
-  exec = execute_run_combos(grouped_combos(), opts.simulate, opts.inodes, opts.timeout, opts.loop_count, need_trace)
+  print_utils.debug_print_gen("grouped run combinations: ", grouped_combos())
+  exec = execute_run_combos(grouped_combos(),
+                            opts.simulate,
+                            opts.inodes,
+                            opts.timeout)
+
   results = gather_results(exec, _COMBINATORIAL_OPTIONS, combos())
+
   eval_and_save_to_csv(output_file, results)
 
-  return 0
-
+  return 1
 
 if __name__ == '__main__':
   sys.exit(main())
diff --git a/startop/scripts/app_startup/app_startup_runner_test.py b/startop/scripts/app_startup/app_startup_runner_test.py
index fd81667..9aa7014 100755
--- a/startop/scripts/app_startup/app_startup_runner_test.py
+++ b/startop/scripts/app_startup/app_startup_runner_test.py
@@ -31,18 +31,17 @@
 See also https://docs.pytest.org/en/latest/usage.html
 """
 
-# global imports
-from contextlib import contextmanager
 import io
 import shlex
 import sys
 import typing
-
-# pip imports
-import pytest
+# global imports
+from contextlib import contextmanager
 
 # local imports
 import app_startup_runner as asr
+# pip imports
+import pytest
 
 #
 # Argument Parsing Helpers
@@ -91,7 +90,8 @@
   """
   # Combine it with all of the "optional" parameters' default values.
   """
-  d = {'compiler_filters': None, 'simulate': False, 'debug': False, 'output': None, 'timeout': None, 'loop_count': 1, 'inodes': None}
+  d = {'compiler_filters': None, 'simulate': False, 'debug': False,
+       'output': None, 'timeout': 10, 'loop_count': 1, 'inodes': None}
   d.update(kwargs)
   return d
 
@@ -111,7 +111,7 @@
   in default_mock_dict_for_parsed_args.
   """
   req = "--package com.fake.package --readahead warm"
-  return parse_args("%s %s" %(req, str))
+  return parse_args("%s %s" % (req, str))
 
 def test_argparse():
   # missing arguments
@@ -124,15 +124,22 @@
   # required arguments are parsed correctly
   ad = default_dict_for_parsed_args  # assert dict
 
-  assert parse_args("--package xyz --readahead warm") == ad(packages=['xyz'], readaheads=['warm'])
-  assert parse_args("-p xyz -r warm") == ad(packages=['xyz'], readaheads=['warm'])
+  assert parse_args("--package xyz --readahead warm") == ad(packages=['xyz'],
+                                                            readaheads=['warm'])
+  assert parse_args("-p xyz -r warm") == ad(packages=['xyz'],
+                                            readaheads=['warm'])
 
-  assert parse_args("-p xyz -r warm -s") == ad(packages=['xyz'], readaheads=['warm'], simulate=True)
-  assert parse_args("-p xyz -r warm --simulate") == ad(packages=['xyz'], readaheads=['warm'], simulate=True)
+  assert parse_args("-p xyz -r warm -s") == ad(packages=['xyz'],
+                                               readaheads=['warm'],
+                                               simulate=True)
+  assert parse_args("-p xyz -r warm --simulate") == ad(packages=['xyz'],
+                                                       readaheads=['warm'],
+                                                       simulate=True)
 
   # optional arguments are parsed correctly.
   mad = default_mock_dict_for_parsed_args  # mock assert dict
-  assert parse_optional_args("--output filename.csv") == mad(output='filename.csv')
+  assert parse_optional_args("--output filename.csv") == mad(
+    output='filename.csv')
   assert parse_optional_args("-o filename.csv") == mad(output='filename.csv')
 
   assert parse_optional_args("--timeout 123") == mad(timeout=123)
@@ -145,36 +152,6 @@
   assert parse_optional_args("-in baz") == mad(inodes="baz")
 
 
-def generate_run_combinations(*args):
-  # expand out the generator values so that assert x == y works properly.
-  return [i for i in asr.generate_run_combinations(*args)]
-
-def test_generate_run_combinations():
-  blank_nd = typing.NamedTuple('Blank')
-  assert generate_run_combinations(blank_nd, {}) == [()], "empty"
-  assert generate_run_combinations(blank_nd, {'a' : ['a1', 'a2']}) == [()], "empty filter"
-  a_nd = typing.NamedTuple('A', [('a', str)])
-  assert generate_run_combinations(a_nd, {'a': None}) == [(None,)], "None"
-  assert generate_run_combinations(a_nd, {'a': ['a1', 'a2']}) == [('a1',), ('a2',)], "one item"
-  assert generate_run_combinations(a_nd,
-                                   {'a' : ['a1', 'a2'], 'b': ['b1', 'b2']}) == [('a1',), ('a2',)],\
-      "one item filter"
-  ab_nd = typing.NamedTuple('AB', [('a', str), ('b', str)])
-  assert generate_run_combinations(ab_nd,
-                                   {'a': ['a1', 'a2'],
-                                    'b': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
-                                                            ab_nd('a1', 'b2'),
-                                                            ab_nd('a2', 'b1'),
-                                                            ab_nd('a2', 'b2')],\
-      "two items"
-
-  assert generate_run_combinations(ab_nd,
-                                   {'as': ['a1', 'a2'],
-                                    'bs': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
-                                                             ab_nd('a1', 'b2'),
-                                                             ab_nd('a2', 'b1'),
-                                                             ab_nd('a2', 'b2')],\
-      "two items plural"
 
 def test_key_to_cmdline_flag():
   assert asr.key_to_cmdline_flag("abc") == "--abc"
@@ -182,138 +159,18 @@
   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)
+  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)
+  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_flat():
-  # empty file -> empty list
-  f = io.StringIO("")
-  assert asr.parse_run_script_csv_file_flat(f) == []
-
-  # common case
-  f = io.StringIO("1,2,3")
-  assert asr.parse_run_script_csv_file_flat(f) == [1,2,3]
-
-  # ignore trailing comma
-  f = io.StringIO("1,2,3,4,5,")
-  assert asr.parse_run_script_csv_file_flat(f) == [1,2,3,4,5]
-
-def test_data_frame():
-  # trivial empty data frame
-  df = asr.DataFrame()
-  assert df.headers == []
-  assert df.data_table == []
-  assert df.data_table_transposed == []
-
-  # common case, same number of values in each place.
-  df = asr.DataFrame({'TotalTime_ms':[1,2,3], 'Displayed_ms':[4,5,6]})
-  assert df.headers == ['TotalTime_ms', 'Displayed_ms']
-  assert df.data_table == [[1, 4], [2, 5], [3, 6]]
-  assert df.data_table_transposed == [(1, 2, 3), (4, 5, 6)]
-
-  # varying num values.
-  df = asr.DataFrame({'many':[1,2], 'none': []})
-  assert df.headers == ['many', 'none']
-  assert df.data_table == [[1, None], [2, None]]
-  assert df.data_table_transposed == [(1, 2), (None, None)]
-
-  df = asr.DataFrame({'many':[], 'none': [1,2]})
-  assert df.headers == ['many', 'none']
-  assert df.data_table == [[None, 1], [None, 2]]
-  assert df.data_table_transposed == [(None, None), (1, 2)]
-
-  # merge multiple data frames
-  df = asr.DataFrame()
-  df.concat_rows(asr.DataFrame())
-  assert df.headers == []
-  assert df.data_table == []
-  assert df.data_table_transposed == []
-
-  df = asr.DataFrame()
-  df2 = asr.DataFrame({'TotalTime_ms':[1,2,3], 'Displayed_ms':[4,5,6]})
-
-  df.concat_rows(df2)
-  assert df.headers == ['TotalTime_ms', 'Displayed_ms']
-  assert df.data_table == [[1, 4], [2, 5], [3, 6]]
-  assert df.data_table_transposed == [(1, 2, 3), (4, 5, 6)]
-
-  df = asr.DataFrame({'TotalTime_ms':[1,2]})
-  df2 = asr.DataFrame({'Displayed_ms':[4,5]})
-
-  df.concat_rows(df2)
-  assert df.headers == ['TotalTime_ms', 'Displayed_ms']
-  assert df.data_table == [[1, None], [2, None], [None, 4], [None, 5]]
-
-  df = asr.DataFrame({'TotalTime_ms':[1,2]})
-  df2 = asr.DataFrame({'TotalTime_ms': [3, 4], 'Displayed_ms':[5, 6]})
-
-  df.concat_rows(df2)
-  assert df.headers == ['TotalTime_ms', 'Displayed_ms']
-  assert df.data_table == [[1, None], [2, None], [3, 5], [4, 6]]
-
-  # data_row_at
-  df = asr.DataFrame({'TotalTime_ms':[1,2,3], 'Displayed_ms':[4,5,6]})
-  assert df.data_row_at(-1) == [3,6]
-  assert df.data_row_at(2) == [3,6]
-  assert df.data_row_at(1) == [2,5]
-
-  # repeat
-  df = asr.DataFrame({'TotalTime_ms':[1], 'Displayed_ms':[4]})
-  df2 = asr.DataFrame({'TotalTime_ms':[1,1,1], 'Displayed_ms':[4,4,4]})
-  assert df.repeat(3) == df2
-
-  # repeat
-  df = asr.DataFrame({'TotalTime_ms':[1,1,1], 'Displayed_ms':[4,4,4]})
-  assert df.data_row_len == 3
-  df = asr.DataFrame({'TotalTime_ms':[1,1]})
-  assert df.data_row_len == 2
-
-  # repeat
-  df = asr.DataFrame({'TotalTime_ms':[1,1,1], 'Displayed_ms':[4,4,4]})
-  assert df.data_row_len == 3
-  df = asr.DataFrame({'TotalTime_ms':[1,1]})
-  assert df.data_row_len == 2
-
-  # data_row_reduce
-  df = asr.DataFrame({'TotalTime_ms':[1,1,1], 'Displayed_ms':[4,4,4]})
-  df_sum = asr.DataFrame({'TotalTime_ms':[3], 'Displayed_ms':[12]})
-  assert df.data_row_reduce(sum) == df_sum
-
-  # merge_data_columns
-  df = asr.DataFrame({'TotalTime_ms':[1,2,3]})
-  df2 = asr.DataFrame({'Displayed_ms':[3,4,5,6]})
-
-  df.merge_data_columns(df2)
-  assert df == asr.DataFrame({'TotalTime_ms':[1,2,3], 'Displayed_ms':[3,4,5,6]})
-
-  df = asr.DataFrame({'TotalTime_ms':[1,2,3]})
-  df2 = asr.DataFrame({'Displayed_ms':[3,4]})
-
-  df.merge_data_columns(df2)
-  assert df == asr.DataFrame({'TotalTime_ms':[1,2,3], 'Displayed_ms':[3,4]})
-
-  df = asr.DataFrame({'TotalTime_ms':[1,2,3]})
-  df2 = asr.DataFrame({'TotalTime_ms':[10,11]})
-
-  df.merge_data_columns(df2)
-  assert df == asr.DataFrame({'TotalTime_ms':[10,11,3]})
-
-  df = asr.DataFrame({'TotalTime_ms':[]})
-  df2 = asr.DataFrame({'TotalTime_ms':[10,11]})
-
-  df.merge_data_columns(df2)
-  assert df == asr.DataFrame({'TotalTime_ms':[10,11]})
-
-
-
-
+    assert cmd_str == ["fake_script", "a", "b", "--count", "2", "--output",
+                       tmp_file.name]
 
 def test_parse_run_script_csv_file():
   # empty file -> empty list
diff --git a/startop/scripts/app_startup/lib/args_utils.py b/startop/scripts/app_startup/lib/args_utils.py
new file mode 100644
index 0000000..080f3b5
--- /dev/null
+++ b/startop/scripts/app_startup/lib/args_utils.py
@@ -0,0 +1,77 @@
+import itertools
+import os
+import sys
+from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, \
+    TypeVar, Optional
+
+# local import
+sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(
+    os.path.abspath(__file__)))))
+import lib.print_utils as print_utils
+
+T = TypeVar('T')
+NamedTupleMeta = Callable[
+    ..., T]  # approximation of a (S : NamedTuple<T> where S() == T) metatype.
+FilterFuncType = Callable[[NamedTuple], bool]
+
+def dict_lookup_any_key(dictionary: dict, *keys: List[Any]):
+  for k in keys:
+    if k in dictionary:
+      return dictionary[k]
+
+
+  print_utils.debug_print("None of the keys {} were in the dictionary".format(
+      keys))
+  return [None]
+
+def generate_run_combinations(named_tuple: NamedTupleMeta[T],
+                              opts_dict: Dict[str, List[Optional[object]]],
+                              loop_count: int = 1) -> Iterable[T]:
+  """
+  Create all possible combinations given the values in opts_dict[named_tuple._fields].
+
+  :type T: type annotation for the named_tuple type.
+  :param named_tuple: named tuple type, whose fields are used to make combinations for
+  :param opts_dict: dictionary of keys to value list. keys correspond to the named_tuple fields.
+  :param loop_count: number of repetitions.
+  :return: an iterable over named_tuple instances.
+  """
+  combinations_list = []
+  for k in named_tuple._fields:
+    # the key can be either singular or plural , e.g. 'package' or 'packages'
+    val = dict_lookup_any_key(opts_dict, k, k + "s")
+
+    # treat {'x': None} key value pairs as if it was [None]
+    # otherwise itertools.product throws an exception about not being able to iterate None.
+    combinations_list.append(val or [None])
+
+  print_utils.debug_print("opts_dict: ", opts_dict)
+  print_utils.debug_print_nd("named_tuple: ", named_tuple)
+  print_utils.debug_print("combinations_list: ", combinations_list)
+
+  for i in range(loop_count):
+    for combo in itertools.product(*combinations_list):
+      yield named_tuple(*combo)
+
+def filter_run_combinations(named_tuple: NamedTuple,
+                            filters: List[FilterFuncType]) -> bool:
+  for filter in filters:
+    if filter(named_tuple):
+      return False
+  return True
+
+def generate_group_run_combinations(run_combinations: Iterable[NamedTuple],
+                                    dst_nt: NamedTupleMeta[T]) \
+    -> Iterable[Tuple[T, Iterable[NamedTuple]]]:
+  def group_by_keys(src_nt):
+    src_d = src_nt._asdict()
+    # now remove the keys that aren't legal in dst.
+    for illegal_key in set(src_d.keys()) - set(dst_nt._fields):
+      if illegal_key in src_d:
+        del src_d[illegal_key]
+
+    return dst_nt(**src_d)
+
+  for args_list_it in itertools.groupby(run_combinations, group_by_keys):
+    (group_key_value, args_it) = args_list_it
+    yield (group_key_value, args_it)
diff --git a/startop/scripts/app_startup/lib/args_utils_test.py b/startop/scripts/app_startup/lib/args_utils_test.py
new file mode 100644
index 0000000..4b7e0fa
--- /dev/null
+++ b/startop/scripts/app_startup/lib/args_utils_test.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Unit tests for the args_utils.py script."""
+
+import typing
+
+import args_utils
+
+def generate_run_combinations(*args):
+  # expand out the generator values so that assert x == y works properly.
+  return [i for i in args_utils.generate_run_combinations(*args)]
+
+def test_generate_run_combinations():
+  blank_nd = typing.NamedTuple('Blank')
+  assert generate_run_combinations(blank_nd, {}, 1) == [()], "empty"
+  assert generate_run_combinations(blank_nd, {'a': ['a1', 'a2']}) == [
+    ()], "empty filter"
+  a_nd = typing.NamedTuple('A', [('a', str)])
+  assert generate_run_combinations(a_nd, {'a': None}) == [(None,)], "None"
+  assert generate_run_combinations(a_nd, {'a': ['a1', 'a2']}) == [('a1',), (
+    'a2',)], "one item"
+  assert generate_run_combinations(a_nd,
+                                   {'a': ['a1', 'a2'], 'b': ['b1', 'b2']}) == [
+           ('a1',), ('a2',)], \
+    "one item filter"
+  assert generate_run_combinations(a_nd, {'a': ['a1', 'a2']}, 2) == [('a1',), (
+    'a2',), ('a1',), ('a2',)], "one item"
+  ab_nd = typing.NamedTuple('AB', [('a', str), ('b', str)])
+  assert generate_run_combinations(ab_nd,
+                                   {'a': ['a1', 'a2'],
+                                    'b': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
+                                                            ab_nd('a1', 'b2'),
+                                                            ab_nd('a2', 'b1'),
+                                                            ab_nd('a2', 'b2')], \
+    "two items"
+
+  assert generate_run_combinations(ab_nd,
+                                   {'as': ['a1', 'a2'],
+                                    'bs': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
+                                                             ab_nd('a1', 'b2'),
+                                                             ab_nd('a2', 'b1'),
+                                                             ab_nd('a2', 'b2')], \
+    "two items plural"
diff --git a/startop/scripts/app_startup/lib/data_frame.py b/startop/scripts/app_startup/lib/data_frame.py
new file mode 100644
index 0000000..20a2308
--- /dev/null
+++ b/startop/scripts/app_startup/lib/data_frame.py
@@ -0,0 +1,201 @@
+import itertools
+from typing import Dict, List
+
+class DataFrame:
+  """Table-like class for storing a 2D cells table with named columns."""
+  def __init__(self, data: Dict[str, List[object]] = {}):
+    """
+    Create a new DataFrame from a dictionary (keys = headers,
+    values = columns).
+    """
+    self._headers = [i for i in data.keys()]
+    self._rows = []
+
+    row_num = 0
+
+    def get_data_row(idx):
+      r = {}
+      for header, header_data in data.items():
+
+        if not len(header_data) > idx:
+          continue
+
+        r[header] = header_data[idx]
+
+      return r
+
+    while True:
+      row_dict = get_data_row(row_num)
+      if len(row_dict) == 0:
+        break
+
+      self._append_row(row_dict.keys(), row_dict.values())
+      row_num = row_num + 1
+
+  def concat_rows(self, other: 'DataFrame') -> None:
+    """
+    In-place concatenate rows of other into the rows of the
+    current DataFrame.
+
+    None is added in pre-existing cells if new headers
+    are introduced.
+    """
+    other_datas = other._data_only()
+
+    other_headers = other.headers
+
+    for d in other_datas:
+      self._append_row(other_headers, d)
+
+  def _append_row(self, headers: List[str], data: List[object]):
+    new_row = {k:v for k,v in zip(headers, data)}
+    self._rows.append(new_row)
+
+    for header in headers:
+      if not header in self._headers:
+        self._headers.append(header)
+
+  def __repr__(self):
+#     return repr(self._rows)
+    repr = ""
+
+    header_list = self._headers_only()
+
+    row_format = u""
+    for header in header_list:
+      row_format = row_format + u"{:>%d}" %(len(header) + 1)
+
+    repr = row_format.format(*header_list) + "\n"
+
+    for v in self._data_only():
+      repr = repr + row_format.format(*v) + "\n"
+
+    return repr
+
+  def __eq__(self, other):
+    if isinstance(other, self.__class__):
+      return self.headers == other.headers and self.data_table == other.data_table
+    else:
+      print("wrong instance", other.__class__)
+      return False
+
+  @property
+  def headers(self) -> List[str]:
+    return [i for i in self._headers_only()]
+
+  @property
+  def data_table(self) -> List[List[object]]:
+    return list(self._data_only())
+
+  @property
+  def data_table_transposed(self) -> List[List[object]]:
+    return list(self._transposed_data())
+
+  @property
+  def data_row_len(self) -> int:
+    return len(self._rows)
+
+  def data_row_at(self, idx) -> List[object]:
+    """
+    Return a single data row at the specified index (0th based).
+
+    Accepts negative indices, e.g. -1 is last row.
+    """
+    row_dict = self._rows[idx]
+    l = []
+
+    for h in self._headers_only():
+      l.append(row_dict.get(h)) # Adds None in blank spots.
+
+    return l
+
+  def copy(self) -> 'DataFrame':
+    """
+    Shallow copy of this DataFrame.
+    """
+    return self.repeat(count=0)
+
+  def repeat(self, count: int) -> 'DataFrame':
+    """
+    Returns a new DataFrame where each row of this dataframe is repeated count times.
+    A repeat of a row is adjacent to other repeats of that same row.
+    """
+    df = DataFrame()
+    df._headers = self._headers.copy()
+
+    rows = []
+    for row in self._rows:
+      for i in range(count):
+        rows.append(row.copy())
+
+    df._rows = rows
+
+    return df
+
+  def merge_data_columns(self, other: 'DataFrame'):
+    """
+    Merge self and another DataFrame by adding the data from other column-wise.
+    For any headers that are the same, data from 'other' is preferred.
+    """
+    for h in other._headers:
+      if not h in self._headers:
+        self._headers.append(h)
+
+    append_rows = []
+
+    for self_dict, other_dict in itertools.zip_longest(self._rows, other._rows):
+      if not self_dict:
+        d = {}
+        append_rows.append(d)
+      else:
+        d = self_dict
+
+      d_other = other_dict
+      if d_other:
+        for k,v in d_other.items():
+          d[k] = v
+
+    for r in append_rows:
+      self._rows.append(r)
+
+  def data_row_reduce(self, fnc) -> 'DataFrame':
+    """
+    Reduces the data row-wise by applying the fnc to each row (column-wise).
+    Empty cells are skipped.
+
+    fnc(Iterable[object]) -> object
+    fnc is applied over every non-empty cell in that column (descending row-wise).
+
+    Example:
+      DataFrame({'a':[1,2,3]}).data_row_reduce(sum) == DataFrame({'a':[6]})
+
+    Returns a new single-row DataFrame.
+    """
+    df = DataFrame()
+    df._headers = self._headers.copy()
+
+    def yield_by_column(header_key):
+      for row_dict in self._rows:
+        val = row_dict.get(header_key)
+        if val:
+          yield val
+
+    new_row_dict = {}
+    for h in df._headers:
+      cell_value = fnc(yield_by_column(h))
+      new_row_dict[h] = cell_value
+
+    df._rows = [new_row_dict]
+    return df
+
+  def _headers_only(self):
+    return self._headers
+
+  def _data_only(self):
+    row_len = len(self._rows)
+
+    for i in range(row_len):
+      yield self.data_row_at(i)
+
+  def _transposed_data(self):
+    return zip(*self._data_only())
\ No newline at end of file
diff --git a/startop/scripts/app_startup/lib/data_frame_test.py b/startop/scripts/app_startup/lib/data_frame_test.py
new file mode 100644
index 0000000..1cbc1cb
--- /dev/null
+++ b/startop/scripts/app_startup/lib/data_frame_test.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Unit tests for the data_frame.py script."""
+
+from data_frame import DataFrame
+
+def test_data_frame():
+  # trivial empty data frame
+  df = DataFrame()
+  assert df.headers == []
+  assert df.data_table == []
+  assert df.data_table_transposed == []
+
+  # common case, same number of values in each place.
+  df = DataFrame({'TotalTime_ms': [1, 2, 3], 'Displayed_ms': [4, 5, 6]})
+  assert df.headers == ['TotalTime_ms', 'Displayed_ms']
+  assert df.data_table == [[1, 4], [2, 5], [3, 6]]
+  assert df.data_table_transposed == [(1, 2, 3), (4, 5, 6)]
+
+  # varying num values.
+  df = DataFrame({'many': [1, 2], 'none': []})
+  assert df.headers == ['many', 'none']
+  assert df.data_table == [[1, None], [2, None]]
+  assert df.data_table_transposed == [(1, 2), (None, None)]
+
+  df = DataFrame({'many': [], 'none': [1, 2]})
+  assert df.headers == ['many', 'none']
+  assert df.data_table == [[None, 1], [None, 2]]
+  assert df.data_table_transposed == [(None, None), (1, 2)]
+
+  # merge multiple data frames
+  df = DataFrame()
+  df.concat_rows(DataFrame())
+  assert df.headers == []
+  assert df.data_table == []
+  assert df.data_table_transposed == []
+
+  df = DataFrame()
+  df2 = DataFrame({'TotalTime_ms': [1, 2, 3], 'Displayed_ms': [4, 5, 6]})
+
+  df.concat_rows(df2)
+  assert df.headers == ['TotalTime_ms', 'Displayed_ms']
+  assert df.data_table == [[1, 4], [2, 5], [3, 6]]
+  assert df.data_table_transposed == [(1, 2, 3), (4, 5, 6)]
+
+  df = DataFrame({'TotalTime_ms': [1, 2]})
+  df2 = DataFrame({'Displayed_ms': [4, 5]})
+
+  df.concat_rows(df2)
+  assert df.headers == ['TotalTime_ms', 'Displayed_ms']
+  assert df.data_table == [[1, None], [2, None], [None, 4], [None, 5]]
+
+  df = DataFrame({'TotalTime_ms': [1, 2]})
+  df2 = DataFrame({'TotalTime_ms': [3, 4], 'Displayed_ms': [5, 6]})
+
+  df.concat_rows(df2)
+  assert df.headers == ['TotalTime_ms', 'Displayed_ms']
+  assert df.data_table == [[1, None], [2, None], [3, 5], [4, 6]]
+
+  # data_row_at
+  df = DataFrame({'TotalTime_ms': [1, 2, 3], 'Displayed_ms': [4, 5, 6]})
+  assert df.data_row_at(-1) == [3, 6]
+  assert df.data_row_at(2) == [3, 6]
+  assert df.data_row_at(1) == [2, 5]
+
+  # repeat
+  df = DataFrame({'TotalTime_ms': [1], 'Displayed_ms': [4]})
+  df2 = DataFrame({'TotalTime_ms': [1, 1, 1], 'Displayed_ms': [4, 4, 4]})
+  assert df.repeat(3) == df2
+
+  # repeat
+  df = DataFrame({'TotalTime_ms': [1, 1, 1], 'Displayed_ms': [4, 4, 4]})
+  assert df.data_row_len == 3
+  df = DataFrame({'TotalTime_ms': [1, 1]})
+  assert df.data_row_len == 2
+
+  # repeat
+  df = DataFrame({'TotalTime_ms': [1, 1, 1], 'Displayed_ms': [4, 4, 4]})
+  assert df.data_row_len == 3
+  df = DataFrame({'TotalTime_ms': [1, 1]})
+  assert df.data_row_len == 2
+
+  # data_row_reduce
+  df = DataFrame({'TotalTime_ms': [1, 1, 1], 'Displayed_ms': [4, 4, 4]})
+  df_sum = DataFrame({'TotalTime_ms': [3], 'Displayed_ms': [12]})
+  assert df.data_row_reduce(sum) == df_sum
+
+  # merge_data_columns
+  df = DataFrame({'TotalTime_ms': [1, 2, 3]})
+  df2 = DataFrame({'Displayed_ms': [3, 4, 5, 6]})
+
+  df.merge_data_columns(df2)
+  assert df == DataFrame(
+    {'TotalTime_ms': [1, 2, 3], 'Displayed_ms': [3, 4, 5, 6]})
+
+  df = DataFrame({'TotalTime_ms': [1, 2, 3]})
+  df2 = DataFrame({'Displayed_ms': [3, 4]})
+
+  df.merge_data_columns(df2)
+  assert df == DataFrame(
+    {'TotalTime_ms': [1, 2, 3], 'Displayed_ms': [3, 4]})
+
+  df = DataFrame({'TotalTime_ms': [1, 2, 3]})
+  df2 = DataFrame({'TotalTime_ms': [10, 11]})
+
+  df.merge_data_columns(df2)
+  assert df == DataFrame({'TotalTime_ms': [10, 11, 3]})
+
+  df = DataFrame({'TotalTime_ms': []})
+  df2 = DataFrame({'TotalTime_ms': [10, 11]})
+
+  df.merge_data_columns(df2)
+  assert df == DataFrame({'TotalTime_ms': [10, 11]})
diff --git a/startop/scripts/app_startup/query_compiler_filter.py b/startop/scripts/app_startup/query_compiler_filter.py
index dc97c66..ea14264 100755
--- a/startop/scripts/app_startup/query_compiler_filter.py
+++ b/startop/scripts/app_startup/query_compiler_filter.py
@@ -31,13 +31,15 @@
 #
 
 import argparse
-import sys
+import os
 import re
+import sys
 
 # TODO: refactor this with a common library file with analyze_metrics.py
-import app_startup_runner
-from app_startup_runner import _debug_print
-from app_startup_runner import execute_arbitrary_command
+DIR = os.path.abspath(os.path.dirname(__file__))
+sys.path.append(os.path.dirname(DIR))
+import lib.cmd_utils as cmd_utils
+import lib.print_utils as print_utils
 
 from typing import List, NamedTuple, Iterable
 
@@ -74,7 +76,11 @@
       x86: [status=quicken] [reason=install]
 """ %(package, package, package, package)
 
-  code, res = execute_arbitrary_command(['adb', 'shell', 'dumpsys', 'package', package], simulate=False, timeout=5)
+  code, res = cmd_utils.execute_arbitrary_command(['adb', 'shell', 'dumpsys',
+                                                   'package', package],
+                                                  simulate=False,
+                                                  timeout=5,
+                                                  shell=False)
   if code:
     return res
   else:
@@ -115,7 +121,7 @@
       line = str_lines[line_num]
       current_indent = get_indent_level(line)
 
-      _debug_print("INDENT=%d, LINE=%s" %(current_indent, line))
+      print_utils.debug_print("INDENT=%d, LINE=%s" %(current_indent, line))
 
       current_label = line.lstrip()
 
@@ -135,7 +141,7 @@
       break
 
   new_remainder = str_lines[line_num::]
-  _debug_print("NEW REMAINDER: ", new_remainder)
+  print_utils.debug_print("NEW REMAINDER: ", new_remainder)
 
   parse_tree = ParseTree(label, children)
   return ParseResult(new_remainder, parse_tree)
@@ -159,7 +165,7 @@
 def find_first_compiler_filter(dexopt_state: DexoptState, package: str, instruction_set: str) -> str:
   lst = find_all_compiler_filters(dexopt_state, package)
 
-  _debug_print("all compiler filters: ", lst)
+  print_utils.debug_print("all compiler filters: ", lst)
 
   for compiler_filter_info in lst:
     if not instruction_set:
@@ -180,10 +186,10 @@
   if not package_tree:
     raise AssertionError("Could not find any package subtree for package %s" %(package))
 
-  _debug_print("package tree: ", package_tree)
+  print_utils.debug_print("package tree: ", package_tree)
 
   for path_tree in find_parse_children(package_tree, "path: "):
-    _debug_print("path tree: ", path_tree)
+    print_utils.debug_print("path tree: ", path_tree)
 
     matchre = re.compile("([^:]+):\s+\[status=([^\]]+)\]\s+\[reason=([^\]]+)\]")
 
@@ -198,16 +204,16 @@
 
 def main() -> int:
   opts = parse_options()
-  app_startup_runner._debug = opts.debug
+  cmd_utils._debug = opts.debug
   if _DEBUG_FORCE is not None:
-    app_startup_runner._debug = _DEBUG_FORCE
-  _debug_print("parsed options: ", opts)
+    cmd_utils._debug = _DEBUG_FORCE
+  print_utils.debug_print("parsed options: ", opts)
 
   # Note: This can often 'fail' if the package isn't actually installed.
   package_dumpsys = remote_dumpsys_package(opts.package, opts.simulate)
-  _debug_print("package dumpsys: ", package_dumpsys)
+  print_utils.debug_print("package dumpsys: ", package_dumpsys)
   dumpsys_parse_tree = parse_tab_tree(package_dumpsys, package_dumpsys)
-  _debug_print("parse tree: ", dumpsys_parse_tree)
+  print_utils.debug_print("parse tree: ", dumpsys_parse_tree)
   dexopt_state = parse_dexopt_state(dumpsys_parse_tree)
 
   filter = find_first_compiler_filter(dexopt_state, opts.package, opts.instruction_set)
diff --git a/startop/scripts/app_startup/run_app_with_prefetch.py b/startop/scripts/app_startup/run_app_with_prefetch.py
index 052db9d..464742d 100644
--- a/startop/scripts/app_startup/run_app_with_prefetch.py
+++ b/startop/scripts/app_startup/run_app_with_prefetch.py
@@ -30,7 +30,7 @@
 import os
 import sys
 import time
-from typing import List, Tuple, Optional
+from typing import List, Tuple, Optional, NamedTuple
 
 # local imports
 import lib.adb_utils as adb_utils
@@ -47,10 +47,20 @@
 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])])
+
 def parse_options(argv: List[str] = None):
   """Parses command line arguments and return an argparse Namespace object."""
   parser = argparse.ArgumentParser(
-    description='Run an Android application once and measure startup time.'
+      description='Run an Android application once and measure startup time.'
   )
 
   required_named = parser.add_argument_group('required named arguments')
@@ -91,43 +101,44 @@
 
   return parser.parse_args(argv)
 
-def validate_options(opts: argparse.Namespace) -> bool:
+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 = (opts.readahead != 'cold' and opts.readahead != 'warm')
-  if needs_trace_file and (opts.input is None or
-                           not os.path.exists(opts.input)):
+  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
+    return False, args
 
-  if opts.simulate:
-    opts.activity = 'act'
+  if args.simulate:
+    args = args._replace(activity='act')
 
-  if not opts.activity:
-    _, opts.activity = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
-                                                'get_activity_name',
-                                                [opts.package])
+  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 opts.activity:
+  if not args.activity:
     print_utils.error_print('Activity name could not be found, '
-                              'invalid package name?!')
-    return False
+                            '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(
-      opts.package, opts.activity, opts.input)
+        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(opts.package, opts.activity))
-      return False
+                                format(args.package, args.activity))
+      return False, args
 
-  return True
+  return True, args
 
 def set_up_adb_env():
   """Sets up adb environment."""
@@ -149,17 +160,18 @@
 
   passed, current_compiler_filter_info = \
     cmd_utils.run_shell_command(
-      '{} --package {}'.format(os.path.join(DIR, 'query_compiler_filter.py'),
-                               package))
+        '{} --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(' ')
+  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))
+      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.
@@ -202,7 +214,7 @@
     print_utils.debug_print('metric: "{metric_name}", '
                             'value: "{metric_value}" '.
                               format(metric_name=metric_name,
-                                     metric_value=metric_value))
+                                   metric_value=metric_value))
 
     all_metrics.append((metric_name, metric_value))
   return all_metrics
@@ -230,7 +242,7 @@
   """
   total_time = _parse_total_time(am_start_output)
   displayed_time = adb_utils.blocking_wait_for_logcat_displayed_time(
-    pre_launch_timestamp, package, timeout)
+      pre_launch_timestamp, package, timeout)
 
   return 'TotalTime={}\nDisplayedTime={}'.format(total_time, displayed_time)
 
@@ -268,10 +280,10 @@
                                                '"{DIR}/launch_application" '
                                                '"{package}" '
                                                '"{activity}"'
-                                                .format(timeout=timeout,
-                                                        DIR=DIR,
-                                                        package=package,
-                                                        activity=activity))
+                                                 .format(timeout=timeout,
+                                                       DIR=DIR,
+                                                       package=package,
+                                                       activity=activity))
   if not passed and not simulate:
     return None
 
@@ -285,7 +297,7 @@
     results = parse_metrics_output(output, simulate)
 
   passed = perform_post_launch_cleanup(
-    readahead, package, activity, timeout, debug, pre_launch_timestamp)
+      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
@@ -306,10 +318,10 @@
   """
   if readahead != 'warm' and readahead != 'cold':
     passed = iorapd_utils.wait_for_iorapd_finish(package,
-                                               activity,
-                                               timeout,
-                                               debug,
-                                               logcat_timestamp)
+                                                 activity,
+                                                 timeout,
+                                                 debug,
+                                                 logcat_timestamp)
 
     if not passed:
       return passed
@@ -319,16 +331,16 @@
   # Don't need to do anything for warm or cold.
   return True
 
-def run_test(opts: argparse.Namespace) -> List[Tuple[str, str]]:
+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 and anything left.
+    A list of tuples that including metric name, metric value.
   """
-  print_utils.DEBUG = opts.debug
-  cmd_utils.SIMULATE = opts.simulate
+  print_utils.DEBUG = args.debug
+  cmd_utils.SIMULATE = args.simulate
 
-  passed = validate_options(opts)
+  passed, args = validate_options(args)
   if not passed:
     return None
 
@@ -337,15 +349,22 @@
   # 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(opts.compiler_filter, opts.package,
-                                   opts.activity):
+  if not configure_compiler_filter(args.compiler_filter, args.package,
+                                   args.activity):
     return None
 
-  return run(opts.readahead, opts.package, opts.activity, opts.timeout,
-             opts.simulate, opts.debug)
+  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():
-  args = parse_options()
+  opts = parse_options()
+  args = get_args_from_opts(opts)
   result = run_test(args)
 
   if result is None:
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 a642385..8536ce5 100644
--- a/startop/scripts/app_startup/run_app_with_prefetch_test.py
+++ b/startop/scripts/app_startup/run_app_with_prefetch_test.py
@@ -156,7 +156,8 @@
   args = '--package com.fake.package --activity act -s'
   opts = run.parse_options(shlex.split(args))
 
-  result = run.run_test(opts)
+  args = run.get_args_from_opts(opts)
+  result = run.run_test(args)
   assert result == [('TotalTime', '123')]
 
 def test_set_up_adb_env():
diff --git a/startop/scripts/iorap/compiler.py b/startop/scripts/iorap/compiler.py
index 7914960..a335b30 100755
--- a/startop/scripts/iorap/compiler.py
+++ b/startop/scripts/iorap/compiler.py
@@ -23,22 +23,27 @@
 # $> pip3 install --user protobuf sqlalchemy sqlite3
 #
 
-import collections
 import optparse
 import os
 import re
 import sys
+import tempfile
+from pathlib import Path
+from typing import Iterable, Optional, List
 
-from typing import Iterable
-
-from lib.inode2filename import Inode2Filename
 from generated.TraceFile_pb2 import *
+from lib.inode2filename import Inode2Filename
 
 parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-sys.path.append(parent_dir_name + "/trace_analyzer")
-from lib.trace2db import Trace2Db, MmFilemapAddToPageCache
+sys.path.append(parent_dir_name)
+from trace_analyzer.lib.trace2db import Trace2Db, MmFilemapAddToPageCache, \
+    RawFtraceEntry
+import lib.cmd_utils as cmd_utils
 
 _PAGE_SIZE = 4096 # adb shell getconf PAGESIZE ## size of a memory page in bytes.
+ANDROID_BUILD_TOP = Path(parent_dir_name).parents[3]
+TRACECONV_BIN = ANDROID_BUILD_TOP.joinpath(
+    'external/perfetto/tools/traceconv')
 
 class PageRun:
   """
@@ -165,9 +170,79 @@
 
   return trace_file
 
-def query_add_to_page_cache(trace2db: Trace2Db):
+def calc_trace_end_time(trace2db: Trace2Db,
+                        trace_duration: Optional[int]) -> float:
+  """
+  Calculates the end time based on the trace duration.
+  The start time is the first receiving mm file map event.
+  The end time is the start time plus the trace duration.
+  All of them are in milliseconds.
+  """
+  # If the duration is not set, assume all time is acceptable.
+  if trace_duration is None:
+    # float('inf')
+    return RawFtraceEntry.__table__.c.timestamp.type.python_type('inf')
+
+  first_event = trace2db.session.query(MmFilemapAddToPageCache).join(
+      MmFilemapAddToPageCache.raw_ftrace_entry).order_by(
+      RawFtraceEntry.timestamp).first()
+
+  return first_event.raw_ftrace_entry.timestamp + trace_duration
+
+def query_add_to_page_cache(trace2db: Trace2Db, trace_duration: Optional[int]):
+  end_time = calc_trace_end_time(trace2db, trace_duration)
   # SELECT * FROM tbl ORDER BY id;
-  return trace2db.session.query(MmFilemapAddToPageCache).order_by(MmFilemapAddToPageCache.id).all()
+  return trace2db.session.query(MmFilemapAddToPageCache).join(
+      MmFilemapAddToPageCache.raw_ftrace_entry).filter(
+      RawFtraceEntry.timestamp <= end_time).order_by(
+      MmFilemapAddToPageCache.id).all()
+
+def transform_perfetto_trace_to_systrace(path_to_perfetto_trace: str,
+                                         path_to_tmp_systrace: str) -> None:
+  """ Transforms the systrace file from perfetto trace. """
+  cmd_utils.run_command_nofail([str(TRACECONV_BIN),
+                                'systrace',
+                                path_to_perfetto_trace,
+                                path_to_tmp_systrace])
+
+
+def run(sql_db_path:str,
+        trace_file:str,
+        trace_duration:Optional[int],
+        output_file:str,
+        inode_table:str,
+        filter:List[str]) -> int:
+  trace2db = Trace2Db(sql_db_path)
+  # Speed optimization: Skip any entries that aren't mm_filemap_add_to_pagecache.
+  trace2db.set_raw_ftrace_entry_filter(\
+      lambda entry: entry['function'] == 'mm_filemap_add_to_page_cache')
+  # TODO: parse multiple trace files here.
+  parse_count = trace2db.parse_file_into_db(trace_file)
+
+  mm_filemap_add_to_page_cache_rows = query_add_to_page_cache(trace2db,
+                                                              trace_duration)
+  print("DONE. Parsed %d entries into sql db." %(len(mm_filemap_add_to_page_cache_rows)))
+
+  page_runs = page_cache_entries_to_runs(mm_filemap_add_to_page_cache_rows)
+  print("DONE. Converted %d entries" %(len(page_runs)))
+
+  # TODO: flags to select optimizations.
+  optimized_page_runs = optimize_page_runs(page_runs)
+  print("DONE. Optimized down to %d entries" %(len(optimized_page_runs)))
+
+  print("Build protobuf...")
+  trace_file = build_protobuf(optimized_page_runs, inode_table, filter)
+
+  print("Write protobuf to file...")
+  output_file = open(output_file, 'wb')
+  output_file.write(trace_file.SerializeToString())
+  output_file.close()
+
+  print("DONE")
+
+  # TODO: Silent running mode [no output except on error] for build runs.
+
+  return 0
 
 def main(argv):
   parser = optparse.OptionParser(usage="Usage: %prog [options]", description="Compile systrace file into TraceFile.pb")
@@ -175,6 +250,9 @@
                     help='Read cached inode data from a file saved earlier with pagecache.py -d')
   parser.add_option('-t', dest='trace_file', metavar='FILE',
                     help='Path to systrace file (trace.html) that will be parsed')
+  parser.add_option('--perfetto-trace', dest='perfetto_trace_file',
+                    metavar='FILE',
+                    help='Path to perfetto trace that will be parsed')
 
   parser.add_option('--db', dest='sql_db', metavar='FILE',
                     help='Path to intermediate sqlite3 database [default: in-memory].')
@@ -188,57 +266,51 @@
   parser.add_option('-o', dest='output_file', metavar='FILE',
                     help='Output protobuf file')
 
+  parser.add_option('--duration', dest='trace_duration', action="store",
+                    type=int, help='The duration of trace in milliseconds.')
+
   options, categories = parser.parse_args(argv[1:])
 
   # TODO: OptionParser should have some flags to make these mandatory.
   if not options.inode_data_file:
     parser.error("-i is required")
-  if not options.trace_file:
-    parser.error("-t is required")
+  if not options.trace_file and not options.perfetto_trace_file:
+    parser.error("one of -t or --perfetto-trace is required")
+  if options.trace_file and options.perfetto_trace_file:
+    parser.error("please enter either -t or --perfetto-trace, not both")
   if not options.output_file:
     parser.error("-o is required")
 
   if options.launch_lock:
     print("INFO: Launch lock flag (-l) enabled; filtering all events not inside launch_lock.")
 
-
   inode_table = Inode2Filename.new_from_filename(options.inode_data_file)
 
-  trace_file = open(options.trace_file)
-
   sql_db_path = ":memory:"
   if options.sql_db:
     sql_db_path = options.sql_db
 
-  trace2db = Trace2Db(sql_db_path)
-  # Speed optimization: Skip any entries that aren't mm_filemap_add_to_pagecache.
-  trace2db.set_raw_ftrace_entry_filter(\
-      lambda entry: entry['function'] == 'mm_filemap_add_to_page_cache')
-  # TODO: parse multiple trace files here.
-  parse_count = trace2db.parse_file_into_db(options.trace_file)
+  # if the input is systrace
+  if options.trace_file:
+    return run(sql_db_path,
+               options.trace_file,
+               options.trace_duration,
+               options.output_file,
+               inode_table,
+               options.filter)
 
-  mm_filemap_add_to_page_cache_rows = query_add_to_page_cache(trace2db)
-  print("DONE. Parsed %d entries into sql db." %(len(mm_filemap_add_to_page_cache_rows)))
+  # if the input is perfetto trace
+  # TODO python 3.7 switch to using nullcontext
+  with tempfile.NamedTemporaryFile() as trace_file:
+    transform_perfetto_trace_to_systrace(options.perfetto_trace_file,
+                                         trace_file.name)
+    return run(sql_db_path,
+               options.trace_file,
+               options.trace_duration,
+               options.output_file,
+               inode_table,
+               options.filter)
 
-  page_runs = page_cache_entries_to_runs(mm_filemap_add_to_page_cache_rows)
-  print("DONE. Converted %d entries" %(len(page_runs)))
-
-  # TODO: flags to select optimizations.
-  optimized_page_runs = optimize_page_runs(page_runs)
-  print("DONE. Optimized down to %d entries" %(len(optimized_page_runs)))
-
-  print("Build protobuf...")
-  trace_file = build_protobuf(optimized_page_runs, inode_table, options.filter)
-
-  print("Write protobuf to file...")
-  output_file = open(options.output_file, 'wb')
-  output_file.write(trace_file.SerializeToString())
-  output_file.close()
-
-  print("DONE")
-
-  # TODO: Silent running mode [no output except on error] for build runs.
-
-  return 0
-
-sys.exit(main(sys.argv))
+if __name__ == '__main__':
+  print(sys.argv)
+  sys.exit(main(sys.argv))
diff --git a/startop/scripts/iorap/compiler_test.py b/startop/scripts/iorap/compiler_test.py
new file mode 100644
index 0000000..b5d28b0
--- /dev/null
+++ b/startop/scripts/iorap/compiler_test.py
@@ -0,0 +1,78 @@
+#!/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 compiler.py script.
+
+Install:
+  $> sudo apt-get install python3-pytest   ##  OR
+  $> pip install -U pytest
+See also https://docs.pytest.org/en/latest/getting-started.html
+
+Usage:
+  $> pytest compiler_test.py
+
+See also https://docs.pytest.org/en/latest/usage.html
+"""
+import os
+
+import compiler
+
+DIR = os.path.abspath(os.path.dirname(__file__))
+TEXTCACHE = os.path.join(DIR, 'test_fixtures/compiler/common_textcache')
+SYSTRACE = os.path.join(DIR, 'test_fixtures/compiler/common_systrace')
+ARGV = [os.path.join(DIR, 'compiler.py'), '-i', TEXTCACHE, '-t', SYSTRACE]
+PERFETTO_TRACE = os.path.join(DIR,
+                              'test_fixtures/compiler/common_perfetto_trace.pb')
+
+def assert_compile_result(output, expected, *extra_argv):
+  argv = ARGV + ['-o', output] + [args for args in extra_argv]
+
+  compiler.main(argv)
+
+  with open(output, 'rb') as f1, open(expected, 'rb') as f2:
+    assert f1.read() == f2.read()
+
+### Unit tests - testing compiler code directly
+def test_transform_perfetto_trace_to_systrace(tmpdir):
+  expected = os.path.join(DIR,
+                          'test_fixtures/compiler/test_result_systrace')
+  output = tmpdir.mkdir('compiler').join('tmp_systrace')
+
+  compiler.transform_perfetto_trace_to_systrace(PERFETTO_TRACE, str(output))
+
+  with open(output, 'rb') as f1, open(expected, 'rb') as f2:
+    assert f1.read() == f2.read()
+
+### Functional tests - calls 'compiler.py --args...'
+def test_compiler_main(tmpdir):
+  output = tmpdir.mkdir('compiler').join('output')
+
+  # No duration
+  expected = os.path.join(DIR,
+                          'test_fixtures/compiler/test_result_without_duration.TraceFile.pb')
+  assert_compile_result(output, expected)
+
+  # 10ms duration
+  expected = os.path.join(DIR,
+                          'test_fixtures/compiler/test_result_with_duration.TraceFile.pb')
+  assert_compile_result(output, expected, '--duration', '10')
+
+  # 30ms duration
+  expected = os.path.join(DIR,
+                          'test_fixtures/compiler/test_result_without_duration.TraceFile.pb')
+  assert_compile_result(output, expected, '--duration', '30')
diff --git a/startop/scripts/iorap/test_fixtures/compiler/common_perfetto_trace.pb b/startop/scripts/iorap/test_fixtures/compiler/common_perfetto_trace.pb
new file mode 100644
index 0000000..a47ad3d
--- /dev/null
+++ b/startop/scripts/iorap/test_fixtures/compiler/common_perfetto_trace.pb
Binary files differ
diff --git a/startop/scripts/iorap/test_fixtures/compiler/common_systrace b/startop/scripts/iorap/test_fixtures/compiler/common_systrace
new file mode 100644
index 0000000..4573738
--- /dev/null
+++ b/startop/scripts/iorap/test_fixtures/compiler/common_systrace
@@ -0,0 +1,5 @@
+<...>-2965  (-----) [001] .... 10000.746629: mm_filemap_add_to_page_cache: dev 253:6 ino 1 page=00000000679ee1ec pfn=1299913 ofs=192512
+<...>-2965  (-----) [001] .... 10010.746664: mm_filemap_add_to_page_cache: dev 253:6 ino 2 page=0000000006cd2fb7 pfn=1296251 ofs=196608
+<...>-2965  (-----) [001] .... 10020.746677: mm_filemap_add_to_page_cache: dev 253:6 ino 3 page=00000000af82f3d6 pfn=1419330 ofs=200704
+<...>-2965  (-----) [001] .... 10030.746693: mm_filemap_add_to_page_cache: dev 253:6 ino 4 page=000000002840f054 pfn=1304928 ofs=204800
+<...>-2965  (-----) [001] .... 10040.746706: mm_filemap_add_to_page_cache: dev 253:6 ino 5 page=000000004a59da17 pfn=1288069 ofs=208896
diff --git a/startop/scripts/iorap/test_fixtures/compiler/common_textcache b/startop/scripts/iorap/test_fixtures/compiler/common_textcache
new file mode 100644
index 0000000..da03004
--- /dev/null
+++ b/startop/scripts/iorap/test_fixtures/compiler/common_textcache
@@ -0,0 +1,2 @@
+64774 1 -1 /system/test1
+64774 3 -1 /data/test2
diff --git a/startop/scripts/iorap/test_fixtures/compiler/test_result_systrace b/startop/scripts/iorap/test_fixtures/compiler/test_result_systrace
new file mode 100644
index 0000000..f731e73
--- /dev/null
+++ b/startop/scripts/iorap/test_fixtures/compiler/test_result_systrace
@@ -0,0 +1,748 @@
+TRACE:
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 30624/30624   #P:4
+#
+#                                      _-----=> irqs-off
+#                                     / _----=> need-resched
+#                                    | / _---=> hardirq/softirq
+#                                    || / _--=> preempt-depth
+#                                    ||| /     delay
+#           TASK-PID    TGID   CPU#  ||||    TIMESTAMP  FUNCTION
+#              | |        |      |   ||||       |         |
+       <unknown>-27388 (-----) [004] .... 1920260.530929: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1461937 ofs=9535488
+       <unknown>-27388 (-----) [005] .... 1920260.532161: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1344589 ofs=9474048
+       <unknown>-27388 (-----) [005] .... 1920260.532183: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1153671 ofs=9478144
+       <unknown>-27388 (-----) [005] .... 1920260.532184: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1219563 ofs=9482240
+       <unknown>-27388 (-----) [005] .... 1920260.532185: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1083162 ofs=9486336
+       <unknown>-27388 (-----) [005] .... 1920260.532185: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1147318 ofs=9490432
+       <unknown>-27388 (-----) [005] .... 1920260.532186: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1333594 ofs=9494528
+       <unknown>-27388 (-----) [005] .... 1920260.532186: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1375715 ofs=9498624
+       <unknown>-27388 (-----) [005] .... 1920260.532186: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1184831 ofs=9502720
+       <unknown>-27388 (-----) [005] .... 1920260.532187: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1241653 ofs=9506816
+       <unknown>-27388 (-----) [005] .... 1920260.532187: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1134975 ofs=9510912
+       <unknown>-27388 (-----) [005] .... 1920260.532190: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1145772 ofs=9515008
+       <unknown>-27388 (-----) [005] .... 1920260.532190: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1090457 ofs=9519104
+       <unknown>-27388 (-----) [005] .... 1920260.532190: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1137942 ofs=9523200
+       <unknown>-27388 (-----) [005] .... 1920260.532191: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1130123 ofs=9527296
+       <unknown>-27388 (-----) [005] .... 1920260.532191: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1208783 ofs=9531392
+       <unknown>-27388 (-----) [005] .... 1920260.532192: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1294989 ofs=9539584
+       <unknown>-27388 (-----) [005] .... 1920260.532206: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1163979 ofs=9543680
+       <unknown>-27388 (-----) [005] .... 1920260.532206: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1350628 ofs=9547776
+       <unknown>-27388 (-----) [005] .... 1920260.532206: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1386717 ofs=9551872
+       <unknown>-27388 (-----) [005] .... 1920260.532207: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1316148 ofs=9555968
+       <unknown>-27388 (-----) [005] .... 1920260.532208: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1316419 ofs=9560064
+       <unknown>-27388 (-----) [005] .... 1920260.532208: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1149076 ofs=9564160
+       <unknown>-27388 (-----) [005] .... 1920260.532209: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1372772 ofs=9568256
+       <unknown>-27388 (-----) [005] .... 1920260.532209: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1116389 ofs=9572352
+       <unknown>-27388 (-----) [005] .... 1920260.532211: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1325458 ofs=9576448
+       <unknown>-27388 (-----) [005] .... 1920260.532211: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1195423 ofs=9580544
+       <unknown>-27388 (-----) [005] .... 1920260.532211: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1250964 ofs=9584640
+       <unknown>-27388 (-----) [005] .... 1920260.532212: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1196027 ofs=9588736
+       <unknown>-27388 (-----) [005] .... 1920260.532212: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1354059 ofs=9592832
+       <unknown>-27388 (-----) [005] .... 1920260.532213: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1264649 ofs=9596928
+       <unknown>-27388 (-----) [005] .... 1920260.532213: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1245285 ofs=9601024
+       <unknown>-27388 (-----) [005] .... 1920260.535119: mm_filemap_add_to_page_cache: dev 0:64768 ino 1416 page=0000000000000000 pfn=1411552 ofs=44244992
+       <unknown>-27388 (-----) [005] .... 1920260.535129: mm_filemap_add_to_page_cache: dev 0:3 ino 0 page=0000000000000000 pfn=1483081 ofs=433524736
+       <unknown>-27388 (-----) [004] .... 1920260.536144: mm_filemap_add_to_page_cache: dev 0:3 ino 0 page=0000000000000000 pfn=1276173 ofs=438185984
+       <unknown>-27388 (-----) [004] .... 1920260.536462: mm_filemap_add_to_page_cache: dev 0:64768 ino 1416 page=0000000000000000 pfn=1174575 ofs=44249088
+       <unknown>-27388 (-----) [004] .... 1920260.536464: mm_filemap_add_to_page_cache: dev 0:64768 ino 1416 page=0000000000000000 pfn=1126294 ofs=44253184
+       <unknown>-27388 (-----) [004] .... 1920260.536464: mm_filemap_add_to_page_cache: dev 0:64768 ino 1416 page=0000000000000000 pfn=1248232 ofs=44257280
+       <unknown>-27388 (-----) [004] .... 1920260.537065: mm_filemap_add_to_page_cache: dev 0:64768 ino 1416 page=0000000000000000 pfn=1332993 ofs=44240896
+       <unknown>-27388 (-----) [006] .... 1920260.537646: mm_filemap_add_to_page_cache: dev 0:64768 ino 1416 page=0000000000000000 pfn=1153343 ofs=44400640
+       <unknown>-27388 (-----) [005] .... 1920260.538777: mm_filemap_add_to_page_cache: dev 0:64768 ino 1416 page=0000000000000000 pfn=1358397 ofs=44474368
+       <unknown>-12683 (-----) [006] .... 1920260.560094: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1426577 ofs=0
+       <unknown>-12683 (-----) [006] .... 1920260.560105: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1117587 ofs=1171456
+       <unknown>-12683 (-----) [006] .... 1920260.561199: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1099987 ofs=4096
+       <unknown>-12683 (-----) [006] .... 1920260.561411: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1099910 ofs=16384
+       <unknown>-12683 (-----) [006] .... 1920260.561598: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1099905 ofs=20480
+       <unknown>-12683 (-----) [006] .... 1920260.561758: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1099883 ofs=32768
+       <unknown>-12683 (-----) [006] .... 1920260.562088: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1099809 ofs=36864
+       <unknown>-12683 (-----) [006] .... 1920260.562325: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1099803 ofs=98304
+       <unknown>-12683 (-----) [006] .... 1920260.562516: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1099795 ofs=102400
+       <unknown>-12683 (-----) [006] .... 1920260.563094: mm_filemap_add_to_page_cache: dev 0:64768 ino 1523 page=0000000000000000 pfn=1107649 ofs=12288
+       <unknown>-12683 (-----) [006] .... 1920260.563105: mm_filemap_add_to_page_cache: dev 0:64768 ino 1523 page=0000000000000000 pfn=1269029 ofs=16384
+       <unknown>-12683 (-----) [006] .... 1920260.563785: mm_filemap_add_to_page_cache: dev 0:64768 ino 1242 page=0000000000000000 pfn=1451096 ofs=8192
+       <unknown>-12683 (-----) [006] .... 1920260.563790: mm_filemap_add_to_page_cache: dev 0:64768 ino 1242 page=0000000000000000 pfn=1301480 ofs=12288
+       <unknown>-12683 (-----) [006] .... 1920260.563790: mm_filemap_add_to_page_cache: dev 0:64768 ino 1242 page=0000000000000000 pfn=1314353 ofs=16384
+       <unknown>-12683 (-----) [006] .... 1920260.563791: mm_filemap_add_to_page_cache: dev 0:64768 ino 1242 page=0000000000000000 pfn=1216744 ofs=24576
+       <unknown>-12683 (-----) [006] .... 1920260.564309: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1099787 ofs=49152
+       <unknown>-12683 (-----) [006] .... 1920260.564514: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1099778 ofs=53248
+       <unknown>-12683 (-----) [005] .... 1920260.564756: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1148849 ofs=114688
+       <unknown>-12683 (-----) [005] .... 1920260.564973: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1164731 ofs=118784
+       <unknown>-12683 (-----) [005] .... 1920260.565000: mm_filemap_add_to_page_cache: dev 0:2053 ino 26 page=0000000000000000 pfn=1170255 ofs=0
+       <unknown>-12683 (-----) [005] .... 1920260.565003: mm_filemap_add_to_page_cache: dev 0:2053 ino 26 page=0000000000000000 pfn=1181043 ofs=4096
+       <unknown>-12683 (-----) [005] .... 1920260.565004: mm_filemap_add_to_page_cache: dev 0:2053 ino 26 page=0000000000000000 pfn=1296004 ofs=8192
+       <unknown>-12683 (-----) [005] .... 1920260.565004: mm_filemap_add_to_page_cache: dev 0:2053 ino 26 page=0000000000000000 pfn=1102004 ofs=12288
+       <unknown>-12683 (-----) [005] .... 1920260.565626: mm_filemap_add_to_page_cache: dev 0:3 ino 0 page=0000000000000000 pfn=1351232 ofs=470597632
+       <unknown>-12683 (-----) [005] .... 1920260.565982: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1391336 ofs=40210432
+       <unknown>-12683 (-----) [005] .... 1920260.565985: mm_filemap_add_to_page_cache: dev 0:64771 ino 2 page=0000000000000000 pfn=1267536 ofs=12668928
+       <unknown>-27388 (-----) [007] .... 1920260.566082: mm_filemap_add_to_page_cache: dev 0:64768 ino 1416 page=0000000000000000 pfn=1256752 ofs=43921408
+       <unknown>-12683 (-----) [005] .... 1920260.566516: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1110966 ofs=176226304
+       <unknown>-12683 (-----) [005] .... 1920260.566519: mm_filemap_add_to_page_cache: dev 0:64771 ino 2 page=0000000000000000 pfn=1060586 ofs=12967936
+       <unknown>-12683 (-----) [004] .... 1920260.567773: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1117234 ofs=421888
+       <unknown>-12683 (-----) [005] .... 1920260.568604: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1210571 ofs=430080
+       <unknown>-12683 (-----) [005] .... 1920260.568887: mm_filemap_add_to_page_cache: dev 0:64771 ino 105 page=0000000000000000 pfn=1055640 ofs=0
+       <unknown>-12683 (-----) [005] .... 1920260.568908: mm_filemap_add_to_page_cache: dev 0:64771 ino 73 page=0000000000000000 pfn=1142694 ofs=0
+       <unknown>-12683 (-----) [005] .... 1920260.568910: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1060788 ofs=299008
+       <unknown>-12683 (-----) [005] .... 1920260.569418: mm_filemap_add_to_page_cache: dev 0:64771 ino 73 page=0000000000000000 pfn=1085046 ofs=4096
+       <unknown>-12683 (-----) [005] .... 1920260.569640: mm_filemap_add_to_page_cache: dev 0:64771 ino 73 page=0000000000000000 pfn=1057135 ofs=8192
+       <unknown>-12683 (-----) [005] .... 1920260.569833: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1058976 ofs=19406848
+       <unknown>-12683 (-----) [005] .... 1920260.569835: mm_filemap_add_to_page_cache: dev 0:64771 ino 2 page=0000000000000000 pfn=1477947 ofs=10526720
+       <unknown>-12683 (-----) [005] .... 1920260.572285: mm_filemap_add_to_page_cache: dev 0:64768 ino 1565 page=0000000000000000 pfn=1237492 ofs=299008
+       <unknown>-12683 (-----) [005] .... 1920260.572297: mm_filemap_add_to_page_cache: dev 0:64768 ino 1565 page=0000000000000000 pfn=1264914 ofs=339968
+       <unknown>-12683 (-----) [005] .... 1920260.572314: mm_filemap_add_to_page_cache: dev 0:64768 ino 1565 page=0000000000000000 pfn=1434748 ofs=348160
+       <unknown>-12683 (-----) [005] .... 1920260.572316: mm_filemap_add_to_page_cache: dev 0:64768 ino 1565 page=0000000000000000 pfn=1372959 ofs=352256
+       <unknown>-12683 (-----) [005] .... 1920260.572317: mm_filemap_add_to_page_cache: dev 0:64768 ino 1565 page=0000000000000000 pfn=1258955 ofs=356352
+       <unknown>-12683 (-----) [005] .... 1920260.572317: mm_filemap_add_to_page_cache: dev 0:64768 ino 1565 page=0000000000000000 pfn=1113420 ofs=360448
+       <unknown>-12683 (-----) [005] .... 1920260.572318: mm_filemap_add_to_page_cache: dev 0:64768 ino 1565 page=0000000000000000 pfn=1137083 ofs=364544
+       <unknown>-12683 (-----) [004] .... 1920260.575490: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1379679 ofs=65536
+       <unknown>-12683 (-----) [006] .... 1920260.576194: mm_filemap_add_to_page_cache: dev 0:64771 ino 286 page=0000000000000000 pfn=1323898 ofs=69632
+       <unknown>-12683 (-----) [006] .... 1920260.576248: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1323895 ofs=262623232
+       <unknown>-12683 (-----) [006] .... 1920260.576251: mm_filemap_add_to_page_cache: dev 0:64771 ino 2 page=0000000000000000 pfn=1323861 ofs=13156352
+       <unknown>-12683 (-----) [005] .... 1920260.576810: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1477585 ofs=262590464
+       <unknown>-12683 (-----) [004] .... 1920260.577197: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1267617 ofs=25206784
+       <unknown>-12683 (-----) [004] .... 1920260.577200: mm_filemap_add_to_page_cache: dev 0:64771 ino 2 page=0000000000000000 pfn=1267618 ofs=12636160
+       <unknown>-12683 (-----) [005] .... 1920260.577725: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1056225 ofs=228618240
+       <unknown>-12683 (-----) [005] .... 1920260.577727: mm_filemap_add_to_page_cache: dev 0:64771 ino 2 page=0000000000000000 pfn=1164942 ofs=13082624
+       <unknown>-12683 (-----) [007] .... 1920260.578411: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1372616 ofs=0
+       <unknown>-12683 (-----) [007] .... 1920260.578422: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1307468 ofs=4096
+       <unknown>-12683 (-----) [007] .... 1920260.578428: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1120117 ofs=8192
+       <unknown>-12683 (-----) [007] .... 1920260.578428: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1217989 ofs=12288
+       <unknown>-12683 (-----) [007] .... 1920260.578650: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1475011 ofs=5419008
+       <unknown>-12683 (-----) [007] .... 1920260.578653: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1066084 ofs=236453888
+       <unknown>-12683 (-----) [007] .... 1920260.578654: mm_filemap_add_to_page_cache: dev 0:64771 ino 2 page=0000000000000000 pfn=1100271 ofs=13099008
+       <unknown>-12683 (-----) [004] .... 1920260.579004: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1485156 ofs=5423104
+       <unknown>-12683 (-----) [004] .... 1920260.579005: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1124212 ofs=5427200
+       <unknown>-12683 (-----) [004] .... 1920260.579006: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1195377 ofs=5431296
+       <unknown>-12683 (-----) [004] .... 1920260.579006: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1265888 ofs=5435392
+       <unknown>-12683 (-----) [004] .... 1920260.579007: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1170194 ofs=5439488
+       <unknown>-12683 (-----) [004] .... 1920260.579007: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1403742 ofs=5443584
+       <unknown>-12683 (-----) [004] .... 1920260.579008: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1123826 ofs=5447680
+       <unknown>-12683 (-----) [004] .... 1920260.579008: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1255034 ofs=5451776
+       <unknown>-12683 (-----) [004] .... 1920260.579011: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1190447 ofs=5455872
+       <unknown>-12683 (-----) [004] .... 1920260.579011: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1286864 ofs=5459968
+       <unknown>-12683 (-----) [004] .... 1920260.579012: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1428535 ofs=5464064
+       <unknown>-12683 (-----) [004] .... 1920260.579012: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1184092 ofs=5468160
+       <unknown>-12683 (-----) [004] .... 1920260.579013: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1411906 ofs=5472256
+       <unknown>-12683 (-----) [004] .... 1920260.579013: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1342349 ofs=5476352
+       <unknown>-12683 (-----) [004] .... 1920260.579013: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1188185 ofs=5480448
+       <unknown>-12683 (-----) [004] .... 1920260.579014: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1158702 ofs=5484544
+       <unknown>-12683 (-----) [005] .... 1920260.579430: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1299421 ofs=5230592
+       <unknown>-12683 (-----) [005] .... 1920260.579435: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1317097 ofs=5234688
+       <unknown>-12683 (-----) [005] .... 1920260.579435: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1441714 ofs=5238784
+       <unknown>-12683 (-----) [005] .... 1920260.579438: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1081974 ofs=5242880
+       <unknown>-12683 (-----) [005] .... 1920260.579439: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1128684 ofs=5246976
+       <unknown>-12683 (-----) [005] .... 1920260.579439: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1447381 ofs=5251072
+       <unknown>-12683 (-----) [005] .... 1920260.579440: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1466410 ofs=5255168
+       <unknown>-12683 (-----) [005] .... 1920260.579440: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1259909 ofs=5259264
+       <unknown>-12683 (-----) [005] .... 1920260.579441: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1125784 ofs=5263360
+       <unknown>-12683 (-----) [005] .... 1920260.579441: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1270592 ofs=5267456
+       <unknown>-12683 (-----) [005] .... 1920260.579442: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1246070 ofs=5271552
+       <unknown>-12683 (-----) [005] .... 1920260.579442: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1472544 ofs=5275648
+       <unknown>-12683 (-----) [005] .... 1920260.579442: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1113357 ofs=5279744
+       <unknown>-12683 (-----) [005] .... 1920260.579443: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1202021 ofs=5283840
+       <unknown>-12683 (-----) [005] .... 1920260.579443: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1078639 ofs=5287936
+       <unknown>-12683 (-----) [005] .... 1920260.579449: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1176171 ofs=5292032
+       <unknown>-12683 (-----) [005] .... 1920260.579450: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1089516 ofs=5296128
+       <unknown>-12683 (-----) [005] .... 1920260.579451: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1400065 ofs=5300224
+       <unknown>-12683 (-----) [005] .... 1920260.579452: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1300489 ofs=5304320
+       <unknown>-12683 (-----) [005] .... 1920260.579452: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1452081 ofs=5308416
+       <unknown>-12683 (-----) [005] .... 1920260.579452: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1161862 ofs=5312512
+       <unknown>-12683 (-----) [005] .... 1920260.579453: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1161871 ofs=5316608
+       <unknown>-12683 (-----) [005] .... 1920260.579453: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1263798 ofs=5320704
+       <unknown>-12683 (-----) [005] .... 1920260.579454: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1126887 ofs=5324800
+       <unknown>-12683 (-----) [005] .... 1920260.579454: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1375498 ofs=5328896
+       <unknown>-12683 (-----) [005] .... 1920260.579455: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1328067 ofs=5332992
+       <unknown>-12683 (-----) [005] .... 1920260.579455: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1420691 ofs=5337088
+       <unknown>-12683 (-----) [005] .... 1920260.579456: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1298707 ofs=5341184
+       <unknown>-12683 (-----) [005] .... 1920260.579456: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1078670 ofs=5345280
+       <unknown>-12683 (-----) [005] .... 1920260.579457: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1430498 ofs=5349376
+       <unknown>-12683 (-----) [005] .... 1920260.579458: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1338720 ofs=5353472
+       <unknown>-12683 (-----) [005] .... 1920260.579476: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1452611 ofs=5357568
+       <unknown>-12683 (-----) [006] .... 1920260.580451: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1241967 ofs=0
+       <unknown>-12683 (-----) [006] .... 1920260.580454: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1116541 ofs=4096
+       <unknown>-12683 (-----) [006] .... 1920260.580461: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1145049 ofs=8192
+       <unknown>-12683 (-----) [006] .... 1920260.580462: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1277255 ofs=12288
+       <unknown>-12683 (-----) [006] .... 1920260.580462: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1098037 ofs=16384
+       <unknown>-12683 (-----) [006] .... 1920260.580463: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1135986 ofs=20480
+       <unknown>-12683 (-----) [006] .... 1920260.580464: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1154455 ofs=24576
+       <unknown>-12683 (-----) [006] .... 1920260.580464: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1221822 ofs=28672
+       <unknown>-12683 (-----) [006] .... 1920260.580465: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1078684 ofs=32768
+       <unknown>-12683 (-----) [006] .... 1920260.580465: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1158876 ofs=36864
+       <unknown>-12683 (-----) [006] .... 1920260.580465: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1289644 ofs=40960
+       <unknown>-12683 (-----) [006] .... 1920260.580466: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1289386 ofs=45056
+       <unknown>-12683 (-----) [006] .... 1920260.580466: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1131002 ofs=49152
+       <unknown>-12683 (-----) [006] .... 1920260.580467: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1464335 ofs=53248
+       <unknown>-12683 (-----) [006] .... 1920260.580468: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1135789 ofs=57344
+       <unknown>-12683 (-----) [006] .... 1920260.580469: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1240897 ofs=61440
+       <unknown>-12683 (-----) [006] .... 1920260.580469: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1241770 ofs=65536
+       <unknown>-12683 (-----) [006] .... 1920260.580470: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1421959 ofs=69632
+       <unknown>-12683 (-----) [006] .... 1920260.580470: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1230007 ofs=73728
+       <unknown>-12683 (-----) [006] .... 1920260.580471: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1109271 ofs=77824
+       <unknown>-12683 (-----) [006] .... 1920260.580471: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1159974 ofs=81920
+       <unknown>-12683 (-----) [006] .... 1920260.580471: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1154528 ofs=86016
+       <unknown>-12683 (-----) [006] .... 1920260.580472: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1315790 ofs=90112
+       <unknown>-12683 (-----) [006] .... 1920260.580473: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1185583 ofs=94208
+       <unknown>-12683 (-----) [006] .... 1920260.580473: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1253153 ofs=98304
+       <unknown>-12683 (-----) [006] .... 1920260.580473: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103982 ofs=102400
+       <unknown>-12683 (-----) [006] .... 1920260.580474: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1284589 ofs=106496
+       <unknown>-12683 (-----) [006] .... 1920260.580474: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1169601 ofs=110592
+       <unknown>-12683 (-----) [006] .... 1920260.580476: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1206248 ofs=114688
+       <unknown>-12683 (-----) [006] .... 1920260.580476: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1261161 ofs=118784
+       <unknown>-12683 (-----) [006] .... 1920260.580477: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1305841 ofs=122880
+       <unknown>-12683 (-----) [006] .... 1920260.580477: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1468293 ofs=126976
+       <unknown>-12683 (-----) [004] .... 1920260.580646: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1318816 ofs=16384
+       <unknown>-12683 (-----) [004] .... 1920260.580649: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1472922 ofs=20480
+       <unknown>-12683 (-----) [004] .... 1920260.580650: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1473229 ofs=24576
+       <unknown>-12683 (-----) [004] .... 1920260.580650: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1524262 ofs=28672
+       <unknown>-12683 (-----) [004] .... 1920260.580656: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1205714 ofs=32768
+       <unknown>-12683 (-----) [004] .... 1920260.580657: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1310560 ofs=36864
+       <unknown>-12683 (-----) [004] .... 1920260.580658: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1295070 ofs=40960
+       <unknown>-12683 (-----) [004] .... 1920260.580659: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1404093 ofs=45056
+       <unknown>-12683 (-----) [004] .... 1920260.580659: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1435814 ofs=49152
+       <unknown>-12683 (-----) [004] .... 1920260.580660: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1435442 ofs=53248
+       <unknown>-12683 (-----) [004] .... 1920260.580660: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1096077 ofs=57344
+       <unknown>-12683 (-----) [004] .... 1920260.580661: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1483793 ofs=61440
+       <unknown>-12683 (-----) [004] .... 1920260.580661: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1231298 ofs=65536
+       <unknown>-12683 (-----) [004] .... 1920260.580661: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1215648 ofs=69632
+       <unknown>-12683 (-----) [004] .... 1920260.580662: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1327326 ofs=73728
+       <unknown>-12683 (-----) [004] .... 1920260.580662: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1108894 ofs=77824
+       <unknown>-12683 (-----) [004] .... 1920260.580663: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1327545 ofs=81920
+       <unknown>-12683 (-----) [004] .... 1920260.580663: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1328804 ofs=86016
+       <unknown>-12683 (-----) [004] .... 1920260.580664: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1300171 ofs=90112
+       <unknown>-12683 (-----) [004] .... 1920260.580664: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1353250 ofs=94208
+       <unknown>-12683 (-----) [004] .... 1920260.580668: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1333681 ofs=98304
+       <unknown>-12683 (-----) [004] .... 1920260.580668: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1144969 ofs=102400
+       <unknown>-12683 (-----) [004] .... 1920260.580669: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1450962 ofs=106496
+       <unknown>-12683 (-----) [004] .... 1920260.580669: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1255701 ofs=110592
+       <unknown>-12683 (-----) [004] .... 1920260.580670: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1294782 ofs=114688
+       <unknown>-12683 (-----) [004] .... 1920260.580670: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1226912 ofs=118784
+       <unknown>-12683 (-----) [004] .... 1920260.580671: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1294579 ofs=122880
+       <unknown>-12683 (-----) [004] .... 1920260.580671: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1246960 ofs=126976
+       <unknown>-12683 (-----) [004] .... 1920260.580671: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1199086 ofs=131072
+       <unknown>-12683 (-----) [004] .... 1920260.580672: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1449590 ofs=135168
+       <unknown>-12683 (-----) [004] .... 1920260.580672: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1276363 ofs=139264
+       <unknown>-12683 (-----) [004] .... 1920260.580675: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1389998 ofs=143360
+       <unknown>-12683 (-----) [004] .... 1920260.580739: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1423031 ofs=1249280
+       <unknown>-12683 (-----) [004] .... 1920260.580741: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1171032 ofs=1253376
+       <unknown>-12683 (-----) [004] .... 1920260.580742: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1320946 ofs=1257472
+       <unknown>-12683 (-----) [004] .... 1920260.580743: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1314696 ofs=1261568
+       <unknown>-12683 (-----) [004] .... 1920260.580743: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1414864 ofs=1265664
+       <unknown>-12683 (-----) [004] .... 1920260.580744: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1334933 ofs=1269760
+       <unknown>-12683 (-----) [004] .... 1920260.580744: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1242845 ofs=1273856
+       <unknown>-12683 (-----) [004] .... 1920260.580747: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1289488 ofs=1277952
+       <unknown>-12683 (-----) [004] .... 1920260.580748: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1335445 ofs=1282048
+       <unknown>-12683 (-----) [004] .... 1920260.580748: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1289663 ofs=1286144
+       <unknown>-12683 (-----) [004] .... 1920260.580749: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1080462 ofs=1290240
+       <unknown>-12683 (-----) [004] .... 1920260.580749: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1286303 ofs=1294336
+       <unknown>-12683 (-----) [004] .... 1920260.580750: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1353531 ofs=1298432
+       <unknown>-12683 (-----) [004] .... 1920260.580750: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1280701 ofs=1302528
+       <unknown>-12683 (-----) [004] .... 1920260.580751: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1107730 ofs=1306624
+       <unknown>-12683 (-----) [004] .... 1920260.580752: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1242729 ofs=1310720
+       <unknown>-12683 (-----) [004] .... 1920260.580753: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1078336 ofs=1314816
+       <unknown>-12683 (-----) [004] .... 1920260.580753: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1372425 ofs=1318912
+       <unknown>-12683 (-----) [004] .... 1920260.580754: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1248813 ofs=1323008
+       <unknown>-12683 (-----) [004] .... 1920260.580754: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1201155 ofs=1327104
+       <unknown>-12683 (-----) [004] .... 1920260.580755: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1250103 ofs=1331200
+       <unknown>-12683 (-----) [004] .... 1920260.580755: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1359710 ofs=1335296
+       <unknown>-12683 (-----) [004] .... 1920260.580756: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1272462 ofs=1339392
+       <unknown>-12683 (-----) [004] .... 1920260.580758: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1097035 ofs=1343488
+       <unknown>-12683 (-----) [004] .... 1920260.580759: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1233124 ofs=1347584
+       <unknown>-12683 (-----) [004] .... 1920260.580759: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1455812 ofs=1351680
+       <unknown>-12683 (-----) [004] .... 1920260.580759: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1355689 ofs=1355776
+       <unknown>-12683 (-----) [004] .... 1920260.580760: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1263593 ofs=1359872
+       <unknown>-12683 (-----) [004] .... 1920260.580760: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1230789 ofs=1363968
+       <unknown>-12683 (-----) [004] .... 1920260.580761: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1143766 ofs=1368064
+       <unknown>-12683 (-----) [004] .... 1920260.580762: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1269666 ofs=1372160
+       <unknown>-12683 (-----) [004] .... 1920260.580762: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1353022 ofs=1376256
+       <unknown>-12683 (-----) [004] .... 1920260.581613: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1355509 ofs=258048
+       <unknown>-12683 (-----) [004] .... 1920260.581615: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1178902 ofs=262144
+       <unknown>-12683 (-----) [004] .... 1920260.581616: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1193649 ofs=266240
+       <unknown>-12683 (-----) [004] .... 1920260.581618: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1225497 ofs=270336
+       <unknown>-12683 (-----) [004] .... 1920260.581618: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1228259 ofs=274432
+       <unknown>-12683 (-----) [004] .... 1920260.581635: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1309674 ofs=278528
+       <unknown>-12683 (-----) [004] .... 1920260.581635: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1239390 ofs=282624
+       <unknown>-12683 (-----) [004] .... 1920260.581636: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1468083 ofs=286720
+       <unknown>-12683 (-----) [004] .... 1920260.581636: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1292751 ofs=290816
+       <unknown>-12683 (-----) [004] .... 1920260.581637: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1318066 ofs=294912
+       <unknown>-12683 (-----) [004] .... 1920260.581637: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1489314 ofs=299008
+       <unknown>-12683 (-----) [004] .... 1920260.581637: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1169867 ofs=303104
+       <unknown>-12683 (-----) [004] .... 1920260.581639: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1314256 ofs=307200
+       <unknown>-12683 (-----) [004] .... 1920260.581639: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1310230 ofs=311296
+       <unknown>-12683 (-----) [004] .... 1920260.581640: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1356180 ofs=315392
+       <unknown>-12683 (-----) [004] .... 1920260.581640: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1419179 ofs=319488
+       <unknown>-12683 (-----) [004] .... 1920260.581641: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1307265 ofs=323584
+       <unknown>-12683 (-----) [004] .... 1920260.581641: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1218590 ofs=327680
+       <unknown>-12683 (-----) [004] .... 1920260.581642: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1447586 ofs=331776
+       <unknown>-12683 (-----) [004] .... 1920260.581642: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1209382 ofs=335872
+       <unknown>-12683 (-----) [004] .... 1920260.581642: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1072148 ofs=339968
+       <unknown>-12683 (-----) [004] .... 1920260.581645: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1227195 ofs=344064
+       <unknown>-12683 (-----) [004] .... 1920260.581646: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1246369 ofs=348160
+       <unknown>-12683 (-----) [004] .... 1920260.581646: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1193845 ofs=352256
+       <unknown>-12683 (-----) [004] .... 1920260.581647: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1137553 ofs=356352
+       <unknown>-12683 (-----) [004] .... 1920260.581647: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1475215 ofs=360448
+       <unknown>-12683 (-----) [004] .... 1920260.581648: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1258935 ofs=364544
+       <unknown>-12683 (-----) [004] .... 1920260.581649: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1448788 ofs=368640
+       <unknown>-12683 (-----) [004] .... 1920260.581649: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1447611 ofs=372736
+       <unknown>-12683 (-----) [004] .... 1920260.581650: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1290842 ofs=376832
+       <unknown>-12683 (-----) [004] .... 1920260.581650: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1447826 ofs=380928
+       <unknown>-12683 (-----) [004] .... 1920260.581650: mm_filemap_add_to_page_cache: dev 0:64771 ino 55815 page=0000000000000000 pfn=1181016 ofs=385024
+       <unknown>-12683 (-----) [005] .... 1920260.582230: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1216810 ofs=1662976
+       <unknown>-12683 (-----) [005] .... 1920260.582234: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1175966 ofs=1667072
+       <unknown>-12683 (-----) [005] .... 1920260.582235: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1449798 ofs=1671168
+       <unknown>-12683 (-----) [005] .... 1920260.582236: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1273480 ofs=1675264
+       <unknown>-12683 (-----) [005] .... 1920260.582236: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1152779 ofs=1679360
+       <unknown>-12683 (-----) [005] .... 1920260.582237: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1272810 ofs=1683456
+       <unknown>-12683 (-----) [005] .... 1920260.582237: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1248634 ofs=1687552
+       <unknown>-12683 (-----) [005] .... 1920260.582237: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1203376 ofs=1691648
+       <unknown>-12683 (-----) [005] .... 1920260.582238: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1138880 ofs=1695744
+       <unknown>-12683 (-----) [005] .... 1920260.582238: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1344591 ofs=1699840
+       <unknown>-12683 (-----) [005] .... 1920260.582239: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1416060 ofs=1703936
+       <unknown>-12683 (-----) [005] .... 1920260.582246: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1128676 ofs=1708032
+       <unknown>-12683 (-----) [005] .... 1920260.582247: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1301921 ofs=1712128
+       <unknown>-12683 (-----) [005] .... 1920260.582248: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1384569 ofs=1716224
+       <unknown>-12683 (-----) [005] .... 1920260.582248: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1249106 ofs=1720320
+       <unknown>-12683 (-----) [005] .... 1920260.582249: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1206596 ofs=1724416
+       <unknown>-12683 (-----) [005] .... 1920260.582249: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1429831 ofs=1728512
+       <unknown>-12683 (-----) [005] .... 1920260.582252: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1107796 ofs=1732608
+       <unknown>-12683 (-----) [005] .... 1920260.582255: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1098336 ofs=1736704
+       <unknown>-12683 (-----) [005] .... 1920260.582255: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1230286 ofs=1740800
+       <unknown>-12683 (-----) [005] .... 1920260.582256: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1100370 ofs=1744896
+       <unknown>-12683 (-----) [005] .... 1920260.582256: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1241930 ofs=1748992
+       <unknown>-12683 (-----) [005] .... 1920260.582257: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1366807 ofs=1753088
+       <unknown>-12683 (-----) [005] .... 1920260.582257: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1136252 ofs=1757184
+       <unknown>-12683 (-----) [005] .... 1920260.582258: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1274291 ofs=1761280
+       <unknown>-12683 (-----) [005] .... 1920260.582258: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1254775 ofs=1765376
+       <unknown>-12683 (-----) [005] .... 1920260.582259: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1194679 ofs=1769472
+       <unknown>-12683 (-----) [005] .... 1920260.582262: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1177090 ofs=1773568
+       <unknown>-12683 (-----) [005] .... 1920260.582263: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1343925 ofs=1777664
+       <unknown>-12683 (-----) [005] .... 1920260.582263: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1159217 ofs=1781760
+       <unknown>-12683 (-----) [005] .... 1920260.582263: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1435471 ofs=1785856
+       <unknown>-12683 (-----) [005] .... 1920260.582264: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1435529 ofs=1789952
+       <unknown>-12683 (-----) [004] .... 1920260.582524: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1181910 ofs=0
+       <unknown>-12683 (-----) [004] .... 1920260.582528: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1212021 ofs=4096
+       <unknown>-12683 (-----) [004] .... 1920260.582529: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1162778 ofs=8192
+       <unknown>-12683 (-----) [004] .... 1920260.582529: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1107700 ofs=12288
+       <unknown>-12683 (-----) [004] .... 1920260.583553: mm_filemap_add_to_page_cache: dev 0:64771 ino 57137 page=0000000000000000 pfn=1093394 ofs=3399680
+       <unknown>-12683 (-----) [004] .... 1920260.583984: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1121431 ofs=242503680
+       <unknown>-12683 (-----) [004] .... 1920260.583986: mm_filemap_add_to_page_cache: dev 0:64771 ino 2 page=0000000000000000 pfn=1168551 ofs=13115392
+       <unknown>-12683 (-----) [004] .... 1920260.584304: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1347409 ofs=0
+       <unknown>-12683 (-----) [004] .... 1920260.584307: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1428681 ofs=4096
+       <unknown>-12683 (-----) [004] .... 1920260.584307: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1259106 ofs=8192
+       <unknown>-12683 (-----) [004] .... 1920260.584308: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1343229 ofs=12288
+       <unknown>-12694 (-----) [005] .... 1920260.584622: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1098733 ofs=1531904
+       <unknown>-12696 (-----) [006] .... 1920260.584626: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1331319 ofs=1536000
+       <unknown>-12694 (-----) [005] .... 1920260.584626: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1278537 ofs=1540096
+       <unknown>-12696 (-----) [006] .... 1920260.584631: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1492534 ofs=1544192
+       <unknown>-12694 (-----) [005] .... 1920260.584636: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1460878 ofs=1548288
+       <unknown>-12694 (-----) [005] .... 1920260.584640: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1092973 ofs=1552384
+       <unknown>-12694 (-----) [005] .... 1920260.584641: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1103200 ofs=1556480
+       <unknown>-12694 (-----) [005] .... 1920260.584642: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1257426 ofs=1560576
+       <unknown>-12694 (-----) [005] .... 1920260.584642: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1219424 ofs=1564672
+       <unknown>-12683 (-----) [004] .... 1920260.584660: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1279352 ofs=1568768
+       <unknown>-12696 (-----) [006] .... 1920260.584662: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1260572 ofs=1572864
+       <unknown>-12683 (-----) [004] .... 1920260.584663: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1225809 ofs=1576960
+       <unknown>-12696 (-----) [006] .... 1920260.584665: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1350766 ofs=1585152
+       <unknown>-12697 (-----) [007] .... 1920260.584666: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1107173 ofs=1581056
+       <unknown>-12683 (-----) [004] .... 1920260.584668: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1305885 ofs=1589248
+       <unknown>-12694 (-----) [005] .... 1920260.584669: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1293385 ofs=1593344
+       <unknown>-12696 (-----) [006] .... 1920260.584670: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1173841 ofs=1597440
+       <unknown>-12697 (-----) [007] .... 1920260.584670: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1080021 ofs=1601536
+       <unknown>-12683 (-----) [004] .... 1920260.584673: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1147419 ofs=1605632
+       <unknown>-12696 (-----) [006] .... 1920260.584673: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1252762 ofs=1609728
+       <unknown>-12694 (-----) [005] .... 1920260.584674: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1323916 ofs=1613824
+       <unknown>-12683 (-----) [004] .... 1920260.584675: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1155631 ofs=1617920
+       <unknown>-12696 (-----) [006] .... 1920260.584676: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1449815 ofs=1622016
+       <unknown>-12694 (-----) [005] .... 1920260.584678: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1227069 ofs=1626112
+       <unknown>-12696 (-----) [006] .... 1920260.584680: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1317692 ofs=1630208
+       <unknown>-12694 (-----) [005] .... 1920260.584681: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1492244 ofs=1634304
+       <unknown>-12683 (-----) [004] .... 1920260.584682: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1241876 ofs=1638400
+       <unknown>-12697 (-----) [007] .... 1920260.585446: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1402958 ofs=167936
+       <unknown>-12697 (-----) [007] .... 1920260.585449: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1133263 ofs=172032
+       <unknown>-12697 (-----) [007] .... 1920260.585450: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1295502 ofs=176128
+       <unknown>-12697 (-----) [007] .... 1920260.585450: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1249495 ofs=180224
+       <unknown>-12697 (-----) [007] .... 1920260.585451: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1237999 ofs=184320
+       <unknown>-12697 (-----) [007] .... 1920260.585451: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1280965 ofs=188416
+       <unknown>-12697 (-----) [007] .... 1920260.585454: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1208361 ofs=192512
+       <unknown>-12697 (-----) [007] .... 1920260.585454: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1308840 ofs=196608
+       <unknown>-12695 (-----) [004] .... 1920260.585455: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1138875 ofs=569344
+       <unknown>-12695 (-----) [004] .... 1920260.585458: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1314886 ofs=573440
+       <unknown>-12697 (-----) [007] .... 1920260.585458: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1242734 ofs=200704
+       <unknown>-12695 (-----) [004] .... 1920260.585458: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1447386 ofs=577536
+       <unknown>-12697 (-----) [007] .... 1920260.585459: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1241302 ofs=204800
+       <unknown>-12695 (-----) [004] .... 1920260.585459: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1328663 ofs=581632
+       <unknown>-12697 (-----) [007] .... 1920260.585459: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1476101 ofs=208896
+       <unknown>-12695 (-----) [004] .... 1920260.585460: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1209461 ofs=585728
+       <unknown>-12697 (-----) [007] .... 1920260.585460: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1080147 ofs=212992
+       <unknown>-12697 (-----) [007] .... 1920260.585461: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1128509 ofs=217088
+       <unknown>-12697 (-----) [007] .... 1920260.585461: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1371915 ofs=221184
+       <unknown>-12697 (-----) [007] .... 1920260.585461: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1264015 ofs=225280
+       <unknown>-12697 (-----) [007] .... 1920260.585462: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1211695 ofs=229376
+       <unknown>-12697 (-----) [007] .... 1920260.585462: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1150386 ofs=233472
+       <unknown>-12697 (-----) [007] .... 1920260.585463: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1135747 ofs=237568
+       <unknown>-12697 (-----) [007] .... 1920260.585463: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1128230 ofs=241664
+       <unknown>-12697 (-----) [007] .... 1920260.585464: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1155451 ofs=245760
+       <unknown>-12697 (-----) [007] .... 1920260.585465: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1246841 ofs=249856
+       <unknown>-12697 (-----) [007] .... 1920260.585465: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1462971 ofs=253952
+       <unknown>-12697 (-----) [007] .... 1920260.585466: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1131333 ofs=258048
+       <unknown>-12697 (-----) [007] .... 1920260.585466: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1289407 ofs=262144
+       <unknown>-12695 (-----) [004] .... 1920260.585467: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1134730 ofs=589824
+       <unknown>-12697 (-----) [007] .... 1920260.585467: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1289873 ofs=266240
+       <unknown>-12697 (-----) [007] .... 1920260.585468: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1448734 ofs=270336
+       <unknown>-12695 (-----) [004] .... 1920260.585468: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1129776 ofs=593920
+       <unknown>-12697 (-----) [007] .... 1920260.585468: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1524090 ofs=274432
+       <unknown>-12695 (-----) [004] .... 1920260.585468: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1399725 ofs=598016
+       <unknown>-12697 (-----) [007] .... 1920260.585469: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1524081 ofs=278528
+       <unknown>-12695 (-----) [004] .... 1920260.585469: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1276535 ofs=602112
+       <unknown>-12697 (-----) [007] .... 1920260.585469: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1524060 ofs=282624
+       <unknown>-12695 (-----) [004] .... 1920260.585470: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1449847 ofs=606208
+       <unknown>-12697 (-----) [007] .... 1920260.585470: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1158944 ofs=286720
+       <unknown>-12695 (-----) [004] .... 1920260.585470: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1384536 ofs=610304
+       <unknown>-12697 (-----) [007] .... 1920260.585470: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1116785 ofs=290816
+       <unknown>-12695 (-----) [004] .... 1920260.585471: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1308118 ofs=614400
+       <unknown>-12697 (-----) [007] .... 1920260.585471: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1448669 ofs=294912
+       <unknown>-12695 (-----) [004] .... 1920260.585471: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1227050 ofs=618496
+       <unknown>-12695 (-----) [004] .... 1920260.585473: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1289324 ofs=622592
+       <unknown>-12695 (-----) [004] .... 1920260.585473: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1187869 ofs=626688
+       <unknown>-12695 (-----) [004] .... 1920260.585474: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1400523 ofs=630784
+       <unknown>-12695 (-----) [004] .... 1920260.585474: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1344176 ofs=634880
+       <unknown>-12695 (-----) [004] .... 1920260.585475: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1092871 ofs=638976
+       <unknown>-12695 (-----) [004] .... 1920260.585475: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1092021 ofs=643072
+       <unknown>-12695 (-----) [004] .... 1920260.585476: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1198169 ofs=647168
+       <unknown>-12695 (-----) [004] .... 1920260.585476: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1371540 ofs=651264
+       <unknown>-12683 (-----) [005] .... 1920260.585476: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1195003 ofs=348160
+       <unknown>-12695 (-----) [004] .... 1920260.585477: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1228787 ofs=655360
+       <unknown>-12695 (-----) [004] .... 1920260.585477: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1236123 ofs=659456
+       <unknown>-12695 (-----) [004] .... 1920260.585477: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1137213 ofs=663552
+       <unknown>-12695 (-----) [004] .... 1920260.585478: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1294618 ofs=667648
+       <unknown>-12695 (-----) [004] .... 1920260.585478: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1241048 ofs=671744
+       <unknown>-12695 (-----) [004] .... 1920260.585479: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1228779 ofs=675840
+       <unknown>-12683 (-----) [005] .... 1920260.585479: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1199292 ofs=352256
+       <unknown>-12683 (-----) [005] .... 1920260.585480: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1200861 ofs=356352
+       <unknown>-12695 (-----) [004] .... 1920260.585480: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1309572 ofs=679936
+       <unknown>-12683 (-----) [005] .... 1920260.585480: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1215770 ofs=360448
+       <unknown>-12695 (-----) [004] .... 1920260.585481: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1409002 ofs=684032
+       <unknown>-12683 (-----) [005] .... 1920260.585481: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1151883 ofs=364544
+       <unknown>-12695 (-----) [004] .... 1920260.585481: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1103729 ofs=688128
+       <unknown>-12683 (-----) [005] .... 1920260.585482: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1468126 ofs=368640
+       <unknown>-12695 (-----) [004] .... 1920260.585482: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1162720 ofs=692224
+       <unknown>-12683 (-----) [005] .... 1920260.585482: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1251672 ofs=372736
+       <unknown>-12695 (-----) [004] .... 1920260.585482: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1199221 ofs=696320
+       <unknown>-12683 (-----) [005] .... 1920260.585483: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1283325 ofs=376832
+       <unknown>-12683 (-----) [005] .... 1920260.585483: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1190489 ofs=380928
+       <unknown>-12683 (-----) [005] .... 1920260.585484: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1489117 ofs=385024
+       <unknown>-12683 (-----) [005] .... 1920260.585484: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1273899 ofs=389120
+       <unknown>-12683 (-----) [005] .... 1920260.585485: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1274459 ofs=393216
+       <unknown>-12683 (-----) [005] .... 1920260.585486: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1316649 ofs=397312
+       <unknown>-12683 (-----) [005] .... 1920260.585491: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1375678 ofs=401408
+       <unknown>-12683 (-----) [005] .... 1920260.585491: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1483317 ofs=405504
+       <unknown>-12683 (-----) [005] .... 1920260.585492: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1240286 ofs=409600
+       <unknown>-12683 (-----) [005] .... 1920260.585492: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1131345 ofs=413696
+       <unknown>-12683 (-----) [005] .... 1920260.585493: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1200483 ofs=417792
+       <unknown>-12683 (-----) [005] .... 1920260.585493: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1384693 ofs=421888
+       <unknown>-12683 (-----) [005] .... 1920260.585493: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1161385 ofs=425984
+       <unknown>-12683 (-----) [005] .... 1920260.585494: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1452025 ofs=430080
+       <unknown>-12683 (-----) [005] .... 1920260.585495: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1253654 ofs=434176
+       <unknown>-12683 (-----) [005] .... 1920260.585495: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1116697 ofs=438272
+       <unknown>-12683 (-----) [005] .... 1920260.585495: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1432645 ofs=442368
+       <unknown>-12694 (-----) [006] .... 1920260.585495: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1337397 ofs=16384
+       <unknown>-12683 (-----) [005] .... 1920260.585496: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1304229 ofs=446464
+       <unknown>-12683 (-----) [005] .... 1920260.585496: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1419147 ofs=450560
+       <unknown>-12683 (-----) [005] .... 1920260.585498: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1349246 ofs=454656
+       <unknown>-12683 (-----) [005] .... 1920260.585499: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1128519 ofs=458752
+       <unknown>-12683 (-----) [005] .... 1920260.585499: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1125168 ofs=462848
+       <unknown>-12694 (-----) [006] .... 1920260.585509: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1081031 ofs=20480
+       <unknown>-12694 (-----) [006] .... 1920260.585509: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1293022 ofs=24576
+       <unknown>-12694 (-----) [006] .... 1920260.585510: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1113007 ofs=28672
+       <unknown>-12694 (-----) [006] .... 1920260.585510: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1339312 ofs=32768
+       <unknown>-12694 (-----) [006] .... 1920260.585511: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1412311 ofs=36864
+       <unknown>-12694 (-----) [006] .... 1920260.585511: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1260960 ofs=40960
+       <unknown>-12694 (-----) [006] .... 1920260.585512: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1189529 ofs=45056
+       <unknown>-12694 (-----) [006] .... 1920260.585512: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1412184 ofs=49152
+       <unknown>-12694 (-----) [006] .... 1920260.585513: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1481227 ofs=53248
+       <unknown>-12694 (-----) [006] .... 1920260.585513: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1455940 ofs=57344
+       <unknown>-12694 (-----) [006] .... 1920260.585514: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1299132 ofs=61440
+       <unknown>-12694 (-----) [006] .... 1920260.585514: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1337375 ofs=65536
+       <unknown>-12694 (-----) [006] .... 1920260.585529: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1328742 ofs=69632
+       <unknown>-12694 (-----) [006] .... 1920260.585529: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1315646 ofs=73728
+       <unknown>-12694 (-----) [006] .... 1920260.585531: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1225475 ofs=77824
+       <unknown>-12694 (-----) [006] .... 1920260.585531: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1146097 ofs=81920
+       <unknown>-12694 (-----) [006] .... 1920260.585532: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1318775 ofs=86016
+       <unknown>-12694 (-----) [006] .... 1920260.585532: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1448391 ofs=90112
+       <unknown>-12694 (-----) [006] .... 1920260.585532: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1441412 ofs=94208
+       <unknown>-12694 (-----) [006] .... 1920260.585533: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1138111 ofs=98304
+       <unknown>-12694 (-----) [006] .... 1920260.585533: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1143223 ofs=102400
+       <unknown>-12683 (-----) [005] .... 1920260.585534: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1079876 ofs=466944
+       <unknown>-12694 (-----) [006] .... 1920260.585534: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1447637 ofs=106496
+       <unknown>-12694 (-----) [006] .... 1920260.585534: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1220585 ofs=110592
+       <unknown>-12694 (-----) [006] .... 1920260.585535: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1449051 ofs=114688
+       <unknown>-12694 (-----) [006] .... 1920260.585535: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1313180 ofs=118784
+       <unknown>-12694 (-----) [006] .... 1920260.585535: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1313166 ofs=122880
+       <unknown>-12694 (-----) [006] .... 1920260.585536: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1313154 ofs=126976
+       <unknown>-12683 (-----) [005] .... 1920260.585536: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1218394 ofs=471040
+       <unknown>-12694 (-----) [006] .... 1920260.585536: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1144047 ofs=131072
+       <unknown>-12683 (-----) [005] .... 1920260.585537: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1218579 ofs=475136
+       <unknown>-12694 (-----) [006] .... 1920260.585543: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1241332 ofs=135168
+       <unknown>-12694 (-----) [006] .... 1920260.585543: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1097199 ofs=139264
+       <unknown>-12694 (-----) [006] .... 1920260.585545: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1214197 ofs=143360
+       <unknown>-12694 (-----) [006] .... 1920260.585645: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1197633 ofs=147456
+       <unknown>-12694 (-----) [006] .... 1920260.585647: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1311536 ofs=151552
+       <unknown>-12694 (-----) [006] .... 1920260.585647: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1322952 ofs=155648
+       <unknown>-12694 (-----) [006] .... 1920260.585647: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1346974 ofs=159744
+       <unknown>-12694 (-----) [006] .... 1920260.585648: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1257232 ofs=163840
+       <unknown>-12695 (-----) [004] .... 1920260.586355: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1204484 ofs=700416
+       <unknown>-12695 (-----) [004] .... 1920260.586357: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1326426 ofs=704512
+       <unknown>-12695 (-----) [004] .... 1920260.586358: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1151808 ofs=708608
+       <unknown>-12695 (-----) [004] .... 1920260.586358: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1209422 ofs=712704
+       <unknown>-12695 (-----) [004] .... 1920260.586359: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1408387 ofs=716800
+       <unknown>-12695 (-----) [004] .... 1920260.586359: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1197336 ofs=720896
+       <unknown>-12695 (-----) [004] .... 1920260.586363: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1205652 ofs=724992
+       <unknown>-12695 (-----) [004] .... 1920260.586363: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1133421 ofs=729088
+       <unknown>-12695 (-----) [004] .... 1920260.586364: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1092173 ofs=733184
+       <unknown>-12695 (-----) [004] .... 1920260.586365: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1124430 ofs=737280
+       <unknown>-12695 (-----) [004] .... 1920260.586365: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1143926 ofs=741376
+       <unknown>-12695 (-----) [004] .... 1920260.586366: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1090109 ofs=745472
+       <unknown>-12695 (-----) [004] .... 1920260.586366: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1102012 ofs=749568
+       <unknown>-12695 (-----) [004] .... 1920260.586367: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1154930 ofs=753664
+       <unknown>-12695 (-----) [004] .... 1920260.586368: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1132993 ofs=757760
+       <unknown>-12695 (-----) [004] .... 1920260.586369: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1430780 ofs=761856
+       <unknown>-12695 (-----) [004] .... 1920260.586369: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1197452 ofs=765952
+       <unknown>-12695 (-----) [004] .... 1920260.586369: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1075111 ofs=770048
+       <unknown>-12695 (-----) [004] .... 1920260.586370: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1275616 ofs=774144
+       <unknown>-12695 (-----) [004] .... 1920260.586370: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1444981 ofs=778240
+       <unknown>-12695 (-----) [004] .... 1920260.586371: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1452592 ofs=782336
+       <unknown>-12695 (-----) [004] .... 1920260.586374: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1102857 ofs=786432
+       <unknown>-12695 (-----) [004] .... 1920260.586376: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1406969 ofs=790528
+       <unknown>-12695 (-----) [004] .... 1920260.586378: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1522553 ofs=794624
+       <unknown>-12695 (-----) [004] .... 1920260.586378: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1260771 ofs=798720
+       <unknown>-12695 (-----) [004] .... 1920260.586379: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1474649 ofs=802816
+       <unknown>-12695 (-----) [004] .... 1920260.586379: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1268708 ofs=806912
+       <unknown>-12695 (-----) [004] .... 1920260.586379: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1346144 ofs=811008
+       <unknown>-12695 (-----) [004] .... 1920260.586380: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1081167 ofs=815104
+       <unknown>-12695 (-----) [004] .... 1920260.586380: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1137677 ofs=819200
+       <unknown>-12695 (-----) [004] .... 1920260.586381: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1161175 ofs=823296
+       <unknown>-12695 (-----) [004] .... 1920260.586381: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1461331 ofs=827392
+       <unknown>-12695 (-----) [004] .... 1920260.586492: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1347219 ofs=831488
+       <unknown>-12695 (-----) [004] .... 1920260.586494: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1290004 ofs=835584
+       <unknown>-12695 (-----) [004] .... 1920260.586494: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1299174 ofs=839680
+       <unknown>-12695 (-----) [004] .... 1920260.586496: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1317595 ofs=843776
+       <unknown>-12695 (-----) [004] .... 1920260.586496: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1484924 ofs=847872
+       <unknown>-12695 (-----) [004] .... 1920260.586497: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1169920 ofs=851968
+       <unknown>-12695 (-----) [004] .... 1920260.586501: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1359189 ofs=856064
+       <unknown>-12695 (-----) [004] .... 1920260.586501: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1307842 ofs=860160
+       <unknown>-12695 (-----) [004] .... 1920260.586502: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1237858 ofs=864256
+       <unknown>-12695 (-----) [004] .... 1920260.586502: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1189461 ofs=868352
+       <unknown>-12695 (-----) [004] .... 1920260.586503: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1223232 ofs=872448
+       <unknown>-12695 (-----) [004] .... 1920260.586503: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1104076 ofs=876544
+       <unknown>-12695 (-----) [004] .... 1920260.586504: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1079223 ofs=880640
+       <unknown>-12695 (-----) [004] .... 1920260.586504: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1092537 ofs=884736
+       <unknown>-12695 (-----) [004] .... 1920260.586505: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1353960 ofs=888832
+       <unknown>-12695 (-----) [004] .... 1920260.586505: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1346330 ofs=892928
+       <unknown>-12695 (-----) [004] .... 1920260.586506: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1345764 ofs=897024
+       <unknown>-12695 (-----) [004] .... 1920260.586507: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1363913 ofs=901120
+       <unknown>-12695 (-----) [004] .... 1920260.586508: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1319570 ofs=905216
+       <unknown>-12695 (-----) [004] .... 1920260.586508: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1367024 ofs=909312
+       <unknown>-12695 (-----) [004] .... 1920260.586508: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1333808 ofs=913408
+       <unknown>-12695 (-----) [004] .... 1920260.586509: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1158627 ofs=917504
+       <unknown>-12695 (-----) [004] .... 1920260.586509: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1300368 ofs=921600
+       <unknown>-12695 (-----) [004] .... 1920260.586510: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1245363 ofs=925696
+       <unknown>-12695 (-----) [004] .... 1920260.586510: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1345609 ofs=929792
+       <unknown>-12695 (-----) [004] .... 1920260.586510: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1393826 ofs=933888
+       <unknown>-12695 (-----) [004] .... 1920260.586511: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1200552 ofs=937984
+       <unknown>-12695 (-----) [004] .... 1920260.586511: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1170885 ofs=942080
+       <unknown>-12695 (-----) [004] .... 1920260.586512: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1536209 ofs=946176
+       <unknown>-12695 (-----) [004] .... 1920260.586512: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1189630 ofs=950272
+       <unknown>-12695 (-----) [004] .... 1920260.586513: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1121010 ofs=954368
+       <unknown>-12695 (-----) [004] .... 1920260.586514: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1324474 ofs=958464
+       <unknown>-12697 (-----) [007] .... 1920260.586578: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1129628 ofs=299008
+       <unknown>-12697 (-----) [007] .... 1920260.586579: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1307120 ofs=303104
+       <unknown>-12697 (-----) [007] .... 1920260.586580: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1347284 ofs=307200
+       <unknown>-12697 (-----) [007] .... 1920260.586580: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1312996 ofs=311296
+       <unknown>-12697 (-----) [007] .... 1920260.586581: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1170623 ofs=315392
+       <unknown>-12697 (-----) [007] .... 1920260.586581: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1359281 ofs=319488
+       <unknown>-12697 (-----) [007] .... 1920260.586582: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1180021 ofs=323584
+       <unknown>-12697 (-----) [007] .... 1920260.586582: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1195728 ofs=327680
+       <unknown>-12697 (-----) [007] .... 1920260.586582: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1163642 ofs=331776
+       <unknown>-12697 (-----) [007] .... 1920260.586587: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1152538 ofs=335872
+       <unknown>-12697 (-----) [007] .... 1920260.586589: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1345922 ofs=339968
+       <unknown>-12697 (-----) [007] .... 1920260.586589: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1343604 ofs=344064
+       <unknown>-12697 (-----) [007] .... 1920260.586721: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1399371 ofs=479232
+       <unknown>-12697 (-----) [007] .... 1920260.586723: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1106549 ofs=483328
+       <unknown>-12697 (-----) [007] .... 1920260.586724: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1331546 ofs=487424
+       <unknown>-12697 (-----) [007] .... 1920260.586724: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1299299 ofs=491520
+       <unknown>-12697 (-----) [007] .... 1920260.586725: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1288883 ofs=495616
+       <unknown>-12697 (-----) [007] .... 1920260.586725: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1399049 ofs=499712
+       <unknown>-12697 (-----) [007] .... 1920260.586726: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1146931 ofs=503808
+       <unknown>-12697 (-----) [007] .... 1920260.586726: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1296592 ofs=507904
+       <unknown>-12697 (-----) [007] .... 1920260.586727: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1468397 ofs=512000
+       <unknown>-12697 (-----) [007] .... 1920260.586727: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1215698 ofs=516096
+       <unknown>-12697 (-----) [007] .... 1920260.586727: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1177341 ofs=520192
+       <unknown>-12697 (-----) [007] .... 1920260.586731: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1189162 ofs=524288
+       <unknown>-12697 (-----) [007] .... 1920260.586732: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1435997 ofs=528384
+       <unknown>-12697 (-----) [007] .... 1920260.586732: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1209896 ofs=532480
+       <unknown>-12697 (-----) [007] .... 1920260.586733: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1255888 ofs=536576
+       <unknown>-12697 (-----) [007] .... 1920260.586734: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1234200 ofs=540672
+       <unknown>-12697 (-----) [007] .... 1920260.586734: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1422854 ofs=544768
+       <unknown>-12697 (-----) [007] .... 1920260.586735: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1435794 ofs=548864
+       <unknown>-12697 (-----) [007] .... 1920260.586735: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1236279 ofs=552960
+       <unknown>-12697 (-----) [007] .... 1920260.586736: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1485732 ofs=557056
+       <unknown>-12683 (-----) [005] .... 1920260.586743: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1417198 ofs=561152
+       <unknown>-12683 (-----) [005] .... 1920260.586746: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1469450 ofs=565248
+       <unknown>-12696 (-----) [004] .... 1920260.587465: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1489023 ofs=1040384
+       <unknown>-12696 (-----) [004] .... 1920260.587469: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1449498 ofs=1044480
+       <unknown>-12696 (-----) [004] .... 1920260.587469: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1447737 ofs=1048576
+       <unknown>-12696 (-----) [004] .... 1920260.587470: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1124530 ofs=1052672
+       <unknown>-12696 (-----) [004] .... 1920260.587476: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1246743 ofs=1056768
+       <unknown>-12696 (-----) [004] .... 1920260.587476: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1441927 ofs=1060864
+       <unknown>-12696 (-----) [004] .... 1920260.587477: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1280581 ofs=1064960
+       <unknown>-12696 (-----) [004] .... 1920260.587477: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1289438 ofs=1069056
+       <unknown>-12696 (-----) [004] .... 1920260.587477: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1464236 ofs=1073152
+       <unknown>-12696 (-----) [004] .... 1920260.587478: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1125808 ofs=1077248
+       <unknown>-12696 (-----) [004] .... 1920260.587478: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1329385 ofs=1081344
+       <unknown>-12696 (-----) [004] .... 1920260.587480: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1314093 ofs=1085440
+       <unknown>-12696 (-----) [004] .... 1920260.587480: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1201837 ofs=1089536
+       <unknown>-12696 (-----) [004] .... 1920260.587481: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1327734 ofs=1093632
+       <unknown>-12696 (-----) [004] .... 1920260.587481: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1406568 ofs=1097728
+       <unknown>-12696 (-----) [004] .... 1920260.587481: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1331873 ofs=1101824
+       <unknown>-12696 (-----) [004] .... 1920260.587482: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1331898 ofs=1105920
+       <unknown>-12696 (-----) [004] .... 1920260.587482: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1331917 ofs=1110016
+       <unknown>-12696 (-----) [004] .... 1920260.587483: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1332091 ofs=1114112
+       <unknown>-12696 (-----) [004] .... 1920260.587483: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1108186 ofs=1118208
+       <unknown>-12696 (-----) [004] .... 1920260.587486: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1182631 ofs=1122304
+       <unknown>-12696 (-----) [004] .... 1920260.587486: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1085941 ofs=1126400
+       <unknown>-12696 (-----) [004] .... 1920260.587487: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1433982 ofs=1130496
+       <unknown>-12696 (-----) [004] .... 1920260.587487: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1387028 ofs=1134592
+       <unknown>-12696 (-----) [004] .... 1920260.587488: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1353117 ofs=1138688
+       <unknown>-12696 (-----) [004] .... 1920260.587489: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1352364 ofs=1142784
+       <unknown>-12696 (-----) [004] .... 1920260.587489: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1144513 ofs=1146880
+       <unknown>-12696 (-----) [004] .... 1920260.587490: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1403984 ofs=1150976
+       <unknown>-12696 (-----) [004] .... 1920260.587490: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1278970 ofs=1155072
+       <unknown>-12696 (-----) [004] .... 1920260.587491: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1326743 ofs=1159168
+       <unknown>-12696 (-----) [004] .... 1920260.587491: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1221809 ofs=1163264
+       <unknown>-12696 (-----) [004] .... 1920260.587492: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1268668 ofs=1167360
+       <unknown>-12695 (-----) [005] .... 1920260.587502: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1074544 ofs=962560
+       <unknown>-12695 (-----) [005] .... 1920260.587506: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1074294 ofs=966656
+       <unknown>-12695 (-----) [005] .... 1920260.587506: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1075097 ofs=970752
+       <unknown>-12695 (-----) [005] .... 1920260.587507: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1162407 ofs=974848
+       <unknown>-12695 (-----) [005] .... 1920260.587507: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1141370 ofs=978944
+       <unknown>-12695 (-----) [005] .... 1920260.587508: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1306487 ofs=983040
+       <unknown>-12695 (-----) [005] .... 1920260.587508: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1306434 ofs=987136
+       <unknown>-12695 (-----) [005] .... 1920260.587514: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1306347 ofs=991232
+       <unknown>-12695 (-----) [005] .... 1920260.587514: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1306247 ofs=995328
+       <unknown>-12695 (-----) [005] .... 1920260.587515: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1306195 ofs=999424
+       <unknown>-12695 (-----) [005] .... 1920260.587516: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1306039 ofs=1003520
+       <unknown>-12695 (-----) [005] .... 1920260.587516: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1305983 ofs=1007616
+       <unknown>-12694 (-----) [006] .... 1920260.587701: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1216391 ofs=1171456
+       <unknown>-12694 (-----) [006] .... 1920260.587705: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1262462 ofs=1175552
+       <unknown>-12694 (-----) [006] .... 1920260.587706: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1358114 ofs=1179648
+       <unknown>-12694 (-----) [006] .... 1920260.587706: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1357898 ofs=1183744
+       <unknown>-12694 (-----) [006] .... 1920260.587707: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1237003 ofs=1187840
+       <unknown>-12694 (-----) [006] .... 1920260.587707: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1126319 ofs=1191936
+       <unknown>-12694 (-----) [006] .... 1920260.587708: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1415489 ofs=1196032
+       <unknown>-12694 (-----) [006] .... 1920260.587708: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1279558 ofs=1200128
+       <unknown>-12694 (-----) [006] .... 1920260.587708: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1434022 ofs=1204224
+       <unknown>-12694 (-----) [006] .... 1920260.587709: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1220130 ofs=1208320
+       <unknown>-12694 (-----) [006] .... 1920260.587710: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1163037 ofs=1212416
+       <unknown>-12694 (-----) [006] .... 1920260.587711: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1404501 ofs=1216512
+       <unknown>-12694 (-----) [006] .... 1920260.587711: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1406287 ofs=1220608
+       <unknown>-12697 (-----) [007] .... 1920260.588132: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1355143 ofs=1376256
+       <unknown>-12697 (-----) [007] .... 1920260.588136: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1213923 ofs=1380352
+       <unknown>-12697 (-----) [007] .... 1920260.588136: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1243190 ofs=1384448
+       <unknown>-12697 (-----) [007] .... 1920260.588143: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1300698 ofs=1388544
+       <unknown>-12697 (-----) [007] .... 1920260.588144: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1482568 ofs=1392640
+       <unknown>-12697 (-----) [007] .... 1920260.588144: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1461789 ofs=1396736
+       <unknown>-12697 (-----) [007] .... 1920260.588145: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1242314 ofs=1400832
+       <unknown>-12697 (-----) [007] .... 1920260.588145: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1471996 ofs=1404928
+       <unknown>-12697 (-----) [007] .... 1920260.588146: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1242742 ofs=1409024
+       <unknown>-12697 (-----) [007] .... 1920260.588146: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1242579 ofs=1413120
+       <unknown>-12697 (-----) [007] .... 1920260.588148: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1242553 ofs=1417216
+       <unknown>-12697 (-----) [007] .... 1920260.588148: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1457332 ofs=1421312
+       <unknown>-12697 (-----) [007] .... 1920260.588149: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1315431 ofs=1425408
+       <unknown>-12697 (-----) [007] .... 1920260.588149: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1080653 ofs=1429504
+       <unknown>-12697 (-----) [007] .... 1920260.588149: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1324174 ofs=1433600
+       <unknown>-12697 (-----) [007] .... 1920260.588150: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1324142 ofs=1437696
+       <unknown>-12697 (-----) [007] .... 1920260.588150: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1157760 ofs=1441792
+       <unknown>-12697 (-----) [007] .... 1920260.588151: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1075059 ofs=1445888
+       <unknown>-12683 (-----) [006] .... 1920260.589785: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1279192 ofs=1486848
+       <unknown>-12683 (-----) [006] .... 1920260.589790: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1278527 ofs=1490944
+       <unknown>-12683 (-----) [006] .... 1920260.589791: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1091778 ofs=1495040
+       <unknown>-12683 (-----) [006] .... 1920260.589791: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1339447 ofs=1499136
+       <unknown>-12683 (-----) [006] .... 1920260.589792: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1254007 ofs=1503232
+       <unknown>-12683 (-----) [006] .... 1920260.589793: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1115173 ofs=1507328
+       <unknown>-12683 (-----) [006] .... 1920260.589793: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1393985 ofs=1511424
+       <unknown>-12683 (-----) [006] .... 1920260.589794: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1369123 ofs=1515520
+       <unknown>-12683 (-----) [006] .... 1920260.589794: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1314257 ofs=1519616
+       <unknown>-12683 (-----) [006] .... 1920260.589802: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1404487 ofs=1523712
+       <unknown>-12683 (-----) [006] .... 1920260.589803: mm_filemap_add_to_page_cache: dev 0:64771 ino 59205 page=0000000000000000 pfn=1354554 ofs=1527808
+       <unknown>-12683 (-----) [006] .... 1920260.594312: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1141445 ofs=9801728
+       <unknown>-12683 (-----) [006] .... 1920260.594322: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1323774 ofs=231460864
+       <unknown>-12683 (-----) [006] .... 1920260.594326: mm_filemap_add_to_page_cache: dev 0:64771 ino 2 page=0000000000000000 pfn=1323772 ofs=10993664
+       <unknown>-12683 (-----) [006] .... 1920260.595212: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1481305 ofs=9805824
+       <unknown>-12683 (-----) [006] .... 1920260.595214: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1481306 ofs=9809920
+       <unknown>-12683 (-----) [006] .... 1920260.595214: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1481316 ofs=9814016
+       <unknown>-12683 (-----) [006] .... 1920260.595215: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1481340 ofs=9818112
+       <unknown>-12683 (-----) [006] .... 1920260.595216: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1394587 ofs=9822208
+       <unknown>-12683 (-----) [006] .... 1920260.595216: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103455 ofs=9826304
+       <unknown>-12683 (-----) [006] .... 1920260.595217: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103271 ofs=9830400
+       <unknown>-12683 (-----) [006] .... 1920260.595218: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103168 ofs=9834496
+       <unknown>-12683 (-----) [006] .... 1920260.595218: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103145 ofs=9838592
+       <unknown>-12683 (-----) [006] .... 1920260.595219: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103115 ofs=9842688
+       <unknown>-12683 (-----) [006] .... 1920260.595222: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103057 ofs=9846784
+       <unknown>-12683 (-----) [006] .... 1920260.595222: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1331958 ofs=9850880
+       <unknown>-12683 (-----) [006] .... 1920260.595227: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1356305 ofs=9854976
+       <unknown>-12683 (-----) [006] .... 1920260.595228: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103708 ofs=9859072
+       <unknown>-12683 (-----) [006] .... 1920260.595228: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1099286 ofs=9863168
+       <unknown>-12683 (-----) [006] .... 1920260.595229: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1435190 ofs=9867264
+       <unknown>-12683 (-----) [006] .... 1920260.595229: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1395504 ofs=9871360
+       <unknown>-12683 (-----) [006] .... 1920260.595230: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1352916 ofs=9875456
+       <unknown>-12683 (-----) [006] .... 1920260.595231: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1255529 ofs=9879552
+       <unknown>-12683 (-----) [006] .... 1920260.595231: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1336145 ofs=9883648
+       <unknown>-12683 (-----) [006] .... 1920260.595232: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1334143 ofs=9887744
+       <unknown>-12683 (-----) [006] .... 1920260.595232: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1328548 ofs=9891840
+       <unknown>-12683 (-----) [006] .... 1920260.595232: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1222215 ofs=9895936
+       <unknown>-12683 (-----) [006] .... 1920260.595233: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1461056 ofs=9900032
+       <unknown>-12683 (-----) [006] .... 1920260.595234: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1228276 ofs=9904128
+       <unknown>-12683 (-----) [006] .... 1920260.595235: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1151188 ofs=9908224
+       <unknown>-12683 (-----) [006] .... 1920260.595236: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1443605 ofs=9912320
+       <unknown>-12683 (-----) [006] .... 1920260.595236: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1146821 ofs=9916416
+       <unknown>-12683 (-----) [006] .... 1920260.595237: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103669 ofs=9920512
+       <unknown>-12683 (-----) [006] .... 1920260.595238: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103744 ofs=9924608
+       <unknown>-12683 (-----) [006] .... 1920260.595238: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1103868 ofs=9928704
+       <unknown>-12683 (-----) [006] .... 1920260.595789: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1465942 ofs=15855616
+       <unknown>-12683 (-----) [006] .... 1920260.595792: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1323712 ofs=261189632
+       <unknown>-12683 (-----) [006] .... 1920260.595998: mm_filemap_add_to_page_cache: dev 0:64771 ino 1 page=0000000000000000 pfn=1323701 ofs=262094848
+       <unknown>-12683 (-----) [006] .... 1920260.596191: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1222287 ofs=15859712
+       <unknown>-12683 (-----) [006] .... 1920260.596192: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1213146 ofs=15863808
+       <unknown>-12683 (-----) [006] .... 1920260.596192: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1310396 ofs=15867904
+       <unknown>-12683 (-----) [006] .... 1920260.596193: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1310177 ofs=15872000
+       <unknown>-12683 (-----) [006] .... 1920260.596194: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1187914 ofs=15876096
+       <unknown>-12683 (-----) [006] .... 1920260.596195: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1322409 ofs=15880192
+       <unknown>-12683 (-----) [006] .... 1920260.596195: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1282484 ofs=15884288
+       <unknown>-12683 (-----) [006] .... 1920260.596200: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1097245 ofs=15888384
+       <unknown>-12683 (-----) [006] .... 1920260.596200: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1416816 ofs=15892480
+       <unknown>-12683 (-----) [006] .... 1920260.596201: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1257125 ofs=15896576
+       <unknown>-12683 (-----) [006] .... 1920260.596201: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1403527 ofs=15900672
+       <unknown>-12683 (-----) [006] .... 1920260.596202: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1218006 ofs=15904768
+       <unknown>-12683 (-----) [006] .... 1920260.596202: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1153893 ofs=15908864
+       <unknown>-12683 (-----) [006] .... 1920260.596202: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1328023 ofs=15912960
+       <unknown>-12683 (-----) [006] .... 1920260.596203: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1465412 ofs=15917056
+       <unknown>-12683 (-----) [006] .... 1920260.596203: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1092448 ofs=15921152
+       <unknown>-12683 (-----) [006] .... 1920260.596204: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1239220 ofs=15925248
+       <unknown>-12683 (-----) [006] .... 1920260.596204: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1276491 ofs=15929344
+       <unknown>-12683 (-----) [006] .... 1920260.596205: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1262240 ofs=15933440
+       <unknown>-12683 (-----) [006] .... 1920260.596206: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1323793 ofs=15937536
+       <unknown>-12683 (-----) [006] .... 1920260.596206: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1074937 ofs=15941632
+       <unknown>-12683 (-----) [006] .... 1920260.596207: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1311157 ofs=15945728
+       <unknown>-12683 (-----) [006] .... 1920260.596207: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1308442 ofs=15949824
+       <unknown>-12683 (-----) [006] .... 1920260.596210: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1467709 ofs=15953920
+       <unknown>-12683 (-----) [006] .... 1920260.596211: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1394299 ofs=15958016
+       <unknown>-12683 (-----) [004] .... 1920260.612586: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1316156 ofs=344064
+       <unknown>-12683 (-----) [004] .... 1920260.612591: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1406323 ofs=348160
+       <unknown>-12683 (-----) [004] .... 1920260.612601: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1216972 ofs=352256
+       <unknown>-12683 (-----) [004] .... 1920260.612605: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1271924 ofs=356352
+       <unknown>-12683 (-----) [004] .... 1920260.612605: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1369225 ofs=360448
+       <unknown>-12683 (-----) [004] .... 1920260.612608: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1318474 ofs=364544
+       <unknown>-12683 (-----) [004] .... 1920260.612609: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1227283 ofs=368640
+       <unknown>-12683 (-----) [004] .... 1920260.612613: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1364376 ofs=372736
+       <unknown>-12683 (-----) [004] .... 1920260.612613: mm_filemap_add_to_page_cache: dev 0:64771 ino 6154 page=0000000000000000 pfn=1073400 ofs=376832
diff --git a/startop/scripts/iorap/test_fixtures/compiler/test_result_with_duration.TraceFile.pb b/startop/scripts/iorap/test_fixtures/compiler/test_result_with_duration.TraceFile.pb
new file mode 100644
index 0000000..ab3df45
--- /dev/null
+++ b/startop/scripts/iorap/test_fixtures/compiler/test_result_with_duration.TraceFile.pb
Binary files differ
diff --git a/startop/scripts/iorap/test_fixtures/compiler/test_result_without_duration.TraceFile.pb b/startop/scripts/iorap/test_fixtures/compiler/test_result_without_duration.TraceFile.pb
new file mode 100644
index 0000000..17cb116
--- /dev/null
+++ b/startop/scripts/iorap/test_fixtures/compiler/test_result_without_duration.TraceFile.pb
Binary files differ
diff --git a/startop/scripts/lib/cmd_utils.py b/startop/scripts/lib/cmd_utils.py
index bc5ca31..6071f14 100644
--- a/startop/scripts/lib/cmd_utils.py
+++ b/startop/scripts/lib/cmd_utils.py
@@ -26,6 +26,18 @@
 TIMEOUT = 50
 SIMULATE = False
 
+def run_command_nofail(cmd: List[str], **kwargs) -> None:
+  """Runs cmd list with default timeout.
+
+     Throws exception if the execution fails.
+  """
+  my_kwargs = {"timeout": TIMEOUT, "shell": False, "simulate": False}
+  my_kwargs.update(kwargs)
+  passed, out = execute_arbitrary_command(cmd, **my_kwargs)
+  if not passed:
+    raise RuntimeError(
+      "Failed to execute %s (kwargs=%s), output=%s" % (cmd, kwargs, out))
+
 def run_adb_shell_command(cmd: str) -> Tuple[bool, str]:
   """Runs command using adb shell.
 
diff --git a/startop/scripts/lib/logcat_utils.py b/startop/scripts/lib/logcat_utils.py
index 13b1c3a..8a3d00b 100644
--- a/startop/scripts/lib/logcat_utils.py
+++ b/startop/scripts/lib/logcat_utils.py
@@ -22,7 +22,7 @@
 from typing import Optional, Pattern
 
 # local import
-import print_utils
+import lib.print_utils as print_utils
 
 def parse_logcat_datetime(timestamp: str) -> Optional[datetime]:
   """Parses the timestamp of logcat.
@@ -61,7 +61,7 @@
                                             pattern: Pattern,
                                             timeout: datetime) -> Optional[str]:
   # Show the year in the timestampe.
-  logcat_cmd = 'adb logcat -v year -v threadtime -T'.split()
+  logcat_cmd = 'adb logcat -v UTC -v year -v threadtime -T'.split()
   logcat_cmd.append(str(timestamp))
   print_utils.debug_print('[LOGCAT]:' + ' '.join(logcat_cmd))
 
diff --git a/startop/scripts/lib/print_utils.py b/startop/scripts/lib/print_utils.py
index c33e0f9..8c5999d 100644
--- a/startop/scripts/lib/print_utils.py
+++ b/startop/scripts/lib/print_utils.py
@@ -27,3 +27,41 @@
 
 def error_print(*args, **kwargs):
   print('[ERROR]:', *args, file=sys.stderr, **kwargs)
+
+def _expand_gen_repr(args):
+  """Like repr but any generator-like object has its iterator consumed
+  and then called repr on."""
+  new_args_list = []
+  for i in args:
+    # detect iterable objects that do not have their own override of __str__
+    if hasattr(i, '__iter__'):
+      to_str = getattr(i, '__str__')
+      if to_str.__objclass__ == object:
+        # the repr for a generator is just type+address, expand it out instead.
+        new_args_list.append([_expand_gen_repr([j])[0] for j in i])
+        continue
+    # normal case: uses the built-in to-string
+    new_args_list.append(i)
+  return new_args_list
+
+def debug_print_gen(*args, **kwargs):
+  """Like _debug_print but will turn any iterable args into a list."""
+  if not DEBUG:
+    return
+
+  new_args_list = _expand_gen_repr(args)
+  debug_print(*new_args_list, **kwargs)
+
+def debug_print_nd(*args, **kwargs):
+  """Like _debug_print but will turn any NamedTuple-type args into a string."""
+  if not DEBUG:
+    return
+
+  new_args_list = []
+  for i in args:
+    if hasattr(i, '_field_types'):
+      new_args_list.append("%s: %s" % (i.__name__, i._field_types))
+    else:
+      new_args_list.append(i)
+
+  debug_print(*new_args_list, **kwargs)
diff --git a/startop/scripts/trace_analyzer/lib/trace2db.py b/startop/scripts/trace_analyzer/lib/trace2db.py
index f60d6ab..42a33af 100644
--- a/startop/scripts/trace_analyzer/lib/trace2db.py
+++ b/startop/scripts/trace_analyzer/lib/trace2db.py
@@ -19,6 +19,7 @@
 from sqlalchemy import create_engine
 from sqlalchemy import Column, Date, Integer, Float, String, ForeignKey
 from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.orm import relationship
 
 from sqlalchemy.orm import sessionmaker
 
@@ -43,6 +44,10 @@
   function = Column(String, nullable=False)
   function_args = Column(String, nullable=False)
 
+  # 1:1 relation with MmFilemapAddToPageCache.
+  mm_filemap_add_to_page_cache = relationship("MmFilemapAddToPageCache",
+                                              back_populates="raw_ftrace_entry")
+
   @staticmethod
   def parse_dict(line):
     # '           <...>-5521  (-----) [003] ...1 17148.446877: tracing_mark_write: trace_event_clock_sync: parent_ts=17148.447266'
@@ -155,6 +160,9 @@
   pfn = Column(Integer, nullable=False)
   ofs = Column(Integer, nullable=False)
 
+  # 1:1 relation with RawFtraceEntry.
+  raw_ftrace_entry = relationship("RawFtraceEntry", uselist=False)
+
   @staticmethod
   def parse_dict(function_args, id = None):
     # dev 253:6 ino b2c7 page=00000000ec787cd9 pfn=1478539 ofs=4096
@@ -251,6 +259,8 @@
 def parse_file_buf(filebuf, session, engine, raw_ftrace_entry_filter, limit=None) -> int:
   global _FLUSH_LIMIT
   count = 0
+  # count and id are not equal, because count still increases for invalid lines.
+  id = 0
 
   pending_entries = []
   pending_sched_switch = []
@@ -305,9 +315,10 @@
       continue
 
     pending_entries.append(raw_ftrace_entry)
+    id = id + 1
 
     if raw_ftrace_entry['function'] == 'sched_switch':
-      sched_switch = SchedSwitch.parse_dict(raw_ftrace_entry['function_args'], count)
+      sched_switch = SchedSwitch.parse_dict(raw_ftrace_entry['function_args'], id)
 
       if not sched_switch:
         print("WARNING: Failed to parse sched_switch: " + l)
@@ -315,7 +326,7 @@
         pending_sched_switch.append(sched_switch)
 
     elif raw_ftrace_entry['function'] == 'sched_blocked_reason':
-      sbr = SchedBlockedReason.parse_dict(raw_ftrace_entry['function_args'], count)
+      sbr = SchedBlockedReason.parse_dict(raw_ftrace_entry['function_args'], id)
 
       if not sbr:
         print("WARNING: Failed to parse sched_blocked_reason: " + l)
@@ -323,7 +334,8 @@
         pending_sched_blocked_reasons.append(sbr)
 
     elif raw_ftrace_entry['function'] == 'mm_filemap_add_to_page_cache':
-      d = MmFilemapAddToPageCache.parse_dict(raw_ftrace_entry['function_args'], count)
+      d = MmFilemapAddToPageCache.parse_dict(raw_ftrace_entry['function_args'],
+                                             id)
       if not d:
         print("WARNING: Failed to parse mm_filemap_add_to_page_cache: " + l)
       else:
diff --git a/startop/scripts/trace_analyzer/lib/trace2db_test.py b/startop/scripts/trace_analyzer/lib/trace2db_test.py
index b67cffa..3b326f0 100755
--- a/startop/scripts/trace_analyzer/lib/trace2db_test.py
+++ b/startop/scripts/trace_analyzer/lib/trace2db_test.py
@@ -32,17 +32,10 @@
 """
 
 # global imports
-from contextlib import contextmanager
 import io
-import shlex
-import sys
-import typing
-
 from copy import deepcopy
 
 # pip imports
-import pytest
-
 # local imports
 from trace2db import *
 
@@ -197,6 +190,33 @@
   assert_eq_ignore_id(MmFilemapAddToPageCache(dev=64774, dev_major=253, dev_minor=6,
       ino=0x9a64, page=0x000000006e0f8322, pfn=797894, ofs=4096), second_to_last_row)
 
+def test_timestamp_filter():
+  test_contents = """
+    MediaStoreImpor-27212 (27176) [000] .... 16136.595194: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=0000000060e990c7 pfn=677646 ofs=159744
+    NonUserFacing6-5246  ( 1322) [005] .... 16139.357581: mm_filemap_add_to_page_cache: dev 253:6 ino 9a64 page=000000006e0f8322 pfn=797894 ofs=4096
+    MediaStoreImpor-27212 (27176) [000] .... 16136.604126: mm_filemap_add_to_page_cache: dev 253:6 ino b1d8 page=0000000098d4d2e2 pfn=829676 ofs=0
+  """
+
+  t2d = parse_trace_file_to_db(test_contents)
+  session = t2d.session
+
+  end_time = 16137.0
+
+  results = session.query(MmFilemapAddToPageCache).join(
+      MmFilemapAddToPageCache.raw_ftrace_entry).filter(
+      RawFtraceEntry.timestamp <= end_time).order_by(
+      MmFilemapAddToPageCache.id).all()
+
+  assert len(results) == 2
+  assert_eq_ignore_id(
+      MmFilemapAddToPageCache(dev=64774, dev_major=253, dev_minor=6,
+                              ino=0x7580, page=0x0000000060e990c7, pfn=677646,
+                              ofs=159744), results[0])
+  assert_eq_ignore_id(
+      MmFilemapAddToPageCache(dev=64774, dev_major=253, dev_minor=6,
+                              ino=0xb1d8, page=0x0000000098d4d2e2, pfn=829676,
+                              ofs=0), results[1])
+
 
 if __name__ == '__main__':
   pytest.main()
diff --git a/startop/scripts/trace_analyzer/test_fixtures/common_systrace b/startop/scripts/trace_analyzer/test_fixtures/common_systrace
new file mode 100644
index 0000000..802cb55
--- /dev/null
+++ b/startop/scripts/trace_analyzer/test_fixtures/common_systrace
@@ -0,0 +1,518 @@
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 411983/411983   #P:8
+#
+#                                      _-----=> irqs-off
+#                                     / _----=> need-resched
+#                                    | / _---=> hardirq/softirq
+#                                    || / _--=> preempt-depth
+#                                    ||| /     delay
+#           TASK-PID    TGID   CPU#  ||||    TIMESTAMP  FUNCTION
+#              | |        |      |   ||||       |         |
+           <...>-14603 (-----) [000] ...1 14592.893157: tracing_mark_write: trace_event_clock_sync: parent_ts=14592.892578
+           <...>-14603 (-----) [000] ...1 14592.893172: tracing_mark_write: trace_event_clock_sync: realtime_ts=1557129597951
+           <...>-18150 (-----) [004] d..2 14594.182110: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=D ==> next_comm=kworker/u16:16 next_pid=23269 next_prio=120
+  kworker/u16:16-23269 (23269) [004] d.h3 14594.182228: sched_blocked_reason: pid=18150 iowait=0 caller=a6xx_oob_set+0x194/0x3dc
+  kworker/u16:16-23269 (23269) [004] d..2 14594.182248: sched_switch: prev_comm=kworker/u16:16 prev_pid=23269 prev_prio=120 prev_state=D ==> next_comm=kworker/u16:18 next_pid=18150 next_prio=120
+           <...>-18150 (-----) [004] d..2 14594.182312: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=D ==> next_comm=swapper/4 next_pid=0 next_prio=120
+           <...>-18150 (-----) [004] d..2 14594.182488: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=D ==> next_comm=swapper/4 next_pid=0 next_prio=120
+  kworker/u16:16-23269 (23269) [005] d..2 14594.182610: sched_switch: prev_comm=kworker/u16:16 prev_pid=23269 prev_prio=120 prev_state=S ==> next_comm=swapper/5 next_pid=0 next_prio=120
+           <...>-18150 (-----) [004] d..2 14594.182626: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=D ==> next_comm=swapper/4 next_pid=0 next_prio=120
+           <...>-18150 (-----) [004] d..2 14594.182755: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=D ==> next_comm=swapper/4 next_pid=0 next_prio=120
+           <...>-18150 (-----) [004] d..2 14594.182975: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=D ==> next_comm=swapper/4 next_pid=0 next_prio=120
+           <...>-18150 (-----) [004] d..2 14594.183209: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=D ==> next_comm=swapper/4 next_pid=0 next_prio=120
+           <...>-18150 (-----) [004] d..2 14594.183371: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=D ==> next_comm=swapper/4 next_pid=0 next_prio=120
+           <...>-18150 (-----) [004] d..2 14594.184286: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=S ==> next_comm=swapper/4 next_pid=0 next_prio=120
+  kworker/u16:16-23269 (23269) [005] d..2 14594.184495: sched_switch: prev_comm=kworker/u16:16 prev_pid=23269 prev_prio=120 prev_state=S ==> next_comm=swapper/5 next_pid=0 next_prio=120
+           <...>-18150 (-----) [004] d..2 14594.184498: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=S ==> next_comm=swapper/4 next_pid=0 next_prio=120
+     ksoftirqd/4-47    (   47) [004] d..2 14594.185678: sched_switch: prev_comm=ksoftirqd/4 prev_pid=47 prev_prio=120 prev_state=S ==> next_comm=swapper/4 next_pid=0 next_prio=120
+     kworker/6:2-10610 (10610) [006] d..2 14594.186012: sched_switch: prev_comm=kworker/6:2 prev_pid=10610 prev_prio=120 prev_state=S ==> next_comm=swapper/6 next_pid=0 next_prio=120
+           <...>-656   (-----) [001] .... 14594.219464: binder_set_priority: proc=625 thread=656 old=110 => new=120 desired=120
+           <...>-1803  (-----) [000] d..2 14594.219595: sched_switch: prev_comm=ndroid.systemui prev_pid=1803 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+           <...>-3359  (-----) [001] ...1 14594.219856: tracing_mark_write: S|1368|launching: com.google.android.dialer|0
+           <...>-3359  (-----) [001] ...1 14594.219863: tracing_mark_write: B|1368|MetricsLogger:launchObserverNotifyActivityLaunched
+           <...>-3359  (-----) [001] ...1 14594.219869: tracing_mark_write: B|1368|MetricsLogger:convertActivityRecordToProto
+           <...>-1398  (-----) [006] ...1 14594.220160: tracing_mark_write: B|1368|updateInputWindows
+           <...>-3359  (-----) [001] .... 14594.220230: binder_set_priority: proc=1368 thread=3359 old=110 => new=120 desired=120
+           <...>-1398  (-----) [006] ...1 14594.220588: tracing_mark_write: B|1368|android.os.Handler: com.android.server.wm.AppWindowToken$1
+           <...>-1398  (-----) [006] ...1 14594.220722: tracing_mark_write: B|1368|ResourcesManager#getResources
+           <...>-1052  (-----) [002] d..2 14594.220884: sched_switch: prev_comm=statsd.writer prev_pid=1052 prev_prio=120 prev_state=S ==> next_comm=UiThreadHelper next_pid=2045 next_prio=118
+           <...>-1398  (-----) [006] ...1 14594.220926: tracing_mark_write: B|1368|Theme::ApplyStyle
+           <...>-1398  (-----) [006] ...1 14594.220929: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-2007  (-----) [007] ...1 14594.220996: tracing_mark_write: B|2007|Choreographer#doFrame
+           <...>-2007  (-----) [007] ...1 14594.221005: tracing_mark_write: B|2007|animation
+           <...>-1398  (-----) [006] ...1 14594.221015: tracing_mark_write: B|1368|ResourcesManager#getResources
+           <...>-2045  (-----) [002] ...2 14594.221035: binder_set_priority: proc=1368 thread=1903 old=120 => new=118 desired=118
+           <...>-2045  (-----) [002] d..2 14594.221065: sched_switch: prev_comm=UiThreadHelper prev_pid=2045 prev_prio=118 prev_state=S ==> next_comm=Binder:1368_4 next_pid=1903 next_prio=118
+           <...>-1398  (-----) [006] ...1 14594.221080: tracing_mark_write: B|1368|AssetManager::SetApkAssets
+           <...>-2007  (-----) [007] ...1 14594.221110: tracing_mark_write: B|2007|traversal
+           <...>-656   (-----) [000] ...1 14594.221137: tracing_mark_write: B|625|requestNextVsync
+           <...>-656   (-----) [000] ...1 14594.221141: tracing_mark_write: B|625|resetIdleTimer
+           <...>-2007  (-----) [007] ...1 14594.221146: tracing_mark_write: B|2007|draw
+           <...>-2007  (-----) [007] ...1 14594.221160: tracing_mark_write: B|2007|Record View#draw()
+           <...>-660   (-----) [005] d..2 14594.221285: sched_switch: prev_comm=app prev_pid=660 prev_prio=97 prev_state=S ==> next_comm=RenderThread next_pid=2738 next_prio=110
+           <...>-658   (-----) [004] d..2 14594.221327: sched_switch: prev_comm=DispSync prev_pid=658 prev_prio=97 prev_state=S ==> next_comm=android.display next_pid=1397 next_prio=117
+           <...>-2738  (-----) [005] ...1 14594.221342: tracing_mark_write: B|2007|notifyFramePending
+           <...>-2738  (-----) [005] ...1 14594.221362: tracing_mark_write: B|2007|DrawFrame
+           <...>-2738  (-----) [005] ...1 14594.221369: tracing_mark_write: B|2007|query
+           <...>-2007  (-----) [007] d..2 14594.221369: sched_switch: prev_comm=s.nexuslauncher prev_pid=2007 prev_prio=110 prev_state=S ==> next_comm=swapper/7 next_pid=0 next_prio=120
+           <...>-1903  (-----) [002] .... 14594.221397: binder_set_priority: proc=1368 thread=1903 old=118 => new=120 desired=120
+           <...>-2738  (-----) [005] ...2 14594.221400: binder_set_priority: proc=625 thread=656 old=120 => new=110 desired=110
+           <...>-2738  (-----) [005] d..2 14594.221430: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=110
+           <...>-1368  (-----) [003] ...1 14594.221431: tracing_mark_write: B|1368|Lock contention on GC thread flip lock (owner tid: 0)
+           <...>-656   (-----) [005] ...1 14594.221460: tracing_mark_write: B|625|query
+           <...>-656   (-----) [005] .... 14594.221528: binder_set_priority: proc=625 thread=656 old=110 => new=120 desired=120
+           <...>-2738  (-----) [007] ...1 14594.221552: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...2 14594.221563: binder_set_priority: proc=625 thread=656 old=120 => new=110 desired=110
+           <...>-2738  (-----) [007] d..2 14594.221600: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=110
+           <...>-1368  (-----) [003] d..2 14594.221623: sched_switch: prev_comm=system_server prev_pid=1368 prev_prio=118 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120
+           <...>-656   (-----) [007] ...1 14594.221628: tracing_mark_write: B|625|query
+           <...>-23031 (-----) [001] d..2 14594.221643: sched_switch: prev_comm=UiAutomation prev_pid=23031 prev_prio=120 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-2738  (-----) [007] ...1 14594.221664: tracing_mark_write: B|2007|syncFrameState
+           <...>-2738  (-----) [007] ...1 14594.221697: tracing_mark_write: B|2007|prepareTree
+           <...>-23008 (-----) [005] d..2 14594.221706: sched_switch: prev_comm=hub.uiautomator prev_pid=23008 prev_prio=120 prev_state=S ==> next_comm=swapper/5 next_pid=0 next_prio=120
+           <...>-656   (-----) [000] .... 14594.221737: binder_set_priority: proc=625 thread=656 old=110 => new=120 desired=120
+           <...>-1803  (-----) [003] d..2 14594.221747: sched_switch: prev_comm=ndroid.systemui prev_pid=1803 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120
+           <...>-1397  (-----) [004] d..2 14594.221806: sched_switch: prev_comm=android.display prev_pid=1397 prev_prio=117 prev_state=S ==> next_comm=Binder:2007_A next_pid=4180 next_prio=120
+           <...>-1398  (-----) [006] d..2 14594.221816: sched_switch: prev_comm=android.anim prev_pid=1398 prev_prio=110 prev_state=R ==> next_comm=s.nexuslauncher next_pid=2007 next_prio=110
+           <...>-2738  (-----) [007] ...1 14594.221824: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...1 14594.221830: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...1 14594.221834: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...1 14594.221841: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...1 14594.221843: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...1 14594.221846: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...1 14594.221850: tracing_mark_write: B|2007|dequeueBuffer
+           <...>-2738  (-----) [007] ...2 14594.221864: binder_set_priority: proc=625 thread=656 old=120 => new=110 desired=110
+           <...>-2738  (-----) [007] d..2 14594.221985: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=R+ ==> next_comm=crtc_event:97 next_pid=303 next_prio=83
+           <...>-2007  (-----) [006] ...1 14594.221989: tracing_mark_write: B|2007|topResumedActivityChangeItem
+           <...>-303   (-----) [007] d..2 14594.222016: sched_switch: prev_comm=crtc_event:97 prev_pid=303 prev_prio=83 prev_state=S ==> next_comm=rcu_preempt next_pid=7 next_prio=120
+     rcu_preempt-7     (    7) [007] d..2 14594.222035: sched_switch: prev_comm=rcu_preempt prev_pid=7 prev_prio=120 prev_state=S ==> next_comm=RenderThread next_pid=2738 next_prio=110
+     migration/4-46    (   46) [004] d..2 14594.222037: sched_switch: prev_comm=migration/4 prev_pid=46 prev_prio=0 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=110
+           <...>-2738  (-----) [007] d..2 14594.222039: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=S ==> next_comm=kworker/u16:18 next_pid=18150 next_prio=120
+           <...>-656   (-----) [004] ...1 14594.222100: tracing_mark_write: B|625|dequeueBuffer
+           <...>-656   (-----) [004] ...1 14594.222114: tracing_mark_write: B|625|com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#1: 2
+           <...>-2007  (-----) [006] ...2 14594.222131: binder_set_priority: proc=1368 thread=1903 old=120 => new=110 desired=110
+           <...>-2007  (-----) [006] d..2 14594.222143: sched_switch: prev_comm=s.nexuslauncher prev_pid=2007 prev_prio=110 prev_state=S ==> next_comm=UiThreadHelper next_pid=2045 next_prio=118
+           <...>-2613  (-----) [001] d..2 14594.222158: sched_switch: prev_comm=ogle.android.as prev_pid=2613 prev_prio=120 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-18150 (-----) [007] d..2 14594.222193: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=S ==> next_comm=swapper/7 next_pid=0 next_prio=120
+           <...>-656   (-----) [004] .... 14594.222220: binder_set_priority: proc=625 thread=656 old=110 => new=120 desired=120
+           <...>-2738  (-----) [007] ...1 14594.222267: tracing_mark_write: B|2007|HWC release fence 36027 has signaled
+           <...>-656   (-----) [007] ...1 14594.223842: tracing_mark_write: B|625|queueBuffer
+           <...>-656   (-----) [007] ...1 14594.223845: tracing_mark_write: B|625|com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#1: 2
+           <...>-656   (-----) [007] ...1 14594.223871: tracing_mark_write: B|625|requestNextVsync
+           <...>-656   (-----) [007] ...1 14594.223873: tracing_mark_write: B|625|resetIdleTimer
+           <...>-656   (-----) [007] ...1 14594.223881: tracing_mark_write: B|625|addAndGetFrameTimestamps
+           <...>-1395  (-----) [001] d..2 14594.223909: sched_switch: prev_comm=android.ui prev_pid=1395 prev_prio=118 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-2738  (-----) [007] ...1 14594.223959: tracing_mark_write: B|2007|Trace GPU completion fence 36027
+           <...>-11799 (-----) [006] ...1 14594.224006: tracing_mark_write: B|2007|waiting for GPU completion 36027
+           <...>-11799 (-----) [006] ...1 14594.224009: tracing_mark_write: B|2007|waitForever
+           <...>-2613  (-----) [004] d..2 14594.224014: sched_switch: prev_comm=ogle.android.as prev_pid=2613 prev_prio=120 prev_state=S ==> next_comm=Binder:1803_6 next_pid=2173 next_prio=120
+           <...>-11799 (-----) [006] d..1 14594.224014: fence_enable_signal: driver=kgsl-timeline timeline=kgsl-3d0_13-s.nexuslauncher(200 context=27 seqno=78002
+           <...>-11799 (-----) [006] d..2 14594.224021: sched_switch: prev_comm=GPU completion prev_pid=11799 prev_prio=110 prev_state=S ==> next_comm=rcuop/6 next_pid=68 next_prio=120
+         rcuop/6-68    (   68) [006] d..2 14594.224044: sched_switch: prev_comm=rcuop/6 prev_pid=68 prev_prio=120 prev_state=S ==> next_comm=swapper/6 next_pid=0 next_prio=120
+           <...>-259   (-----) [006] d..2 14594.224132: sched_switch: prev_comm=kgsl_worker_thr prev_pid=259 prev_prio=97 prev_state=S ==> next_comm=Binder:2007_A next_pid=4180 next_prio=120
+           <...>-3206  (-----) [001] d..2 14594.224167: sched_switch: prev_comm=aiai-vc-0 prev_pid=3206 prev_prio=139 prev_state=R ==> next_comm=ndroid.systemui next_pid=1803 next_prio=120
+    lowpool[847]-14589 ( 2446) [005] d..1 14594.224300: mm_filemap_delete_from_page_cache: dev 0:1 ino 3d0034 page=000000008247d586 pfn=676904 ofs=0
+           <...>-1803  (-----) [001] d..2 14594.224302: sched_switch: prev_comm=ndroid.systemui prev_pid=1803 prev_prio=120 prev_state=S ==> next_comm=aiai-vc-0 next_pid=3206 next_prio=139
+           <...>-3206  (-----) [001] d..2 14594.224433: sched_switch: prev_comm=aiai-vc-0 prev_pid=3206 prev_prio=139 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-1903  (-----) [003] ...1 14594.224490: tracing_mark_write: B|1368|dispatchingStartProcess:com.google.android.dialer
+           <...>-1903  (-----) [003] ...1 14594.224659: tracing_mark_write: B|1368|wmLayout
+           <...>-1903  (-----) [003] ...1 14594.224666: tracing_mark_write: B|1368|performSurfacePlacement
+           <...>-1903  (-----) [003] ...1 14594.224683: tracing_mark_write: B|1368|applySurfaceChanges
+           <...>-1903  (-----) [003] ...1 14594.224688: tracing_mark_write: B|1368|openSurfaceTransaction
+           <...>-2738  (-----) [007] ...1 14594.224711: tracing_mark_write: B|2007|query
+           <...>-1903  (-----) [003] ...1 14594.224714: tracing_mark_write: B|1368|performLayout
+           <...>-2738  (-----) [007] ...1 14594.224714: tracing_mark_write: B|2007|query
+           <...>-1903  (-----) [003] ...1 14594.224723: tracing_mark_write: B|1368|applyPostLayoutPolicy
+           <...>-2738  (-----) [007] d..2 14594.224752: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=110
+           <...>-656   (-----) [007] .... 14594.224766: binder_set_priority: proc=625 thread=656 old=110 => new=120 desired=120
+           <...>-1398  (-----) [002] ...1 14594.224801: tracing_mark_write: B|1368|Theme::ApplyStyle
+           <...>-1398  (-----) [002] ...1 14594.224805: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-1398  (-----) [002] ...1 14594.224820: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-1398  (-----) [002] ...1 14594.224826: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-1398  (-----) [002] ...1 14594.224833: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-1398  (-----) [002] ...1 14594.224838: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-1398  (-----) [002] ...1 14594.224846: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-1398  (-----) [002] ...1 14594.224853: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-1398  (-----) [002] ...1 14594.224859: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-1398  (-----) [002] ...1 14594.224864: tracing_mark_write: B|1368|AssetManager::GetBag
+           <...>-18150 (-----) [006] d..2 14594.228407: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=R+ ==> next_comm=mmc-cmdqd/0 next_pid=440 next_prio=98
+           <...>-2738  (-----) [007] d..2 14594.228411: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=R+ ==> next_comm=kworker/7:0H next_pid=76 next_prio=100
+           <...>-1409  (-----) [004] ...1 14594.228417: tracing_mark_write: B|1368|Start proc: com.google.android.dialer
+           <...>-440   (-----) [006] d..2 14594.228418: sched_switch: prev_comm=mmc-cmdqd/0 prev_pid=440 prev_prio=98 prev_state=D ==> next_comm=kworker/u16:18 next_pid=18150 next_prio=120
+           <...>-76    (-----) [007] d..2 14594.228430: sched_switch: prev_comm=kworker/7:0H prev_pid=76 prev_prio=100 prev_state=R+ ==> next_comm=mmc-cmdqd/0 next_pid=440 next_prio=98
+           <...>-440   (-----) [007] d..2 14594.228434: sched_switch: prev_comm=mmc-cmdqd/0 prev_pid=440 prev_prio=98 prev_state=D ==> next_comm=kworker/7:0H next_pid=76 next_prio=100
+           <...>-18150 (-----) [006] d..3 14594.228442: sched_blocked_reason: pid=1398 iowait=1 caller=wait_on_page_bit_common+0x2a8/0x5f8
+           <...>-76    (-----) [007] d..2 14594.228442: sched_switch: prev_comm=kworker/7:0H prev_pid=76 prev_prio=100 prev_state=S ==> next_comm=RenderThread next_pid=2738 next_prio=110
+           <...>-2738  (-----) [007] ...2 14594.228446: binder_set_priority: proc=625 thread=656 old=120 => new=110 desired=110
+           <...>-18150 (-----) [006] d..2 14594.228447: sched_switch: prev_comm=kworker/u16:18 prev_pid=18150 prev_prio=120 prev_state=R+ ==> next_comm=android.anim next_pid=1398 next_prio=110
+           <...>-2738  (-----) [007] d..2 14594.228479: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=110
+           <...>-1409  (-----) [004] d..2 14594.228499: sched_switch: prev_comm=ActivityManager prev_pid=1409 prev_prio=118 prev_state=D ==> next_comm=Binder:965_2 next_pid=1041 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.229271: tracing_mark_write: B|625|handleTransaction
+           <...>-1773  (-----) [004] .... 14594.229285: binder_set_priority: proc=625 thread=1773 old=110 => new=120 desired=120
+           <...>-440   (-----) [007] d..2 14594.229301: sched_switch: prev_comm=mmc-cmdqd/0 prev_pid=440 prev_prio=98 prev_state=D ==> next_comm=RenderThread next_pid=2738 next_prio=110
+           <...>-2738  (-----) [007] ...1 14594.229318: tracing_mark_write: B|2007|HWC release fence 36028 has signaled
+           <...>-2738  (-----) [007] ...1 14594.229331: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...1 14594.229337: tracing_mark_write: B|2007|eglBeginFrame
+           <...>-2738  (-----) [007] ...1 14594.229352: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...1 14594.229354: tracing_mark_write: B|2007|query
+           <...>-791   (-----) [000] d..2 14594.229357: sched_switch: prev_comm=main prev_pid=791 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.229440: tracing_mark_write: B|625|doTransaction
+           <...>-13916 (-----) [002] d..2 14594.229482: sched_switch: prev_comm=HeapTaskDaemon prev_pid=13916 prev_prio=124 prev_state=D|K ==> next_comm=swapper/2 next_pid=0 next_prio=120
+           <...>-13917 (-----) [001] d..2 14594.229492: sched_blocked_reason: pid=13916 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-625   (-----) [003] ...1 14594.229492: tracing_mark_write: B|625|doTransaction
+           <...>-625   (-----) [003] ...1 14594.229507: tracing_mark_write: B|625|doTransaction
+           <...>-13917 (-----) [001] d..2 14594.229523: sched_switch: prev_comm=ReferenceQueueD prev_pid=13917 prev_prio=124 prev_state=D ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-13916 (-----) [002] d..2 14594.229535: sched_blocked_reason: pid=13917 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-625   (-----) [003] ...1 14594.229538: tracing_mark_write: B|625|doTransaction
+           <...>-2738  (-----) [007] ...1 14594.229543: tracing_mark_write: B|2007|flush commands
+           <...>-13916 (-----) [002] .... 14594.229562: sched_process_exit: comm=HeapTaskDaemon pid=13916 prio=124
+           <...>-625   (-----) [003] ...1 14594.229567: tracing_mark_write: B|625|doTransaction
+           <...>-625   (-----) [003] ...1 14594.229588: tracing_mark_write: B|625|doTransaction
+           <...>-625   (-----) [003] ...1 14594.229628: tracing_mark_write: B|625|doTransaction
+           <...>-625   (-----) [003] ...1 14594.229652: tracing_mark_write: B|625|doTransaction
+           <...>-13916 (-----) [002] d..2 14594.229676: sched_switch: prev_comm=HeapTaskDaemon prev_pid=13916 prev_prio=124 prev_state=x ==> next_comm=swapper/2 next_pid=0 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.229676: tracing_mark_write: B|625|doTransaction
+           <...>-2007  (-----) [006] d..2 14594.229688: sched_switch: prev_comm=s.nexuslauncher prev_pid=2007 prev_prio=110 prev_state=S ==> next_comm=swapper/6 next_pid=0 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.229703: tracing_mark_write: B|625|doTransaction
+           <...>-625   (-----) [003] ...1 14594.229725: tracing_mark_write: B|625|doTransaction
+           <...>-625   (-----) [003] ...1 14594.229750: tracing_mark_write: B|625|doTransaction
+           <...>-625   (-----) [003] ...1 14594.229772: tracing_mark_write: B|625|doTransaction
+           <...>-625   (-----) [003] ...1 14594.229792: tracing_mark_write: B|625|doTransaction
+           <...>-791   (-----) [000] d..2 14594.229811: sched_switch: prev_comm=main prev_pid=791 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.229824: tracing_mark_write: B|625|doTransaction
+           <...>-2738  (-----) [007] ...1 14594.229827: tracing_mark_write: B|2007|eglSwapBuffersWithDamageKHR
+           <...>-13917 (-----) [001] d..2 14594.229836: sched_switch: prev_comm=ReferenceQueueD prev_pid=13917 prev_prio=124 prev_state=D ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-2738  (-----) [007] ...1 14594.229837: tracing_mark_write: B|2007|setSurfaceDamage
+           <...>-625   (-----) [003] ...1 14594.229850: tracing_mark_write: B|625|doTransaction
+           <...>-13918 (-----) [002] d..2 14594.229856: sched_blocked_reason: pid=13917 iowait=0 caller=SyS_madvise+0xd34/0xd3c
+           <...>-5281  (-----) [001] d..2 14594.229932: sched_switch: prev_comm=writer prev_pid=5281 prev_prio=96 prev_state=D ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-89    (-----) [006] d..2 14594.229951: sched_switch: prev_comm=lpass_smem_glin prev_pid=89 prev_prio=98 prev_state=S ==> next_comm=swapper/6 next_pid=0 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.229982: tracing_mark_write: B|625|handleMessageInvalidate
+           <...>-625   (-----) [003] ...1 14594.229984: tracing_mark_write: B|625|handlePageFlip
+           <...>-625   (-----) [003] ...1 14594.230013: tracing_mark_write: B|625|latchBuffer
+           <...>-13917 (-----) [000] .... 14594.230015: sched_process_exit: comm=ReferenceQueueD pid=13917 prio=124
+           <...>-625   (-----) [003] ...1 14594.230020: tracing_mark_write: B|625|query
+           <...>-625   (-----) [003] ...1 14594.230028: tracing_mark_write: B|625|updateTexImage
+           <...>-625   (-----) [003] ...1 14594.230035: tracing_mark_write: B|625|acquireBuffer
+           <...>-625   (-----) [003] ...1 14594.230044: tracing_mark_write: B|625|com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#1: 2
+           <...>-2738  (-----) [007] d..2 14594.230057: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=D ==> next_comm=smem_native_lpa next_pid=88 next_prio=120
+           <...>-14607 (-----) [000] d..2 14594.259609: sched_blocked_reason: pid=14624 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-2738  (-----) [005] d..2 14594.259620: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=120 prev_state=S ==> next_comm=Binder:625_4 next_pid=1773 next_prio=120
+           <...>-1773  (-----) [005] ...1 14594.259649: tracing_mark_write: B|625|query
+           <...>-2738  (-----) [005] ...1 14594.259714: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [005] d..2 14594.259743: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=120 prev_state=S ==> next_comm=Binder:625_4 next_pid=1773 next_prio=120
+           <...>-1773  (-----) [005] ...1 14594.259757: tracing_mark_write: B|625|query
+           <...>-2738  (-----) [005] ...1 14594.259810: tracing_mark_write: B|2007|syncFrameState
+           <...>-2738  (-----) [005] ...1 14594.259856: tracing_mark_write: B|2007|prepareTree
+  Binder:14607_1-14624 (14607) [002] ...1 14594.259863: tracing_mark_write: B|14607|AttachCurrentThread
+  Binder:14607_1-14624 (14607) [002] ...1 14594.259869: tracing_mark_write: B|14607|Thread::Attach
+  Binder:14607_1-14624 (14607) [002] ...1 14594.259873: tracing_mark_write: B|14607|Thread birth
+  Binder:14607_1-14624 (14607) [002] ...1 14594.259916: tracing_mark_write: B|14607|Thread::Init
+  Binder:14607_1-14624 (14607) [002] ...1 14594.259920: tracing_mark_write: B|14607|InitStackHwm
+           <...>-14607 (-----) [000] d..2 14594.259932: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_1-14624 (14607) [002] d..2 14594.259941: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-3198  (-----) [001] ...1 14594.259942: tracing_mark_write: B|2007|Update SurfaceView position
+  Binder:14607_1-14624 (14607) [002] ...1 14594.259963: tracing_mark_write: B|14607|InitTlsEntryPoints
+  Binder:14607_1-14624 (14607) [002] ...1 14594.259974: tracing_mark_write: B|14607|InitInterpreterTls
+           <...>-14607 (-----) [000] d..2 14594.260005: sched_blocked_reason: pid=14624 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-3198  (-----) [001] d..2 14594.260007: sched_switch: prev_comm=hwuiTask1 prev_pid=3198 prev_prio=118 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-14607 (-----) [000] d..2 14594.260024: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_1-14624 (14607) [002] d..2 14594.260038: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-14607 (-----) [000] d..2 14594.260064: sched_blocked_reason: pid=14624 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+  Binder:14607_1-14624 (14607) [002] ...1 14594.260101: tracing_mark_write: B|14607|ThreadList::Register
+           <...>-2738  (-----) [005] ...1 14594.260128: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [005] ...1 14594.260140: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [005] ...1 14594.260148: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [005] ...1 14594.260155: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [005] ...1 14594.260161: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [005] ...1 14594.260167: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [005] ...1 14594.260173: tracing_mark_write: B|2007|dequeueBuffer
+           <...>-2007  (-----) [001] d..2 14594.260201: sched_switch: prev_comm=s.nexuslauncher prev_pid=2007 prev_prio=120 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-2738  (-----) [005] d..2 14594.260214: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=120 prev_state=S ==> next_comm=Binder:625_4 next_pid=1773 next_prio=120
+           <...>-1773  (-----) [005] ...1 14594.260236: tracing_mark_write: B|625|dequeueBuffer
+           <...>-1773  (-----) [005] ...1 14594.260249: tracing_mark_write: B|625|com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#1: 2
+           <...>-14607 (-----) [000] d..2 14594.260334: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_1-14624 (14607) [002] d..2 14594.260343: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-14607 (-----) [000] d..2 14594.260376: sched_blocked_reason: pid=14624 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-14607 (-----) [000] d..2 14594.260387: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+           <...>-2738  (-----) [005] ...1 14594.260401: tracing_mark_write: B|2007|HWC release fence 36030 has signaled
+  Binder:14607_1-14624 (14607) [002] d..2 14594.260407: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-2738  (-----) [005] ...1 14594.260419: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [005] ...1 14594.260427: tracing_mark_write: B|2007|eglBeginFrame
+           <...>-2738  (-----) [005] ...1 14594.260445: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [005] ...1 14594.260450: tracing_mark_write: B|2007|query
+  Binder:14607_1-14624 (14607) [002] .... 14594.260472: task_newtask: pid=14625 comm=Binder:14607_1 clone_flags=3d0f00 oom_score_adj=-1000
+           <...>-14607 (-----) [000] d..2 14594.260517: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_2-14625 (14607) [001] d..2 14594.260525: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-14607 (-----) [000] d..2 14594.260555: sched_blocked_reason: pid=14625 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-14607 (-----) [000] ...1 14594.260569: tracing_mark_write: B|14607|ActivityThreadMain
+           <...>-14607 (-----) [000] d..2 14594.260581: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_2-14625 (14607) [001] d..2 14594.260588: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-14607 (-----) [000] d..2 14594.260611: sched_blocked_reason: pid=14625 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-14607 (-----) [000] d..2 14594.260623: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_2-14625 (14607) [001] d..2 14594.260636: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-14607 (-----) [000] d..2 14594.260663: sched_blocked_reason: pid=14625 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-14607 (-----) [000] d..2 14594.260674: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_2-14625 (14607) [001] d..2 14594.260694: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-14607 (-----) [000] d..2 14594.260724: sched_blocked_reason: pid=14625 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-2738  (-----) [005] ...1 14594.260734: tracing_mark_write: B|2007|flush commands
+           <...>-14607 (-----) [000] d..2 14594.260735: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_2-14625 (14607) [001] d..2 14594.260753: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+  Binder:14607_2-14625 (14607) [001] ...1 14594.260925: tracing_mark_write: B|14607|AttachCurrentThread
+  Binder:14607_2-14625 (14607) [001] ...1 14594.260930: tracing_mark_write: B|14607|Thread::Attach
+  Binder:14607_2-14625 (14607) [001] ...1 14594.260933: tracing_mark_write: B|14607|Thread birth
+  Binder:14607_2-14625 (14607) [001] ...1 14594.260973: tracing_mark_write: B|14607|Thread::Init
+  Binder:14607_2-14625 (14607) [001] ...1 14594.260977: tracing_mark_write: B|14607|InitStackHwm
+           <...>-14607 (-----) [000] d..2 14594.260990: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_2-14625 (14607) [001] d..2 14594.260998: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+  Binder:14607_2-14625 (14607) [001] ...1 14594.261023: tracing_mark_write: B|14607|InitTlsEntryPoints
+  Binder:14607_2-14625 (14607) [001] ...1 14594.261034: tracing_mark_write: B|14607|InitInterpreterTls
+           <...>-14607 (-----) [000] d..2 14594.261064: sched_blocked_reason: pid=14625 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-14607 (-----) [000] d..2 14594.261075: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_2-14625 (14607) [001] d..2 14594.261094: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-14607 (-----) [000] d..2 14594.261120: sched_blocked_reason: pid=14625 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-14607 (-----) [000] d..2 14594.261132: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+  Binder:14607_2-14625 (14607) [001] d..2 14594.261146: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+  Binder:14607_2-14625 (14607) [001] ...1 14594.261167: tracing_mark_write: B|14607|ThreadList::Register
+           <...>-14607 (-----) [000] d..2 14594.261209: sched_blocked_reason: pid=14625 iowait=0 caller=__rwsem_down_write_failed_common+0x3e8/0x754
+           <...>-2738  (-----) [005] ...1 14594.261212: tracing_mark_write: B|2007|waitOnFences
+           <...>-14607 (-----) [000] d..2 14594.261220: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=120 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
+           <...>-2738  (-----) [005] ...1 14594.261232: tracing_mark_write: B|2007|eglSwapBuffersWithDamageKHR
+           <...>-2738  (-----) [005] ...1 14594.261244: tracing_mark_write: B|2007|setSurfaceDamage
+  Binder:14607_2-14625 (14607) [001] d..2 14594.261246: sched_blocked_reason: pid=14607 iowait=0 caller=do_page_fault+0x550/0x5fc
+           <...>-14607 (-----) [000] ...1 14594.261326: tracing_mark_write: B|14607|VerifyClass com.android.org.conscrypt.TrustedCertificateStore$PreloadHolder
+           <...>-2738  (-----) [005] .... 14594.261621: fence_init: driver=kgsl-timeline timeline=kgsl-3d0_13-s.nexuslauncher(200 context=27 seqno=78005
+           <...>-625   (-----) [003] ...1 14594.263903: tracing_mark_write: B|625|resetIdleTimer
+           <...>-625   (-----) [003] ...1 14594.263912: tracing_mark_write: B|625|rebuildLayerStacks
+           <...>-625   (-----) [003] ...1 14594.263915: tracing_mark_write: B|625|rebuildLayerStacks VR Dirty
+           <...>-625   (-----) [003] ...1 14594.263919: tracing_mark_write: B|625|computeVisibleRegions
+           <...>-1398  (-----) [006] d..2 14594.263966: sched_switch: prev_comm=android.anim prev_pid=1398 prev_prio=110 prev_state=S ==> next_comm=Binder:625_4 next_pid=1773 next_prio=120
+           <...>-1695  (-----) [001] d..2 14594.264086: sched_switch: prev_comm=InputDispatcher prev_pid=1695 prev_prio=112 prev_state=S ==> next_comm=Binder:1368_14 next_pid=3253 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.264293: tracing_mark_write: B|625|calculateWorkingSet
+           <...>-625   (-----) [003] ...1 14594.264500: tracing_mark_write: B|625|prepare
+           <...>-625   (-----) [003] ...1 14594.264513: tracing_mark_write: B|625|HIDL::IComposerClient::executeCommands_2_2::client
+           <...>-625   (-----) [003] ...2 14594.264584: binder_set_priority: proc=627 thread=627 old=97 => new=98 desired=98
+           <...>-625   (-----) [003] d..2 14594.264617: sched_switch: prev_comm=surfaceflinger prev_pid=625 prev_prio=98 prev_state=S ==> next_comm=logd.writer next_pid=588 next_prio=130
+           <...>-588   (-----) [003] d..2 14594.264851: sched_switch: prev_comm=logd.writer prev_pid=588 prev_prio=130 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120
+     rcu_preempt-7     (    7) [007] d..2 14594.265273: sched_switch: prev_comm=rcu_preempt prev_pid=7 prev_prio=120 prev_state=S ==> next_comm=kworker/u16:3 next_pid=18008 next_prio=120
+           <...>-18008 (-----) [007] d..2 14594.265404: sched_switch: prev_comm=kworker/u16:3 prev_pid=18008 prev_prio=120 prev_state=D ==> next_comm=swapper/7 next_pid=0 next_prio=120
+           <...>-18008 (-----) [007] d..2 14594.265471: sched_switch: prev_comm=kworker/u16:3 prev_pid=18008 prev_prio=120 prev_state=S ==> next_comm=swapper/7 next_pid=0 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.265496: tracing_mark_write: B|625|doComposition
+           <...>-625   (-----) [003] ...1 14594.265507: tracing_mark_write: B|625|doComposeSurfaces
+           <...>-625   (-----) [003] ...1 14594.265552: tracing_mark_write: B|625|acquireBuffer
+           <...>-625   (-----) [003] ...1 14594.265563: tracing_mark_write: B|625|postFramebuffer
+           <...>-625   (-----) [003] ...1 14594.265567: tracing_mark_write: B|625|presentAndGetReleaseFences
+           <...>-625   (-----) [003] d..1 14594.265601: fence_enable_signal: driver=sde_fence:crtc97:91650 timeline=crtc97 context=3 seqno=91650
+           <...>-625   (-----) [003] ...1 14594.265735: tracing_mark_write: B|625|logLayerStats
+           <...>-625   (-----) [003] ...1 14594.265744: tracing_mark_write: B|625|postComposition
+           <...>-625   (-----) [003] ...1 14594.265749: tracing_mark_write: B|625|releaseBuffer
+           <...>-625   (-----) [003] ...1 14594.265753: tracing_mark_write: B|625|com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#1: 1
+           <...>-625   (-----) [003] ...1 14594.265791: tracing_mark_write: B|625|releaseBuffer
+           <...>-440   (-----) [007] d..2 14594.342366: sched_switch: prev_comm=mmc-cmdqd/0 prev_pid=440 prev_prio=98 prev_state=D ==> next_comm=kworker/u17:2 next_pid=1778 next_prio=100
+           <...>-2007  (-----) [006] ...1 14594.342375: tracing_mark_write: B|2007|input
+           <...>-2007  (-----) [006] ...1 14594.342399: tracing_mark_write: B|2007|animation
+           <...>-625   (-----) [003] ...1 14594.342447: tracing_mark_write: B|625|doTransaction
+           <...>-625   (-----) [003] ...1 14594.342489: tracing_mark_write: B|625|doTransaction
+   kworker/u17:2-1778  ( 1778) [007] d..3 14594.342532: sched_blocked_reason: pid=14607 iowait=1 caller=wait_on_page_bit_common+0x2a8/0x5f8
+   kworker/u17:2-1778  ( 1778) [007] d..2 14594.342544: sched_switch: prev_comm=kworker/u17:2 prev_pid=1778 prev_prio=100 prev_state=S ==> next_comm=kworker/u16:2 next_pid=27544 next_prio=120
+           <...>-1773  (-----) [000] ...1 14594.342575: tracing_mark_write: B|625|requestNextVsync
+           <...>-1773  (-----) [000] ...1 14594.342579: tracing_mark_write: B|625|resetIdleTimer
+           <...>-27544 (-----) [007] d..2 14594.342589: sched_switch: prev_comm=kworker/u16:2 prev_pid=27544 prev_prio=120 prev_state=S ==> next_comm=swapper/7 next_pid=0 next_prio=120
+           <...>-656   (-----) [002] d.h3 14594.342604: sched_blocked_reason: pid=1233 iowait=0 caller=geni_i2c_xfer+0x4d8/0x1398
+           <...>-1803  (-----) [001] d..2 14594.342605: sched_switch: prev_comm=ndroid.systemui prev_pid=1803 prev_prio=120 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.342632: tracing_mark_write: B|625|handleMessageInvalidate
+           <...>-625   (-----) [003] ...1 14594.342634: tracing_mark_write: B|625|handlePageFlip
+           <...>-2738  (-----) [007] ...1 14594.342641: tracing_mark_write: B|2007|notifyFramePending
+           <...>-658   (-----) [002] d..2 14594.342653: sched_switch: prev_comm=DispSync prev_pid=658 prev_prio=97 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=120
+           <...>-656   (-----) [002] ...1 14594.342656: tracing_mark_write: B|625|requestNextVsync
+           <...>-2738  (-----) [007] d..2 14594.342658: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=S ==> next_comm=swapper/7 next_pid=0 next_prio=120
+           <...>-656   (-----) [002] ...1 14594.342660: tracing_mark_write: B|625|resetIdleTimer
+           <...>-660   (-----) [005] d..2 14594.342663: sched_switch: prev_comm=app prev_pid=660 prev_prio=97 prev_state=S ==> next_comm=swapper/5 next_pid=0 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.342665: tracing_mark_write: B|625|latchBuffer
+           <...>-625   (-----) [003] ...1 14594.342673: tracing_mark_write: B|625|query
+           <...>-625   (-----) [003] ...1 14594.342682: tracing_mark_write: B|625|updateTexImage
+           <...>-625   (-----) [003] ...1 14594.342693: tracing_mark_write: B|625|acquireBuffer
+           <...>-625   (-----) [003] ...1 14594.342703: tracing_mark_write: B|625|com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#1: 1
+           <...>-660   (-----) [005] d..2 14594.342709: sched_switch: prev_comm=app prev_pid=660 prev_prio=97 prev_state=S ==> next_comm=swapper/5 next_pid=0 next_prio=120
+           <...>-2007  (-----) [006] ...1 14594.342733: tracing_mark_write: B|2007|traversal
+           <...>-2007  (-----) [006] ...1 14594.342776: tracing_mark_write: B|2007|draw
+           <...>-2007  (-----) [006] ...1 14594.342791: tracing_mark_write: B|2007|Record View#draw()
+           <...>-625   (-----) [003] ...1 14594.342849: tracing_mark_write: B|625|updateInputFlinger
+           <...>-2007  (-----) [006] d..2 14594.342903: sched_switch: prev_comm=s.nexuslauncher prev_pid=2007 prev_prio=110 prev_state=S ==> next_comm=kworker/6:2H next_pid=24261 next_prio=100
+           <...>-2738  (-----) [007] ...1 14594.342910: tracing_mark_write: B|2007|DrawFrame
+           <...>-2738  (-----) [007] d..2 14594.342917: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=R+ ==> next_comm=mmc-cmdqd/0 next_pid=440 next_prio=98
+           <...>-24261 (-----) [006] d..2 14594.342918: sched_switch: prev_comm=kworker/6:2H prev_pid=24261 prev_prio=100 prev_state=S ==> next_comm=.android.dialer next_pid=14607 next_prio=110
+           <...>-440   (-----) [007] d..2 14594.342926: sched_switch: prev_comm=mmc-cmdqd/0 prev_pid=440 prev_prio=98 prev_state=D ==> next_comm=RenderThread next_pid=2738 next_prio=110
+           <...>-2738  (-----) [007] ...1 14594.342927: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [007] ...2 14594.342959: binder_set_priority: proc=625 thread=656 old=120 => new=110 desired=110
+           <...>-2738  (-----) [007] d..2 14594.342975: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=R+ ==> next_comm=Binder:625_1 next_pid=656 next_prio=110
+           <...>-656   (-----) [007] ...1 14594.343021: tracing_mark_write: B|625|query
+           <...>-656   (-----) [007] .... 14594.343033: binder_set_priority: proc=625 thread=656 old=110 => new=120 desired=120
+           <...>-2738  (-----) [007] ...1 14594.343070: tracing_mark_write: B|2007|query
+           <...>-1233  (-----) [004] d..2 14594.343074: sched_switch: prev_comm=sound trigger c prev_pid=1233 prev_prio=120 prev_state=R+ ==> next_comm=irq/144-1436400 next_pid=2522 next_prio=49
+           <...>-2738  (-----) [007] ...2 14594.343078: binder_set_priority: proc=625 thread=656 old=120 => new=110 desired=110
+           <...>-625   (-----) [003] ...1 14594.343084: tracing_mark_write: B|625|onMessageReceived
+           <...>-625   (-----) [003] ...1 14594.343087: tracing_mark_write: B|625|handleMessageRefresh
+           <...>-625   (-----) [003] ...1 14594.343090: tracing_mark_write: B|625|preComposition
+           <...>-2738  (-----) [007] d..2 14594.343090: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=R+ ==> next_comm=Binder:625_1 next_pid=656 next_prio=110
+           <...>-625   (-----) [003] ...1 14594.343122: tracing_mark_write: B|625|rebuildLayerStacks
+           <...>-625   (-----) [003] ...1 14594.343124: tracing_mark_write: B|625|rebuildLayerStacks VR Dirty
+           <...>-89    (-----) [007] d..2 14594.343126: sched_switch: prev_comm=lpass_smem_glin prev_pid=89 prev_prio=98 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=110
+           <...>-625   (-----) [003] ...1 14594.343129: tracing_mark_write: B|625|computeVisibleRegions
+           <...>-656   (-----) [007] ...1 14594.343136: tracing_mark_write: B|625|query
+           <...>-14607 (-----) [006] ...2 14594.343141: binder_set_priority: proc=1368 thread=3253 old=120 => new=110 desired=110
+                      <...>-2965  (-----) [001] .... 14596.746610: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=000000002ae8fcff pfn=1522884 ofs=188416
+          <idle>-0     (-----) [002] d..2 14596.746619: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=mmc-cmdqd/0 next_pid=440 next_prio=98
+           <...>-2965  (-----) [001] .... 14596.746629: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=00000000679ee1ec pfn=1299913 ofs=192512
+           <...>-2965  (-----) [001] .... 14596.746664: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=0000000006cd2fb7 pfn=1296251 ofs=196608
+           <...>-2965  (-----) [001] .... 14596.746677: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=00000000af82f3d6 pfn=1419330 ofs=200704
+           <...>-2965  (-----) [001] .... 14596.746693: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=000000002840f054 pfn=1304928 ofs=204800
+           <...>-2965  (-----) [001] .... 14596.746706: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=000000004a59da17 pfn=1288069 ofs=208896
+           <...>-2965  (-----) [001] .... 14596.746717: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=0000000023a80dca pfn=1419686 ofs=212992
+           <...>-2965  (-----) [001] .... 14596.746730: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=000000001cf89eab pfn=1315372 ofs=217088
+           <...>-2965  (-----) [001] .... 14596.746743: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=000000005b4c6cb6 pfn=1380698 ofs=221184
+           <...>-2965  (-----) [001] .... 14596.746760: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=00000000f8304ae7 pfn=1206753 ofs=225280
+           <...>-2965  (-----) [001] .... 14596.746773: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=00000000cb912305 pfn=1325465 ofs=229376
+           <...>-2965  (-----) [001] .... 14596.746785: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=00000000f16f3774 pfn=1408056 ofs=233472
+           <...>-2965  (-----) [001] .... 14596.746801: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=0000000056d4c926 pfn=1418352 ofs=237568
+           <...>-2965  (-----) [001] .... 14596.746815: mm_filemap_add_to_page_cache: dev 253:6 ino a359 page=00000000f3eeb42c pfn=1320957 ofs=241664
+           <...>-440   (-----) [002] d..2 14596.746916: sched_switch: prev_comm=mmc-cmdqd/0 prev_pid=440 prev_prio=98 prev_state=D ==> next_comm=swapper/2 next_pid=0 next_prio=120
+
+           <...>-656   (-----) [007] .... 14594.343145: binder_set_priority: proc=625 thread=656 old=110 => new=120 desired=120
+           <...>-14607 (-----) [006] d..2 14594.343164: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=110 prev_state=S ==> next_comm=swapper/6 next_pid=0 next_prio=120
+           <...>-5281  (-----) [002] d..2 14594.343177: sched_switch: prev_comm=writer prev_pid=5281 prev_prio=96 prev_state=S ==> next_comm=RenderThread next_pid=2738 next_prio=110
+ irq/144-1436400-2522  ( 2522) [004] d..2 14594.343223: sched_switch: prev_comm=irq/144-1436400 prev_pid=2522 prev_prio=49 prev_state=D ==> next_comm=sound trigger c next_pid=1233 next_prio=120
+           <...>-88    (-----) [006] d..2 14594.343240: sched_switch: prev_comm=smem_native_lpa prev_pid=88 prev_prio=98 prev_state=S ==> next_comm=swapper/6 next_pid=0 next_prio=120
+           <...>-1238  (-----) [001] d..2 14594.343243: sched_switch: prev_comm=FastMixer prev_pid=1238 prev_prio=96 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-2738  (-----) [002] ...1 14594.343244: tracing_mark_write: B|2007|syncFrameState
+           <...>-2738  (-----) [002] ...1 14594.343293: tracing_mark_write: B|2007|prepareTree
+           <...>-1695  (-----) [001] d..2 14594.343318: sched_switch: prev_comm=InputDispatcher prev_pid=1695 prev_prio=112 prev_state=R+ ==> next_comm=FastMixer next_pid=1238 next_prio=96
+           <...>-5281  (-----) [005] d..2 14594.343322: sched_switch: prev_comm=writer prev_pid=5281 prev_prio=96 prev_state=S ==> next_comm=Binder:1368_14 next_pid=3253 next_prio=110
+           <...>-1238  (-----) [001] d..2 14594.343442: sched_switch: prev_comm=FastMixer prev_pid=1238 prev_prio=96 prev_state=S ==> next_comm=InputDispatcher next_pid=1695 next_prio=112
+           <...>-1695  (-----) [001] d..2 14594.343467: sched_switch: prev_comm=InputDispatcher prev_pid=1695 prev_prio=112 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
+           <...>-5281  (-----) [000] d..2 14594.343484: sched_switch: prev_comm=writer prev_pid=5281 prev_prio=96 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
+           <...>-625   (-----) [003] ...1 14594.343519: tracing_mark_write: B|625|calculateWorkingSet
+           <...>-2738  (-----) [002] ...1 14594.343568: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [002] ...1 14594.343577: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [002] ...1 14594.343586: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [002] ...1 14594.343591: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [002] ...1 14594.343597: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [002] ...1 14594.343602: tracing_mark_write: B|2007|query
+           <...>-2738  (-----) [002] ...1 14594.343609: tracing_mark_write: B|2007|dequeueBuffer
+           <...>-2007  (-----) [006] d..2 14594.343612: sched_switch: prev_comm=s.nexuslauncher prev_pid=2007 prev_prio=110 prev_state=S ==> next_comm=swapper/6 next_pid=0 next_prio=120
+           <...>-2738  (-----) [002] ...2 14594.343633: binder_set_priority: proc=625 thread=656 old=120 => new=110 desired=110
+           <...>-2738  (-----) [002] d..2 14594.343683: sched_switch: prev_comm=RenderThread prev_pid=2738 prev_prio=110 prev_state=R+ ==> next_comm=Binder:625_1 next_pid=656 next_prio=110
+           <...>-625   (-----) [003] ...1 14594.343704: tracing_mark_write: B|625|prepare
+           <...>-656   (-----) [002] ...1 14594.343707: tracing_mark_write: B|625|dequeueBuffer
+           <...>-625   (-----) [004] ...1 14594.812869: tracing_mark_write: B|625|com.google.android.dialer/com.google.android.dialer.extensions.GoogleDialtactsActivity#0: 2
+           <...>-2048  (-----) [000] d..2 14594.812895: sched_switch: prev_comm=RenderThread prev_pid=2048 prev_prio=120 prev_state=R+ ==> next_comm=Binder:625_3 next_pid=1431 next_prio=120
+           <...>-1431  (-----) [000] ...1 14594.812911: tracing_mark_write: B|625|query
+           <...>-625   (-----) [004] ...1 14594.812914: tracing_mark_write: B|625|latchBuffer
+           <...>-625   (-----) [004] ...1 14594.812919: tracing_mark_write: B|625|query
+           <...>-625   (-----) [004] ...1 14594.812925: tracing_mark_write: B|625|updateTexImage
+           <...>-625   (-----) [004] ...1 14594.812928: tracing_mark_write: B|625|acquireBuffer
+           <...>-625   (-----) [004] ...1 14594.812934: tracing_mark_write: B|625|StatusBar#0: 1
+           <...>-2048  (-----) [000] ...1 14594.812962: tracing_mark_write: B|1803|syncFrameState
+           <...>-656   (-----) [002] ...1 14594.813044: tracing_mark_write: B|625|setTransactionState
+           <...>-14607 (-----) [007] ...2 14594.813083: binder_set_priority: proc=10691 thread=18733 old=120 => new=110 desired=110
+           <...>-14607 (-----) [007] d..2 14594.813114: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=110 prev_state=S ==> next_comm=kworker/7:1 next_pid=7092 next_prio=120
+           <...>-14655 (-----) [006] d..2 14594.813128: sched_switch: prev_comm=DialerExecutors prev_pid=14655 prev_prio=130 prev_state=R ==> next_comm=lpass_smem_glin next_pid=89 next_prio=98
+           <...>-89    (-----) [006] d..2 14594.813163: sched_switch: prev_comm=lpass_smem_glin prev_pid=89 prev_prio=98 prev_state=S ==> next_comm=DialerExecutors next_pid=14655 next_prio=130
+           <...>-656   (-----) [002] ...1 14594.813218: tracing_mark_write: B|625|requestNextVsync
+           <...>-656   (-----) [002] ...1 14594.813222: tracing_mark_write: B|625|resetIdleTimer
+     kworker/7:1-7092  ( 7092) [007] d..2 14594.813239: sched_switch: prev_comm=kworker/7:1 prev_pid=7092 prev_prio=120 prev_state=R+ ==> next_comm=smem_native_lpa next_pid=88 next_prio=98
+           <...>-5281  (-----) [001] d..2 14594.813245: sched_switch: prev_comm=writer prev_pid=5281 prev_prio=96 prev_state=S ==> next_comm=Binder:10691_B next_pid=18733 next_prio=110
+           <...>-88    (-----) [007] d..2 14594.813248: sched_switch: prev_comm=smem_native_lpa prev_pid=88 prev_prio=98 prev_state=R ==> next_comm=kgsl_worker_thr next_pid=259 next_prio=97
+           <...>-2048  (-----) [000] d..2 14594.813249: sched_switch: prev_comm=RenderThread prev_pid=2048 prev_prio=120 prev_state=R+ ==> next_comm=FastMixer next_pid=1238 next_prio=96
+           <...>-14655 (-----) [006] d..2 14594.813263: sched_switch: prev_comm=DialerExecutors prev_pid=14655 prev_prio=130 prev_state=R+ ==> next_comm=smem_native_lpa next_pid=88 next_prio=98
+           <...>-661   (-----) [002] d..2 14594.813265: sched_switch: prev_comm=sf prev_pid=661 prev_prio=97 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=116
+           <...>-259   (-----) [007] d..2 14594.813265: sched_switch: prev_comm=kgsl_worker_thr prev_pid=259 prev_prio=97 prev_state=S ==> next_comm=kworker/7:1 next_pid=7092 next_prio=120
+     kworker/7:1-7092  ( 7092) [007] d..2 14594.813271: sched_switch: prev_comm=kworker/7:1 prev_pid=7092 prev_prio=120 prev_state=S ==> next_comm=system next_pid=108 next_prio=120
+           <...>-108   (-----) [007] .... 14594.813275: ion_heap_shrink: heap_name=system, len=9469952, total_allocated=189620224
+           <...>-88    (-----) [006] d..2 14594.813294: sched_switch: prev_comm=smem_native_lpa prev_pid=88 prev_prio=98 prev_state=S ==> next_comm=DialerExecutors next_pid=14655 next_prio=130
+           <...>-625   (-----) [004] ...1 14594.813310: tracing_mark_write: B|625|updateInputFlinger
+           <...>-1238  (-----) [000] d..2 14594.813312: sched_switch: prev_comm=FastMixer prev_pid=1238 prev_prio=96 prev_state=S ==> next_comm=RenderThread next_pid=2048 next_prio=120
+           <...>-661   (-----) [002] d..2 14594.813317: sched_switch: prev_comm=sf prev_pid=661 prev_prio=97 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=116
+           <...>-14640 (-----) [005] d..2 14594.813319: sched_switch: prev_comm=DialerExecutors prev_pid=14640 prev_prio=130 prev_state=R ==> next_comm=DispSync next_pid=658 next_prio=97
+           <...>-656   (-----) [002] ...1 14594.813336: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-658   (-----) [005] d..2 14594.813345: sched_switch: prev_comm=DispSync prev_pid=658 prev_prio=97 prev_state=S ==> next_comm=DialerExecutors next_pid=14640 next_prio=130
+           <...>-656   (-----) [002] ...1 14594.813345: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] ...1 14594.813353: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-2048  (-----) [000] d..2 14594.813358: sched_switch: prev_comm=RenderThread prev_pid=2048 prev_prio=120 prev_state=R+ ==> next_comm=FastMixer next_pid=1238 next_prio=96
+           <...>-656   (-----) [002] ...1 14594.813364: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-5281  (-----) [001] d..2 14594.813369: sched_switch: prev_comm=writer prev_pid=5281 prev_prio=96 prev_state=S ==> next_comm=Binder:10691_B next_pid=18733 next_prio=110
+           <...>-656   (-----) [002] ...1 14594.813372: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] ...1 14594.813380: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] ...1 14594.813391: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] ...1 14594.813398: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] ...1 14594.813408: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] ...1 14594.813416: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] ...1 14594.813424: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] ...1 14594.813432: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] .n.1 14594.813443: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-1238  (-----) [000] d..2 14594.813464: sched_switch: prev_comm=FastMixer prev_pid=1238 prev_prio=96 prev_state=S ==> next_comm=RenderThread next_pid=2048 next_prio=120
+           <...>-5281  (-----) [002] d..2 14594.813525: sched_switch: prev_comm=writer prev_pid=5281 prev_prio=96 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=116
+           <...>-656   (-----) [002] ...1 14594.813544: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-656   (-----) [002] ...1 14594.813557: tracing_mark_write: B|625|~GraphicBuffer
+           <...>-2048  (-----) [000] d..2 14594.813594: sched_switch: prev_comm=RenderThread prev_pid=2048 prev_prio=120 prev_state=R+ ==> next_comm=Binder:1368_15 next_pid=3359 next_prio=120
+           <...>-18733 (-----) [001] ...2 14594.813635: binder_set_priority: proc=1368 thread=3514 old=120 => new=110 desired=110
+           <...>-656   (-----) [002] .... 14594.813637: binder_set_priority: proc=625 thread=656 old=116 => new=120 desired=120
+           <...>-108   (-----) [007] d..2 14594.813646: sched_switch: prev_comm=system prev_pid=108 prev_prio=120 prev_state=R+ ==> next_comm=android.anim next_pid=1398 next_prio=116
+           <...>-625   (-----) [004] ...1 14594.813646: tracing_mark_write: B|625|onMessageReceived
+           <...>-625   (-----) [004] ...1 14594.813649: tracing_mark_write: B|625|handleMessageRefresh
+           <...>-625   (-----) [004] ...1 14594.813651: tracing_mark_write: B|625|preComposition
+           <...>-625   (-----) [004] ...1 14594.813693: tracing_mark_write: B|625|rebuildLayerStacks
+           <...>-625   (-----) [004] ...1 14594.813696: tracing_mark_write: B|625|rebuildLayerStacks VR Dirty
+           <...>-625   (-----) [004] ...1 14594.813701: tracing_mark_write: B|625|computeVisibleRegions
+           <...>-1398  (-----) [007] d..2 14594.813718: sched_switch: prev_comm=android.anim prev_pid=1398 prev_prio=116 prev_state=S ==> next_comm=system next_pid=108 next_prio=120
+           <...>-108   (-----) [007] d..2 14594.813739: sched_switch: prev_comm=system prev_pid=108 prev_prio=120 prev_state=R+ ==> next_comm=android.anim next_pid=1398 next_prio=116
+           <...>-1695  (-----) [002] d..2 14594.813970: sched_switch: prev_comm=InputDispatcher prev_pid=1695 prev_prio=112 prev_state=S ==> next_comm=system next_pid=108 next_prio=120
+           <...>-1398  (-----) [007] ...1 14594.814029: tracing_mark_write: B|1368|wmLayout
+           <...>-1398  (-----) [007] ...1 14594.814033: tracing_mark_write: B|1368|performSurfacePlacement
+           <...>-1398  (-----) [007] ...1 14594.814040: tracing_mark_write: B|1368|applySurfaceChanges
+           <...>-1398  (-----) [007] ...1 14594.814043: tracing_mark_write: B|1368|openSurfaceTransaction
+           <...>-1398  (-----) [007] ...1 14594.814063: tracing_mark_write: B|1368|performLayout
+           <...>-625   (-----) [004] ...1 14594.814119: tracing_mark_write: B|625|calculateWorkingSet
+           <...>-1398  (-----) [007] ...1 14594.814241: tracing_mark_write: B|1368|layoutInputConsumer
+           <...>-2048  (-----) [000] ...1 14594.814260: tracing_mark_write: B|1803|prepareTree
+           <...>-1398  (-----) [007] ...1 14594.814263: tracing_mark_write: B|1368|applyPostLayoutPolicy
+           <...>-2048  (-----) [000] d..2 14594.814408: sched_switch: prev_comm=RenderThread prev_pid=2048 prev_prio=120 prev_state=R ==> next_comm=Binder:1368_15 next_pid=3359 next_prio=120
+           <...>-625   (-----) [004] ...1 14594.814411: tracing_mark_write: B|625|prepare
+           <...>-625   (-----) [004] ...1 14594.814428: tracing_mark_write: B|625|HIDL::IComposerClient::executeCommands_2_2::client
+           <...>-2048  (-----) [000] d..2 14594.814533: sched_switch: prev_comm=RenderThread prev_pid=2048 prev_prio=120 prev_state=R+ ==> next_comm=ndroid.systemui next_pid=1803 next_prio=120
+           <...>-1803  (-----) [000] d..2 14594.814558: sched_switch: prev_comm=ndroid.systemui prev_pid=1803 prev_prio=120 prev_state=S ==> next_comm=RenderThread next_pid=2048 next_prio=120
+           <...>-2048  (-----) [000] d..2 14594.814572: sched_switch: prev_comm=RenderThread prev_pid=2048 prev_prio=120 prev_state=R+ ==> next_comm=ndroid.systemui next_pid=1803 next_prio=120
+           <...>-625   (-----) [004] ...2 14594.814589: binder_set_priority: proc=627 thread=627 old=97 => new=98 desired=98
+           <...>-108   (-----) [002] d..2 14594.814650: sched_switch: prev_comm=system prev_pid=108 prev_prio=120 prev_state=R+ ==> next_comm=composer@2.2-se next_pid=627 next_prio=98
+           <...>-625   (-----) [004] d..2 14594.814664: sched_switch: prev_comm=surfaceflinger prev_pid=625 prev_prio=98 prev_state=S ==> next_comm=ashmemd next_pid=854 next_prio=129
+           <...>-1398  (-----) [007] ...1 14594.814723: tracing_mark_write: B|1368|applyWindowSurfaceChanges
+           <...>-854   (-----) [004] .... 14594.814746: binder_set_priority: proc=854 thread=854 old=129 => new=120 desired=120
+           <...>-854   (-----) [004] d..2 14594.814757: sched_switch: prev_comm=ashmemd prev_pid=854 prev_prio=120 prev_state=R+ ==> next_comm=highpool[0] next_pid=3493 next_prio=129
+           <...>-1803  (-----) [000] d..2 14594.814763: sched_switch: prev_comm=ndroid.systemui prev_pid=1803 prev_prio=120 prev_state=S ==> next_comm=RenderThread next_pid=2048 next_prio=120
+           <...>-18733 (-----) [001] d..1 14594.814819: mm_filemap_delete_from_page_cache: dev 0:1 ino 3ce5e7 page=0000000083f10c7a pfn=1298474 ofs=0
+           <...>-2048  (-----) [000] ...1 14594.814842: tracing_mark_write: B|1803|dequeueBuffer
+           <...>-1398  (-----) [007] ...1 14594.814850: tracing_mark_write: F|1368|launching: com.google.android.dialer|0
+           <...>-1398  (-----) [007] ...1 14594.814855: tracing_mark_write: B|1368|MetricsLogger:launchObserverNotifyActivityLaunchFinished
+           <...>-1398  (-----) [007] ...1 14594.814857: tracing_mark_write: B|1368|MetricsLogger:convertActivityRecordToProto
+           <...>-2048  (-----) [000] d..2 14594.814905: sched_switch: prev_comm=RenderThread prev_pid=2048 prev_prio=120 prev_state=R+ ==> next_comm=Binder:625_1 next_pid=656 next_prio=120
+           <...>-1410  (-----) [006] .... 14592.997816: mm_filemap_add_to_page_cache: dev 253:6 ino b785 page=00000000615a8f24 pfn=1134764 ofs=0
+           <...>-1410  (-----) [006] .... 14592.997831: mm_filemap_add_to_page_cache: dev 253:6 ino b785 page=000000008768a58f pfn=1134751 ofs=4096
+
+           <...>-18733 (-----) [001] .... 14594.814914: binder_set_priority: proc=10691 thread=18733 old=110 => new=120 desired=120
+           <...>-14655 (-----) [006] d..2 14594.814932: sched_switch: prev_comm=DialerExecutors prev_pid=14655 prev_prio=130 prev_state=R ==> next_comm=.android.dialer next_pid=14607 next_prio=110
+           <...>-656   (-----) [000] ...1 14594.814948: tracing_mark_write: B|625|dequeueBuffer
+           <...>-3514  (-----) [001] .... 14594.814954: binder_set_priority: proc=1368 thread=3514 old=110 => new=120 desired=120
+           <...>-656   (-----) [000] ...1 14594.814963: tracing_mark_write: B|625|NavigationBar0#0: 2
+           <...>-14607 (-----) [006] ...2 14594.815022: binder_set_priority: proc=1368 thread=3514 old=120 => new=110 desired=110
+           <...>-1398  (-----) [007] ...1 14594.815039: tracing_mark_write: B|1368|prepareSurfaces
+           <...>-14607 (-----) [006] d..2 14594.815041: sched_switch: prev_comm=.android.dialer prev_pid=14607 prev_prio=110 prev_state=S ==> next_comm=DialerExecutors next_pid=14655 next_prio=130
+           <...>-3493  (-----) [004] d..2 14594.815057: sched_switch: prev_comm=highpool[0] prev_pid=3493 prev_prio=129 prev_state=R ==> next_comm=Binder:1368_18 next_pid=3514 next_prio=110
+           <...>-2048  (-----) [000] ...1 14594.815088: tracing_mark_write: B|1803|HWC release fence 45750 has signaled
+           <...>-2048  (-----) [000] ...1 14594.815119: tracing_mark_write: B|1803|eglBeginFrame
+           <...>-14655 (-----) [006] d..2 14594.815190: sched_switch: prev_comm=DialerExecutors prev_pid=14655 prev_prio=130 prev_state=R ==> next_comm=crtc_commit:97 next_pid=301 next_prio=83
+           <...>-3514  (-----) [004] .... 14594.815193: binder_set_priority: proc=1368 thread=3514 old=110 => new=120 desired=120
+           <...>-1398  (-----) [007] ...1 14594.815322: tracing_mark_write: B|1368|closeSurfaceTransaction
+           <...>-3493  (-----) [004] .... 14594.815353: mm_filemap_add_to_page_cache: dev 253:6 ino 113b page=0000000069e2b98a pfn=628464 ofs=2723840
+           <...>-1398  (-----) [007] ...2 14594.815393: binder_set_priority: proc=625 thread=656 old=120 => new=116 desired=116
+       rcu_sched-8     (    8) [007] d..2 14594.815449: sched_switch: prev_comm=rcu_sched prev_pid=8 prev_prio=120 prev_state=S ==> next_comm=Binder:625_1 next_pid=656 next_prio=116
diff --git a/startop/scripts/trace_analyzer/trace_analyzer_test.py b/startop/scripts/trace_analyzer/trace_analyzer_test.py
new file mode 100644
index 0000000..579529c
--- /dev/null
+++ b/startop/scripts/trace_analyzer/trace_analyzer_test.py
@@ -0,0 +1,66 @@
+#!/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 trace_analyzer module.
+
+Install:
+  $> sudo apt-get install python3-pytest   ##  OR
+  $> pip install -U pytest
+See also https://docs.pytest.org/en/latest/getting-started.html
+
+Usage:
+  $> pytest trace_analyzer_test.py
+
+See also https://docs.pytest.org/en/latest/usage.html
+"""
+
+# global imports
+import os
+import sys
+
+DIR = os.path.abspath(os.path.dirname(__file__))
+
+sys.path.append(os.path.dirname(DIR))
+import lib.cmd_utils as cmd_utils
+
+def test_trace_analyzer(tmpdir):
+  # Setup
+  bin = os.path.join(DIR, 'trace_analyzer')
+  systrace = os.path.join(DIR, 'test_fixtures/common_systrace')
+  db_file = tmpdir.mkdir('trace_analyzer').join('test.db')
+
+  # Act
+  passed, output = cmd_utils.execute_arbitrary_command([bin, systrace,
+                                                        str(db_file)],
+                                                       timeout=300,
+                                                       shell=False,
+                                                       simulate=False)
+
+  # Assert
+  assert passed
+  assert output == """\
+'blocked_iowait_duration_ms',\
+'process_name',\
+'launching_duration_ms',\
+'launching_started_timestamp_ms',\
+'launching_finished_timestamp_ms'
+81.697999999960302375,\
+'com.google.android.dialer',\
+594.99400000095192808,\
+14594219.85600000061,\
+14594814.85000000149"""
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 91bea5f..4016c5c 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3029,6 +3029,23 @@
             "is_opportunistic_subscription_bool";
 
     /**
+     * Configs used by the IMS stack.
+     */
+    public static final class Ims {
+        /** Prefix of all Ims.KEY_* constants. */
+        public static final String KEY_PREFIX = "ims.";
+
+        //TODO: Add configs related to IMS.
+
+        private Ims() {}
+
+        private static PersistableBundle getDefaults() {
+            PersistableBundle defaults = new PersistableBundle();
+            return defaults;
+        }
+    }
+
+    /**
      * A list of 4 GSM RSSI thresholds above which a signal level is considered POOR,
      * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
      *
@@ -3463,6 +3480,7 @@
                         -89,  /* SIGNAL_STRENGTH_GREAT */
                 });
         sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true);
+        sDefaults.putAll(Ims.getDefaults());
     }
 
     /**
@@ -3659,4 +3677,75 @@
         return ICarrierConfigLoader.Stub
                 .asInterface(ServiceManager.getService(Context.CARRIER_CONFIG_SERVICE));
     }
+
+    /**
+     * Gets the configuration values for a component using its prefix.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param prefix prefix of the component.
+     * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
+     *
+     * @see #getConfigForSubId
+     */
+    @Nullable
+    public PersistableBundle getConfigByComponentForSubId(String prefix, int subId) {
+        PersistableBundle configs = getConfigForSubId(subId);
+
+        if (configs == null) {
+            return null;
+        }
+
+        PersistableBundle ret = new PersistableBundle();
+        for (String configKey : configs.keySet()) {
+            if (configKey.startsWith(prefix)) {
+                addConfig(configKey, configs.get(configKey), ret);
+            }
+        }
+
+        return ret;
+    }
+
+    private void addConfig(String key, Object value, PersistableBundle configs) {
+        if (value instanceof String) {
+            configs.putString(key, (String) value);
+        }
+
+        if (value instanceof String[]) {
+            configs.putStringArray(key, (String[]) value);
+        }
+
+        if (value instanceof Integer) {
+            configs.putInt(key, (Integer) value);
+        }
+
+        if (value instanceof Long) {
+            configs.putLong(key, (Long) value);
+        }
+
+        if (value instanceof Double) {
+            configs.putDouble(key, (Double) value);
+        }
+
+        if (value instanceof Boolean) {
+            configs.putBoolean(key, (Boolean) value);
+        }
+
+        if (value instanceof int[]) {
+            configs.putIntArray(key, (int[]) value);
+        }
+
+        if (value instanceof double[]) {
+            configs.putDoubleArray(key, (double[]) value);
+        }
+
+        if (value instanceof boolean[]) {
+            configs.putBooleanArray(key, (boolean[]) value);
+        }
+
+        if (value instanceof long[]) {
+            configs.putLongArray(key, (long[]) value);
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 484fd3b..2822fcc 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2116,29 +2116,36 @@
     }
 
     /**
+     * TODO(b/137102918) Make this static, tests use this as an instance method currently.
+     *
      * @return the list of subId's that are active,
      *         is never null but the length maybe 0.
      * @hide
      */
     @UnsupportedAppUsage
     public @NonNull int[] getActiveSubscriptionIdList() {
-        int[] subId = null;
+        return getActiveSubscriptionIdList(/* visibleOnly */ true);
+    }
 
+    /**
+     * TODO(b/137102918) Make this static, tests use this as an instance method currently.
+     *
+     * @return a non-null list of subId's that are active.
+     *
+     * @hide
+     */
+    public @NonNull int[] getActiveSubscriptionIdList(boolean visibleOnly) {
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                subId = iSub.getActiveSubIdList(/*visibleOnly*/true);
+                int[] subId = iSub.getActiveSubIdList(visibleOnly);
+                if (subId != null) return subId;
             }
         } catch (RemoteException ex) {
             // ignore it
         }
 
-        if (subId == null) {
-            subId = new int[0];
-        }
-
-        return subId;
-
+        return new int[0];
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ed70a81e0..fd47561 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3983,9 +3983,14 @@
      * The returned set of subscriber IDs will include the subscriber ID corresponding to this
      * TelephonyManager's subId.
      *
+     * This is deprecated and {@link #getMergedSubscriberIdsFromGroup()} should be used for data
+     * usage merging purpose.
+     * TODO: remove this API.
+     *
      * @hide
      */
     @UnsupportedAppUsage
+    @Deprecated
     public @Nullable String[] getMergedSubscriberIds() {
         try {
             ITelephony telephony = getITelephony();
@@ -3998,6 +4003,28 @@
     }
 
     /**
+     * Return the set of subscriber IDs that should be considered "merged together" for data usage
+     * purposes. Unlike {@link #getMergedSubscriberIds()} this API merge subscriberIds based on
+     * subscription grouping: subscriberId of those in the same group will all be returned.
+     *
+     * <p>Requires the calling app to have READ_PRIVILEGED_PHONE_STATE permission.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @Nullable String[] getMergedSubscriberIdsFromGroup() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getMergedSubscriberIdsFromGroup(getSubId(), getOpPackageName());
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
+    /**
      * Returns the MSISDN string.
      * for a GSM phone. Return null if it is unavailable.
      *
@@ -4901,7 +4928,8 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return DATA_ACTIVITY_NONE;
-            return telephony.getDataActivity();
+            return telephony.getDataActivityForSubId(
+                    getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return DATA_ACTIVITY_NONE;
@@ -4949,7 +4977,8 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return DATA_DISCONNECTED;
-            return telephony.getDataState();
+            return telephony.getDataStateForSubId(
+                    getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return DATA_DISCONNECTED;
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index 8c686f7..8e1324b 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.pm.PackageManager;
+import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 
 import java.lang.annotation.Retention;
@@ -55,12 +56,23 @@
      */
     public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2;
 
+    /**
+     * The subscription ID associated with this operation is invalid or not active.
+     * <p>
+     * This is a configuration error and there should be no retry. The subscription used for this
+     * operation is either invalid or has become inactive. The active subscriptions can be queried
+     * with {@link SubscriptionManager#getActiveSubscriptionInfoList()}.
+     * @hide
+     */
+    public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3;
+
     /**@hide*/
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "CODE_ERROR_", value = {
             CODE_ERROR_UNSPECIFIED,
             CODE_ERROR_SERVICE_UNAVAILABLE,
-            CODE_ERROR_UNSUPPORTED_OPERATION
+            CODE_ERROR_UNSUPPORTED_OPERATION,
+            CODE_ERROR_INVALID_SUBSCRIPTION
     })
     public @interface ImsErrorCode {}
 
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index be58723..a1a7fcc 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -31,6 +31,7 @@
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.SubscriptionManager;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -375,6 +376,13 @@
         c.setExecutor(executor);
         try {
             getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException | IllegalStateException e) {
             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
@@ -390,8 +398,6 @@
      * @param c The {@link RegistrationCallback} to be removed.
      * @see SubscriptionManager.OnSubscriptionsChangedListener
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
-     * @throws IllegalArgumentException if the subscription ID associated with this callback is
-     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
@@ -445,6 +451,13 @@
         c.setExecutor(executor);
         try {
             getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }  catch (IllegalStateException e) {
@@ -460,8 +473,6 @@
      * inactive subscription, it will result in a no-op.
      * @param c The MmTel {@link CapabilityCallback} to be removed.
      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
-     * @throws IllegalArgumentException if the subscription ID associated with this callback is
-     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
@@ -482,12 +493,9 @@
      * be enabled as long as the carrier has provisioned these services for the specified
      * subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
      * carrier requirements.
-     *
-     * Modifying this value may also trigger an IMS registration or deregistration, depending on
-     * whether or not the new value is enabled or disabled.
-     *
+     * <p>
      * Note: If the carrier configuration for advanced calling is not editable or hidden, this
-     * method will do nothing and will instead always use the default value.
+     * method will always return the default value.
      *
      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
      * @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
@@ -495,12 +503,21 @@
      * @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
      * @see #setAdvancedCallingSettingEnabled(boolean)
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @return true if the user's setting for advanced calling is enabled, false otherwise.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isAdvancedCallingSettingEnabled() {
         try {
             return getITelephony().isAdvancedCallingSettingEnabled(mSubId);
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -526,12 +543,20 @@
      * @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
      * @see #isAdvancedCallingSettingEnabled()
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
         try {
             getITelephony().setAdvancedCallingSettingEnabled(mSubId, isEnabled);
-            return;
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -597,6 +622,9 @@
 
     /**
      * The user's setting for whether or not they have enabled the "Video Calling" setting.
+     *
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @return true if the user’s “Video Calling” setting is currently enabled.
      * @see #setVtSettingEnabled(boolean)
      */
@@ -604,6 +632,13 @@
     public boolean isVtSettingEnabled() {
         try {
             return getITelephony().isVtSettingEnabled(mSubId);
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -611,13 +646,22 @@
 
     /**
      * Change the user's setting for Video Telephony and enable the Video Telephony capability.
+     *
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @see #isVtSettingEnabled()
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setVtSettingEnabled(boolean isEnabled) {
         try {
             getITelephony().setVtSettingEnabled(mSubId, isEnabled);
-            return;
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -625,12 +669,22 @@
 
     /**
      * @return true if the user's setting for Voice over WiFi is enabled and false if it is not.
+     *
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @see #setVoWiFiSettingEnabled(boolean)
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isVoWiFiSettingEnabled() {
         try {
             return getITelephony().isVoWiFiSettingEnabled(mSubId);
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -638,6 +692,9 @@
 
     /**
      * Sets the user's setting for whether or not Voice over WiFi is enabled.
+     *
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
      * @see #isVoWiFiSettingEnabled()
      */
@@ -645,13 +702,23 @@
     public void setVoWiFiSettingEnabled(boolean isEnabled) {
         try {
             getITelephony().setVoWiFiSettingEnabled(mSubId, isEnabled);
-            return;
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
     /**
+     * Returns the user's voice over WiFi roaming setting associated with the current subscription.
+     *
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @return true if the user's setting for Voice over WiFi while roaming is enabled, false
      * if disabled.
      * @see #setVoWiFiRoamingSettingEnabled(boolean)
@@ -660,6 +727,13 @@
     public boolean isVoWiFiRoamingSettingEnabled() {
         try {
             return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId);
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -667,15 +741,24 @@
 
     /**
      * Change the user's setting for Voice over WiFi while roaming.
+     *
      * @param isEnabled true if the user's setting for Voice over WiFi while roaming is enabled,
      *     false otherwise.
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @see #isVoWiFiRoamingSettingEnabled()
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
         try {
             getITelephony().setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
-            return;
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -691,19 +774,31 @@
      * - {@link #WIFI_MODE_WIFI_ONLY}
      * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
      * - {@link #WIFI_MODE_WIFI_PREFERRED}
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @see #setVoWiFiSettingEnabled(boolean)
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
         try {
             getITelephony().setVoWiFiNonPersistent(mSubId, isCapable, mode);
-            return;
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
     /**
+     * Returns the user's voice over WiFi Roaming mode setting associated with the device.
+     *
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @return The Voice over WiFi Mode preference set by the user, which can be one of the
      * following:
      * - {@link #WIFI_MODE_WIFI_ONLY}
@@ -715,6 +810,13 @@
     public @WiFiCallingMode int getVoWiFiModeSetting() {
         try {
             return getITelephony().getVoWiFiModeSetting(mSubId);
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -727,13 +829,21 @@
      * - {@link #WIFI_MODE_WIFI_ONLY}
      * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
      * - {@link #WIFI_MODE_WIFI_PREFERRED}
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @see #getVoWiFiModeSetting()
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
         try {
             getITelephony().setVoWiFiModeSetting(mSubId, mode);
-            return;
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -748,12 +858,21 @@
      *     - {@link #WIFI_MODE_WIFI_ONLY}
      *     - {@link #WIFI_MODE_CELLULAR_PREFERRED}
      *     - {@link #WIFI_MODE_WIFI_PREFERRED}
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @see #setVoWiFiRoamingSettingEnabled(boolean)
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
         try {
             return getITelephony().getVoWiFiRoamingModeSetting(mSubId);
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -768,13 +887,21 @@
      *     - {@link #WIFI_MODE_WIFI_ONLY}
      *     - {@link #WIFI_MODE_CELLULAR_PREFERRED}
      *     - {@link #WIFI_MODE_WIFI_PREFERRED}
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @see #getVoWiFiRoamingModeSetting()
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
         try {
             getITelephony().setVoWiFiRoamingModeSetting(mSubId, mode);
-            return;
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -787,13 +914,21 @@
      * {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting
      * for RTT. That value is enabled/disabled separately by the user through the Accessibility
      * settings.
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @param isEnabled if true RTT should be enabled during calls made on this subscription.
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setRttCapabilitySetting(boolean isEnabled) {
         try {
             getITelephony().setRttCapabilitySetting(mSubId, isEnabled);
-            return;
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -801,6 +936,9 @@
 
     /**
      * @return true if TTY over VoLTE is supported
+     *
+     * @throws IllegalArgumentException if the subscription associated with this operation is not
+     * active (SIM is not inserted, ESIM inactive) or invalid.
      * @see android.telecom.TelecomManager#getCurrentTtyMode
      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
      */
@@ -808,6 +946,13 @@
     boolean isTtyOverVolteEnabled() {
         try {
             return getITelephony().isTtyOverVolteEnabled(mSubId);
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
+                // Rethrow as runtime error to keep API compatible.
+                throw new IllegalArgumentException(e.getMessage());
+            } else {
+                throw new RuntimeException(e.getMessage());
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
diff --git a/telephony/java/android/telephony/ims/RcsControllerCall.java b/telephony/java/android/telephony/ims/RcsControllerCall.java
index a2d68ad..ce03c3c 100644
--- a/telephony/java/android/telephony/ims/RcsControllerCall.java
+++ b/telephony/java/android/telephony/ims/RcsControllerCall.java
@@ -19,10 +19,11 @@
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.telephony.ims.aidl.IRcs;
+import android.telephony.ims.aidl.IRcsMessage;
 
 /**
- * A wrapper class around RPC calls that {@link RcsMessageStore} APIs to minimize boilerplate code.
+ * A wrapper class around RPC calls that {@link RcsMessageManager} APIs to minimize boilerplate
+ * code.
  *
  * @hide - not meant for public use
  */
@@ -34,13 +35,14 @@
     }
 
     <R> R call(RcsServiceCall<R> serviceCall) throws RcsMessageStoreException {
-        IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_RCS_SERVICE));
-        if (iRcs == null) {
+        IRcsMessage iRcsMessage = IRcsMessage.Stub.asInterface(ServiceManager.getService(
+                Context.TELEPHONY_RCS_MESSAGE_SERVICE));
+        if (iRcsMessage == null) {
             throw new RcsMessageStoreException("Could not connect to RCS storage service");
         }
 
         try {
-            return serviceCall.methodOnIRcs(iRcs, mContext.getOpPackageName());
+            return serviceCall.methodOnIRcs(iRcsMessage, mContext.getOpPackageName());
         } catch (RemoteException exception) {
             throw new RcsMessageStoreException(exception.getMessage());
         }
@@ -48,17 +50,17 @@
 
     void callWithNoReturn(RcsServiceCallWithNoReturn serviceCall)
             throws RcsMessageStoreException {
-        call((iRcs, callingPackage) -> {
-            serviceCall.methodOnIRcs(iRcs, callingPackage);
+        call((iRcsMessage, callingPackage) -> {
+            serviceCall.methodOnIRcs(iRcsMessage, callingPackage);
             return null;
         });
     }
 
     interface RcsServiceCall<R> {
-        R methodOnIRcs(IRcs iRcs, String callingPackage) throws RemoteException;
+        R methodOnIRcs(IRcsMessage iRcs, String callingPackage) throws RemoteException;
     }
 
     interface RcsServiceCallWithNoReturn {
-        void methodOnIRcs(IRcs iRcs, String callingPackage) throws RemoteException;
+        void methodOnIRcs(IRcsMessage iRcs, String callingPackage) throws RemoteException;
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsManager.java b/telephony/java/android/telephony/ims/RcsManager.java
deleted file mode 100644
index 0d6ca3c..0000000
--- a/telephony/java/android/telephony/ims/RcsManager.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.telephony.ims;
-
-import android.annotation.SystemService;
-import android.content.Context;
-
-/**
- * The manager class for RCS related utilities.
- *
- * @hide
- */
-@SystemService(Context.TELEPHONY_RCS_SERVICE)
-public class RcsManager {
-    private final RcsMessageStore mRcsMessageStore;
-
-    /**
-     * @hide
-     */
-    public RcsManager(Context context) {
-        mRcsMessageStore = new RcsMessageStore(context);
-    }
-
-    /**
-     * Returns an instance of {@link RcsMessageStore}
-     */
-    public RcsMessageStore getRcsMessageStore() {
-        return mRcsMessageStore;
-    }
-}
diff --git a/telephony/java/android/telephony/ims/RcsMessageStore.java b/telephony/java/android/telephony/ims/RcsMessageManager.java
similarity index 96%
rename from telephony/java/android/telephony/ims/RcsMessageStore.java
rename to telephony/java/android/telephony/ims/RcsMessageManager.java
index d112798..a1c7c0f 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStore.java
+++ b/telephony/java/android/telephony/ims/RcsMessageManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemService;
 import android.annotation.WorkerThread;
 import android.content.Context;
 import android.net.Uri;
@@ -25,15 +26,20 @@
 import java.util.List;
 
 /**
- * RcsMessageStore is the application interface to RcsProvider and provides access methods to
+ * RcsMessageManager is the application interface to RcsProvider and provides access methods to
  * RCS related database tables.
  *
  * @hide
  */
-public class RcsMessageStore {
+@SystemService(Context.TELEPHONY_RCS_MESSAGE_SERVICE)
+public class RcsMessageManager {
     RcsControllerCall mRcsControllerCall;
 
-    RcsMessageStore(Context context) {
+    /**
+     * Use {@link Context#getSystemService(String)} to get an instance of this service.
+     * @hide
+     */
+    public RcsMessageManager(Context context) {
         mRcsControllerCall = new RcsControllerCall(context);
     }
 
diff --git a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
index 4433c1c..53e4596 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl
@@ -17,6 +17,8 @@
 
 package android.telephony.ims.aidl;
 
+import android.os.PersistableBundle;
+
 import android.telephony.ims.aidl.IImsConfigCallback;
 
 import com.android.ims.ImsConfigListener;
@@ -37,4 +39,5 @@
     int setConfigInt(int item, int value);
     // Return result code defined in ImsConfig#OperationStatusConstants
     int setConfigString(int item, String value);
+    void updateImsCarrierConfigs(in PersistableBundle bundle);
 }
diff --git a/telephony/java/android/telephony/ims/aidl/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl
similarity index 99%
rename from telephony/java/android/telephony/ims/aidl/IRcs.aidl
rename to telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl
index 9ee15da..0ae6303 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcs.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcsMessage.aidl
@@ -35,7 +35,7 @@
  * RPC definition between RCS storage APIs and phone process.
  * {@hide}
  */
-interface IRcs {
+interface IRcsMessage {
     /////////////////////////
     // RcsMessageStore APIs
     /////////////////////////
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 321bfff..91b0a43 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.os.PersistableBundle;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.telephony.ims.aidl.IImsConfig;
@@ -182,6 +183,11 @@
             return retVal;
         }
 
+        @Override
+        public void updateImsCarrierConfigs(PersistableBundle bundle) throws RemoteException {
+            getImsConfigImpl().updateImsCarrierConfigs(bundle);
+        }
+
         private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
             ImsConfigImplBase ref = mImsConfigImplBaseWeakReference.get();
             if (ref == null) {
@@ -387,4 +393,11 @@
         // Base Implementation - To be overridden.
         return null;
     }
+
+    /**
+     * @hide
+     */
+    public void updateImsCarrierConfigs(PersistableBundle bundle) {
+        // Base Implementation - Should be overridden
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index a1bea4d..6498e49 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -22,6 +22,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.os.RemoteException;
+import android.permission.IPermissionManager;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
@@ -71,8 +72,8 @@
      * privileged apps may have changed.
      */
     public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
-            IPackageManager packageManager, TelephonyManager telephonyManager,
-            ContentResolver contentResolver, int userId) {
+            IPackageManager packageManager, IPermissionManager permissionManager,
+            TelephonyManager telephonyManager, ContentResolver contentResolver, int userId) {
         if (DEBUG) {
             Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
         }
@@ -81,8 +82,8 @@
                 config.getDisabledUntilUsedPreinstalledCarrierApps();
         ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
                 config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
-        disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager,
-                contentResolver, userId, systemCarrierAppsDisabledUntilUsed,
+        disableCarrierAppsUntilPrivileged(callingPackage, packageManager, permissionManager,
+                telephonyManager, contentResolver, userId, systemCarrierAppsDisabledUntilUsed,
                 systemCarrierAssociatedAppsDisabledUntilUsed);
     }
 
@@ -98,7 +99,8 @@
      * Manager can kill it, and this can lead to crashes as the app is in an unexpected state.
      */
     public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
-            IPackageManager packageManager, ContentResolver contentResolver, int userId) {
+            IPackageManager packageManager, IPermissionManager permissionManager,
+            ContentResolver contentResolver, int userId) {
         if (DEBUG) {
             Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
         }
@@ -109,7 +111,7 @@
 
         ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
                 config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
-        disableCarrierAppsUntilPrivileged(callingPackage, packageManager,
+        disableCarrierAppsUntilPrivileged(callingPackage, packageManager, permissionManager,
                 null /* telephonyManager */, contentResolver, userId,
                 systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed);
     }
@@ -117,7 +119,8 @@
     // Must be public b/c framework unit tests can't access package-private methods.
     @VisibleForTesting
     public static void disableCarrierAppsUntilPrivileged(String callingPackage,
-            IPackageManager packageManager, @Nullable TelephonyManager telephonyManager,
+            IPackageManager packageManager, IPermissionManager permissionManager,
+            @Nullable TelephonyManager telephonyManager,
             ContentResolver contentResolver, int userId,
             ArraySet<String> systemCarrierAppsDisabledUntilUsed,
             ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
@@ -256,7 +259,7 @@
                 // apps.
                 String[] packageNames = new String[enabledCarrierPackages.size()];
                 enabledCarrierPackages.toArray(packageNames);
-                packageManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId);
+                permissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId);
             }
         } catch (RemoteException e) {
             Slog.w(TAG, "Could not reach PackageManager", e);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 5a27a0f..dcfd193 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -308,18 +308,46 @@
      */
     List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg);
 
-     @UnsupportedAppUsage
-     int getCallState();
+    @UnsupportedAppUsage
+    int getCallState();
 
     /**
      * Returns the call state for a slot.
      */
-     int getCallStateForSlot(int slotIndex);
+    int getCallStateForSlot(int slotIndex);
 
-     @UnsupportedAppUsage
-     int getDataActivity();
-     @UnsupportedAppUsage
-     int getDataState();
+    /**
+     * Replaced by getDataActivityForSubId.
+     */
+    int getDataActivity();
+
+    /**
+     * Returns a constant indicating the type of activity on a data connection
+     * (cellular).
+     *
+     * @see #DATA_ACTIVITY_NONE
+     * @see #DATA_ACTIVITY_IN
+     * @see #DATA_ACTIVITY_OUT
+     * @see #DATA_ACTIVITY_INOUT
+     * @see #DATA_ACTIVITY_DORMANT
+     */
+    int getDataActivityForSubId(int subId);
+
+    /**
+     * Replaced by getDataStateForSubId.
+     */
+    int getDataState();
+
+    /**
+     * Returns a constant indicating the current data connection state
+     * (cellular).
+     *
+     * @see #DATA_DISCONNECTED
+     * @see #DATA_CONNECTING
+     * @see #DATA_CONNECTED
+     * @see #DATA_SUSPENDED
+     */
+    int getDataStateForSubId(int subId);
 
     /**
      * Returns the current active phone type as integer.
@@ -1059,6 +1087,11 @@
     String[] getMergedSubscriberIds(int subId, String callingPackage);
 
     /**
+     * @hide
+     */
+    String[] getMergedSubscriberIdsFromGroup(int subId, String callingPackage);
+
+    /**
      * Override the operator branding for the current ICCID.
      *
      * Once set, whenever the SIM is present in the device, the service
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 7a0ab9c..51c5d12 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -600,26 +600,21 @@
         }
     }
 
-    /**
-     * Returns whether the provided uid has carrier privileges for any active subscription ID.
-     */
-    private static boolean checkCarrierPrivilegeForAnySubId(Context context,
-            Supplier<ITelephony> telephonySupplier, int uid) {
+    /** Returns whether the provided uid has carrier privileges for any active subscription ID. */
+    private static boolean checkCarrierPrivilegeForAnySubId(
+            Context context, Supplier<ITelephony> telephonySupplier, int uid) {
         SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-        int[] activeSubIds = sm.getActiveSubscriptionIdList();
-        if (activeSubIds != null) {
-            for (int activeSubId : activeSubIds) {
-                if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
-                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-                    return true;
-                }
+        int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
+        for (int activeSubId : activeSubIds) {
+            if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
+                    == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                return true;
             }
         }
         return false;
     }
 
-
     private static int getCarrierPrivilegeStatus(
             Supplier<ITelephony> telephonySupplier, int subId, int uid) {
         ITelephony telephony = telephonySupplier.get();
diff --git a/test-base/Android.mk b/test-base/Android.mk
deleted file mode 100644
index a9d30cf..0000000
--- a/test-base/Android.mk
+++ /dev/null
@@ -1,29 +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)
-
-ifeq ($(HOST_OS),linux)
-# Build the legacy-performance-test-hostdex library
-# =================================================
-# This contains the android.test.PerformanceTestCase class only
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := src/android/test/PerformanceTestCase.java
-LOCAL_MODULE := legacy-performance-test-hostdex
-
-include $(BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY)
-endif  # HOST_OS == linux
diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index e9a5ff7..4d8c7d9 100644
--- a/test-mock/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
@@ -16,6 +16,7 @@
 
 package android.test.mock;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentProvider;
 import android.content.ContentProviderOperation;
@@ -23,6 +24,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.IContentProvider;
+import android.content.Intent;
 import android.content.OperationApplicationException;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
@@ -154,6 +156,11 @@
                 ICancellationSignal cancellationSignal) throws RemoteException {
             return MockContentProvider.this.refresh(url, args);
         }
+
+        @Override
+        public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags) {
+            return MockContentProvider.this.checkUriPermission(uri, uid, modeFlags);
+        }
     }
     private final InversionIContentProvider mIContentProvider = new InversionIContentProvider();
 
@@ -266,6 +273,12 @@
         throw new UnsupportedOperationException("unimplemented mock method call");
     }
 
+    /** {@hide} */
+    @Override
+    public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) {
+        throw new UnsupportedOperationException("unimplemented mock method call");
+    }
+
     /**
      * Returns IContentProvider which calls back same methods in this class.
      * By overriding this class, we avoid the mechanism hidden behind ContentProvider
diff --git a/test-mock/src/android/test/mock/MockIContentProvider.java b/test-mock/src/android/test/mock/MockIContentProvider.java
index fc2a464..b072d74 100644
--- a/test-mock/src/android/test/mock/MockIContentProvider.java
+++ b/test-mock/src/android/test/mock/MockIContentProvider.java
@@ -16,12 +16,14 @@
 
 package android.test.mock;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderResult;
 import android.content.ContentValues;
 import android.content.EntityIterator;
 import android.content.IContentProvider;
+import android.content.Intent;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
@@ -144,4 +146,10 @@
             ICancellationSignal cancellationSignal) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
+
+    /** {@hide} */
+    @Override
+    public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags) {
+        throw new UnsupportedOperationException("unimplemented mock method call");
+    }
 }
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs b/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rscript
similarity index 100%
rename from tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs
rename to tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rscript
diff --git a/tests/Codegen/Android.bp b/tests/Codegen/Android.bp
new file mode 100644
index 0000000..966c560
--- /dev/null
+++ b/tests/Codegen/Android.bp
@@ -0,0 +1,25 @@
+android_test {
+    name: "CodegenTests",
+    srcs: [
+        "**/*.java",
+    ],
+
+    platform_apis: true,
+    test_suites: ["device-tests"],
+    certificate: "platform",
+
+    optimize: {
+        enabled: false,
+    },
+
+    plugins: [
+        "staledataclass-annotation-processor",
+    ],
+    static_libs: [
+        "junit",
+        "hamcrest",
+        "hamcrest-library",
+        "androidx.test.runner",
+        "androidx.test.rules",
+    ],
+}
diff --git a/tests/Codegen/AndroidManifest.xml b/tests/Codegen/AndroidManifest.xml
new file mode 100644
index 0000000..2f18550
--- /dev/null
+++ b/tests/Codegen/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.codegentest">
+
+    <application/>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.codegentest"
+        android:label="Codegen test" />
+</manifest>
diff --git a/tests/Codegen/AndroidTest.xml b/tests/Codegen/AndroidTest.xml
new file mode 100644
index 0000000..4dbbc55
--- /dev/null
+++ b/tests/Codegen/AndroidTest.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<configuration description="Runs Codegen Tests.">
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.codegentest" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/tests/Codegen/OWNERS b/tests/Codegen/OWNERS
new file mode 100644
index 0000000..da723b3
--- /dev/null
+++ b/tests/Codegen/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com
\ No newline at end of file
diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh
new file mode 100755
index 0000000..fe3adf9
--- /dev/null
+++ b/tests/Codegen/runTest.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+if [[ "$0" = *"/Codegen/runTest.sh" ]]; then
+	#running in subshell - print code to eval and exit
+	echo "source $0"
+else
+    function header_and_eval() {
+        printf "\n[ $* ]\n" 1>&2
+        eval "$@"
+        return $?
+    }
+
+    header_and_eval m -j16 codegen && \
+        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 && \
+        header_and_eval adb install -r -t $ANDROID_PRODUCT_OUT/testcases/CodegenTests/arm64/CodegenTests.apk && \
+        # header_and_eval adb shell am set-debug-app -w com.android.codegentest && \
+        header_and_eval adb shell am instrument -w -e package com.android.codegentest com.android.codegentest/androidx.test.runner.AndroidJUnitRunner
+
+        exitCode=$?
+
+        # header_and_eval adb shell am clear-debug-app
+
+        return $exitCode
+fi
\ No newline at end of file
diff --git a/tests/Codegen/src/com/android/codegentest/DateParcelling.java b/tests/Codegen/src/com/android/codegentest/DateParcelling.java
new file mode 100644
index 0000000..b0b00d0
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/DateParcelling.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.codegentest;
+
+import android.os.Parcel;
+
+import com.android.internal.util.Parcelling;
+
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Sample {@link Parcelling} implementation for {@link Date}.
+ *
+ * See {@link SampleDataClass#mDate} for usage.
+ * See {@link SampleDataClass#writeToParcel} + {@link SampleDataClass#sParcellingForDate}
+ * for resulting generated code.
+ *
+ * Ignore {@link #sInstanceCount} - used for testing.
+ */
+public class DateParcelling implements Parcelling<Date> {
+
+    static AtomicInteger sInstanceCount = new AtomicInteger(0);
+
+    public DateParcelling() {
+        sInstanceCount.getAndIncrement();
+    }
+
+    @Override
+    public void parcel(Date item, Parcel dest, int parcelFlags) {
+        dest.writeLong(item.getTime());
+    }
+
+    @Override
+    public Date unparcel(Parcel source) {
+        return new Date(source.readLong());
+    }
+}
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.aidl b/tests/Codegen/src/com/android/codegentest/SampleDataClass.aidl
similarity index 79%
rename from wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.aidl
rename to tests/Codegen/src/com/android/codegentest/SampleDataClass.aidl
index c81d1f9..f14d47c 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.aidl
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 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,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.codegentest;
 
-package android.net.wifi.p2p.servicediscovery;
-
-parcelable WifiP2pServiceResponse;
+parcelable SampleDataClass;
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
new file mode 100644
index 0000000..03127ec
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -0,0 +1,1542 @@
+/*
+ * 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.codegentest;
+
+import android.annotation.FloatRange;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.Size;
+import android.annotation.StringDef;
+import android.annotation.StringRes;
+import android.annotation.UserIdInt;
+import android.net.LinkAddress;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.internal.util.AnnotationValidations;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.DataClass.Each;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+/**
+ * Sample data class, showing off various code generation features.
+ *
+ * See javadoc on non-generated code for the explanation of the various features.
+ *
+ * See {@link SampleDataClassTest} for various invariants the generated code is expected to hold.
+ */
+@DataClass(
+//        genParcelable = true, // implied by `implements Parcelable`
+//        genAidl = true,       // implied by `implements Parcelable`
+//        genGetters = true,    // on by default
+//        genConstDefs = true,  // implied by presence of constants with common prefix
+        genEqualsHashCode = true,
+        genBuilder = true,
+        genToString = true,
+        genForEachField = true,
+        genConstructor = true   // on by default but normally suppressed by genBuilder
+)
+public final class SampleDataClass implements Parcelable {
+
+    /**
+     * For any group of {@link int} or {@link String} constants like these, a corresponding
+     * {@link IntDef}/{@link StringDef} will get generated, with name based on common prefix
+     * by default.
+     *
+     * When {@link #SampleDataClass constructing} an instance, fields annotated with these
+     * annotations get automatically validated, with only provided constants being a valid value.
+     *
+     * @see StateName, the generated {@link StringDef}
+     * @see #mStateName annotated with {@link StateName}
+     */
+    public static final String STATE_NAME_UNDEFINED = "?";
+    public static final String STATE_NAME_ON = "on";
+    public static final String STATE_NAME_OFF = "off";
+
+    /**
+     * Additionally, for any generated {@link IntDef} a corresponding static
+     * *ToString method will be also generated, and used in {@link #toString()}.
+     *
+     * @see #stateToString(int)
+     * @see #toString()
+     * @see State
+     */
+    public static final int STATE_UNDEFINED = -1;
+    public static final int STATE_ON = 1;
+    public static final int STATE_OFF = 0;
+
+    /**
+     * {@link IntDef}s with values specified in hex("0x...") are considered to be
+     * {@link IntDef#flag flags}, while ones specified with regular int literals are considered
+     * not to be flags.
+     *
+     * This affects their string representation, e.g. see the difference in
+     * {@link #requestFlagsToString} vs {@link #stateToString}.
+     *
+     * This also affects the validation logic when {@link #SampleDataClass constructing}
+     * an instance, with any flag combination("|") being valid.
+     *
+     * You can customize the name of the generated {@link IntDef}/{@link StringDef} annotation
+     * by annotating each constant with the desired name before running the generation.
+     *
+     * Here the annotation is named {@link RequestFlags} instead of the default {@code Flags}.
+     */
+    public static final @RequestFlags int FLAG_MANUAL_REQUEST = 0x1;
+    public static final @RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST = 0x2;
+    public static final @RequestFlags int FLAG_AUGMENTED_REQUEST = 0x80000000;
+
+
+    /**
+     * Any property javadoc should go onto the field, and will be copied where appropriate,
+     * including getters, constructor parameters, builder setters, etc.
+     *
+     * <p>
+     * This allows to avoid the burden of maintaining copies of the same documentation
+     * pieces in multiple places for each field.
+     */
+    private int mNum;
+    /**
+     * Various javadoc features should work as expected when copied, e.g {@code code},
+     * {@link #mName links}, <a href="https://google.com">html links</a>, etc.
+     *
+     * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
+     */
+    private int mNum2;
+    /**
+     * {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
+     * desired public API surface.
+     *
+     * @see #getNum4() is hidden
+     * @see Builder#setNum4(int) also hidden
+     * @hide
+     */
+    private int mNum4;
+
+    /**
+     * {@link Nullable} fields are considered optional and will not throw an exception if omitted
+     * (or set to null) when creating an instance either via a {@link Builder} or constructor.
+     */
+    private @Nullable String mName;
+    /**
+     * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+     * initialized to the provided default expression, unless explicitly set.
+     */
+    private String mName2 = "Bob";
+    /**
+     * Fields without {@link Nullable} annotation or default value are considered required.
+     *
+     * {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+     */
+    private @NonNull String mName4;
+
+    /**
+     * For parcelling, any field type supported by {@link Parcel} is supported out of the box.
+     * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
+     */
+    private AccessibilityNodeInfo mOtherParcelable = null;
+    /**
+     * Additionally, support for parcelling other types can be added by implementing a
+     * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
+     *
+     * @see DateParcelling an example {@link Parcelling} implementation
+     */
+    @DataClass.ParcelWith(DateParcelling.class)
+    private Date mDate = new Date(42 * 42);
+    /**
+     * If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn}
+     * to encourage its reuse.
+     */
+    @DataClass.ParcelWith(Parcelling.BuiltIn.ForPattern.class)
+    private Pattern mPattern = Pattern.compile("");
+
+    /**
+     * For lists, when using a {@link Builder}, other than a regular
+     * {@link Builder#setLinkAddresses2(List) setter}, and additional
+     * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
+     */
+    private List<LinkAddress> mLinkAddresses2 = new ArrayList<>();
+    /**
+     * For aesthetics, you may want to consider providing a singular version of the plural field
+     * name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method.
+     *
+     * @see Builder#addLinkAddress(LinkAddress)
+     */
+    @DataClass.PluralOf("linkAddress")
+    private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
+    /**
+     * For array fields, when using a {@link Builder}, vararg argument format is used for
+     * convenience.
+     *
+     * @see Builder#setLinkAddresses4(LinkAddress...)
+     */
+    private @Nullable LinkAddress[] mLinkAddresses4 = null;
+    /**
+     * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
+     * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
+     */
+    private boolean mActive = true;
+
+    /**
+     * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
+     * getter/constructor/setter/builder parameters, making for a nicer api.
+     *
+     * @see #getStateName
+     * @see Builder#setStateName
+     */
+    private @StateName String mStateName = STATE_NAME_UNDEFINED;
+    /**
+     * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
+     */
+    private @RequestFlags int mFlags;
+    /**
+     * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
+     */
+    private @State int mState = STATE_UNDEFINED;
+
+
+    /**
+     * Making a field public will suppress getter generation in favor of accessing it directly.
+     */
+    public CharSequence charSeq = "";
+    /**
+     * Final fields suppress generating a setter (when setters are requested).
+     */
+    private final LinkAddress[] mLinkAddresses5;
+    /**
+     * Transient fields are completely ignored and can be used for caching.
+     */
+    private transient LinkAddress[] mLinkAddresses6;
+    /**
+     * When using transient fields for caching it's often also a good idea to initialize them
+     * lazily.
+     *
+     * You can declare a special method like {@link #lazyInitTmpStorage()}, to let the
+     * {@link #getTmpStorage getter} lazily-initialize the value on demand.
+     */
+    transient int[] mTmpStorage;
+    private int[] lazyInitTmpStorage() {
+        return new int[100];
+    }
+
+    /**
+     * Fields with certain annotations are automatically validated in constructor
+     *
+     * You can see overloads in {@link AnnotationValidations} for a list of currently
+     * supported ones.
+     *
+     * You can also extend support to your custom annotations by creating another corresponding
+     * overloads like
+     * {@link AnnotationValidations#validate(Class, UserIdInt, int)}.
+     *
+     * @see #SampleDataClass
+     */
+    private @StringRes int mStringRes = 0;
+    /**
+     * Validation annotations may also have parameters.
+     *
+     * Parameter values will be supplied to validation method as name-value pairs.
+     *
+     * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
+     */
+    private @android.annotation.IntRange(from = 0, to = 4) int mLimited = 3;
+    /**
+     * Unnamed validation annotation parameter gets supplied to the validating method named as
+     * "value".
+     *
+     * Validation annotations following {@link Each} annotation, will be applied for each
+     * array/collection element instead.
+     *
+     * @see AnnotationValidations#validate(Class, Size, int, String, int)
+     */
+    @Size(2)
+    @Each @FloatRange(from = 0f)
+    private float[] mCoords = new float[] {0f, 0f};
+
+
+    /**
+     * Manually declaring any method that would otherwise be generated suppresses its generation,
+     * allowing for fine-grained overrides of the generated behavior.
+     */
+    public LinkAddress[] getLinkAddresses4() {
+        //Suppress autogen
+        return null;
+    }
+
+    /**
+     * Additionally, some methods like {@link #equals}, {@link #hashCode}, {@link #toString},
+     * {@link #writeToParcel}, {@link Parcelable.Creator#createFromParcel} allow you to define
+     * special methods to override their behavior on a per-field basis.
+     *
+     * See the generateted methods' descriptions for the detailed instructions of what the method
+     * signatures for such methods are expected to be.
+     *
+     * Here we use this to "fix" {@link Pattern} not implementing equals/hashCode.
+     *
+     * @see #equals
+     * @see #hashCode
+     */
+    private boolean patternEquals(Pattern other) {
+        return Objects.equals(mPattern.pattern(), other.pattern());
+    }
+    private int patternHashCode() {
+        return Objects.hashCode(mPattern.pattern());
+    }
+
+    /**
+     * Similarly, {@link #onConstructed()}, if defined, gets called at the end of constructing an
+     * instance.
+     *
+     * At this point all fields should be in place, so this is the right place to put any custom
+     * validation logic.
+     */
+    private void onConstructed() {
+        Preconditions.checkState(mNum2 == mNum4);
+    }
+
+    /**
+     * {@link DataClass#genForEachField} can be used to generate a generic {@link #forEachField}
+     * utility, which can be used for various use-cases not covered out of the box.
+     * Callback passed to {@link #forEachField} will be called once per each property with its name
+     * and value.
+     *
+     * Here for example it's used to implement a typical dump method.
+     *
+     * Note that there are 2 {@link #forEachField} versions provided, one that treats each field
+     * value as an {@link Object}, thus boxing primitives if any, and one that additionally takes
+     * specialized callbacks for particular primitive field types used in given class.
+     *
+     * Some primitives like {@link Boolean}s and {@link Integer}s within [-128, 127] don't allocate
+     * when boxed, so it's up to you to decide which one to use for a given use-case.
+     */
+    public void dump(PrintWriter pw) {
+        forEachField((self, name, value) -> {
+            pw.append("  ").append(name).append(": ").append(String.valueOf(value)).append('\n');
+        });
+    }
+
+
+
+    // Code below generated by codegen v0.0.1.
+    //   on Jul 17, 2019, 5:10:26 PM PDT
+    //
+    // DO NOT MODIFY!
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+    //
+    // CHECKSTYLE:OFF Generated code
+
+    @IntDef(prefix = "STATE_", value = {
+        STATE_UNDEFINED,
+        STATE_ON,
+        STATE_OFF
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface State {}
+
+    @DataClass.Generated.Member
+    public static String stateToString(@State int value) {
+        switch (value) {
+            case STATE_UNDEFINED:
+                    return "STATE_UNDEFINED";
+            case STATE_ON:
+                    return "STATE_ON";
+            case STATE_OFF:
+                    return "STATE_OFF";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    @IntDef(flag = true, prefix = "FLAG_", value = {
+        FLAG_MANUAL_REQUEST,
+        FLAG_COMPATIBILITY_MODE_REQUEST,
+        FLAG_AUGMENTED_REQUEST
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface RequestFlags {}
+
+    @DataClass.Generated.Member
+    public static String requestFlagsToString(@RequestFlags int value) {
+        return com.android.internal.util.BitUtils.flagsToString(
+                value, SampleDataClass::singleRequestFlagsToString);
+    }
+
+    @DataClass.Generated.Member
+    static String singleRequestFlagsToString(@RequestFlags int value) {
+        switch (value) {
+            case FLAG_MANUAL_REQUEST:
+                    return "FLAG_MANUAL_REQUEST";
+            case FLAG_COMPATIBILITY_MODE_REQUEST:
+                    return "FLAG_COMPATIBILITY_MODE_REQUEST";
+            case FLAG_AUGMENTED_REQUEST:
+                    return "FLAG_AUGMENTED_REQUEST";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    @StringDef(prefix = "STATE_NAME_", value = {
+        STATE_NAME_UNDEFINED,
+        STATE_NAME_ON,
+        STATE_NAME_OFF
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface StateName {}
+
+    @DataClass.Generated(
+            time = 1563408627046L,
+            codegenVersion = "0.0.1",
+            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)")
+
+/**
+     * @param num
+     *   Any property javadoc should go onto the field, and will be copied where appropriate,
+     *   including getters, constructor parameters, builder setters, etc.
+     *
+     *   <p>
+     *   This allows to avoid the burden of maintaining copies of the same documentation
+     *   pieces in multiple places for each field.
+     * @param num2
+     *   Various javadoc features should work as expected when copied, e.g {@code code},
+     *   {@link #mName links}, <a href="https://google.com">html links</a>, etc.
+     * @param num4
+     *   {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
+     *   desired public API surface.
+     * @param name
+     *   {@link Nullable} fields are considered optional and will not throw an exception if omitted
+     *   (or set to null) when creating an instance either via a {@link Builder} or constructor.
+     * @param name2
+     *   Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+     *   initialized to the provided default expression, unless explicitly set.
+     * @param name4
+     *   Fields without {@link Nullable} annotation or default value are considered required.
+     *
+     *   {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+     * @param otherParcelable
+     *   For parcelling, any field type supported by {@link Parcel} is supported out of the box.
+     *   E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
+     * @param date
+     *   Additionally, support for parcelling other types can be added by implementing a
+     *   {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
+     * @param pattern
+     *   If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn}
+     *   to encourage its reuse.
+     * @param linkAddresses2
+     *   For lists, when using a {@link Builder}, other than a regular
+     *   {@link Builder#setLinkAddresses2(List) setter}, and additional
+     *   {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
+     * @param linkAddresses
+     *   For aesthetics, you may want to consider providing a singular version of the plural field
+     *   name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method.
+     * @param linkAddresses4
+     *   For array fields, when using a {@link Builder}, vararg argument format is used for
+     *   convenience.
+     * @param active
+     *   For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
+     *   like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
+     * @param stateName
+     *   {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
+     *   getter/constructor/setter/builder parameters, making for a nicer api.
+     * @param flags
+     *   Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
+     * @param state
+     *   Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
+     * @param charSeq
+     *   Making a field public will suppress getter generation in favor of accessing it directly.
+     * @param linkAddresses5
+     *   Final fields suppress generating a setter (when setters are requested).
+     * @param stringRes
+     *   Fields with certain annotations are automatically validated in constructor
+     *
+     *   You can see overloads in {@link AnnotationValidations} for a list of currently
+     *   supported ones.
+     *
+     *   You can also extend support to your custom annotations by creating another corresponding
+     *   overloads like
+     *   {@link AnnotationValidations#validate(Class, UserIdInt, int)}.
+     * @param limited
+     *   Validation annotations may also have parameters.
+     *
+     *   Parameter values will be supplied to validation method as name-value pairs.
+     * @param coords
+     *   Unnamed validation annotation parameter gets supplied to the validating method named as
+     *   "value".
+     *
+     *   Validation annotations following {@link Each} annotation, will be applied for each
+     *   array/collection element instead.
+     */
+    @DataClass.Generated.Member
+    public SampleDataClass(
+            int num,
+            int num2,
+            int num4,
+            @Nullable String name,
+            String name2,
+            @NonNull String name4,
+            AccessibilityNodeInfo otherParcelable,
+            Date date,
+            Pattern pattern,
+            List<LinkAddress> linkAddresses2,
+            ArrayList<LinkAddress> linkAddresses,
+            @Nullable LinkAddress[] linkAddresses4,
+            boolean active,
+            @StateName String stateName,
+            @RequestFlags int flags,
+            @State int state,
+            CharSequence charSeq,
+            LinkAddress[] linkAddresses5,
+            @StringRes int stringRes,
+            @android.annotation.IntRange(from = 0, to = 4) int limited,
+            @Size(2) @FloatRange(from = 0f) float[] coords) {
+        this.mNum = num;
+        this.mNum2 = num2;
+        this.mNum4 = num4;
+        this.mName = name;
+        this.mName2 = name2;
+        this.mName4 = Preconditions.checkNotNull(name4);
+        this.mOtherParcelable = otherParcelable;
+        this.mDate = date;
+        this.mPattern = pattern;
+        this.mLinkAddresses2 = linkAddresses2;
+        this.mLinkAddresses = linkAddresses;
+        this.mLinkAddresses4 = linkAddresses4;
+        this.mActive = active;
+        this.mStateName = stateName;
+        this.mFlags = flags;
+        this.mState = state;
+        this.charSeq = charSeq;
+        this.mLinkAddresses5 = linkAddresses5;
+        this.mStringRes = stringRes;
+        this.mLimited = limited;
+        this.mCoords = coords;
+        AnnotationValidations.validate(
+                NonNull.class, null, mName4);
+
+        //noinspection PointlessBooleanExpression
+        if (true
+                && !(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
+                && !(Objects.equals(mStateName, STATE_NAME_ON))
+                && !(Objects.equals(mStateName, STATE_NAME_OFF))) {
+            throw new java.lang.IllegalArgumentException(
+                    "stateName was " + mStateName + " but must be one of: "
+                            + "STATE_NAME_UNDEFINED(" + STATE_NAME_UNDEFINED + "), "
+                            + "STATE_NAME_ON(" + STATE_NAME_ON + "), "
+                            + "STATE_NAME_OFF(" + STATE_NAME_OFF + ")");
+        }
+
+
+        //noinspection PointlessBitwiseExpression
+        Preconditions.checkFlagsArgument(
+                mFlags, 0
+                        | FLAG_MANUAL_REQUEST
+                        | FLAG_COMPATIBILITY_MODE_REQUEST
+                        | FLAG_AUGMENTED_REQUEST);
+
+        //noinspection PointlessBooleanExpression
+        if (true
+                && !(mState == STATE_UNDEFINED)
+                && !(mState == STATE_ON)
+                && !(mState == STATE_OFF)) {
+            throw new java.lang.IllegalArgumentException(
+                    "state was " + mState + " but must be one of: "
+                            + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+                            + "STATE_ON(" + STATE_ON + "), "
+                            + "STATE_OFF(" + STATE_OFF + ")");
+        }
+
+        AnnotationValidations.validate(
+                StringRes.class, null, mStringRes);
+        AnnotationValidations.validate(
+                android.annotation.IntRange.class, null, mLimited,
+                "from", 0,
+                "to", 4);
+        AnnotationValidations.validate(
+                Size.class, null, mCoords.length,
+                "value", 2);
+        int coordsSize = mCoords.length;
+        for (int i = 0; i < coordsSize; i++) {
+            AnnotationValidations.validate(
+                    FloatRange.class, null, mCoords[i],
+                    "from", 0f);
+        }
+
+
+        onConstructed();
+    }
+
+    /**
+     * Any property javadoc should go onto the field, and will be copied where appropriate,
+     * including getters, constructor parameters, builder setters, etc.
+     *
+     * <p>
+     * This allows to avoid the burden of maintaining copies of the same documentation
+     * pieces in multiple places for each field.
+     */
+    @DataClass.Generated.Member
+    public int getNum() {
+        return mNum;
+    }
+
+    /**
+     * Various javadoc features should work as expected when copied, e.g {@code code},
+     * {@link #mName links}, <a href="https://google.com">html links</a>, etc.
+     *
+     * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
+     */
+    @DataClass.Generated.Member
+    public int getNum2() {
+        return mNum2;
+    }
+
+    /**
+     * {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
+     * desired public API surface.
+     *
+     * @see #getNum4() is hidden
+     * @see Builder#setNum4(int) also hidden
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public int getNum4() {
+        return mNum4;
+    }
+
+    /**
+     * {@link Nullable} fields are considered optional and will not throw an exception if omitted
+     * (or set to null) when creating an instance either via a {@link Builder} or constructor.
+     */
+    @DataClass.Generated.Member
+    public @Nullable String getName() {
+        return mName;
+    }
+
+    /**
+     * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+     * initialized to the provided default expression, unless explicitly set.
+     */
+    @DataClass.Generated.Member
+    public String getName2() {
+        return mName2;
+    }
+
+    /**
+     * Fields without {@link Nullable} annotation or default value are considered required.
+     *
+     * {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+     */
+    @DataClass.Generated.Member
+    public @NonNull String getName4() {
+        return mName4;
+    }
+
+    /**
+     * For parcelling, any field type supported by {@link Parcel} is supported out of the box.
+     * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
+     */
+    @DataClass.Generated.Member
+    public AccessibilityNodeInfo getOtherParcelable() {
+        return mOtherParcelable;
+    }
+
+    /**
+     * Additionally, support for parcelling other types can be added by implementing a
+     * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
+     *
+     * @see DateParcelling an example {@link Parcelling} implementation
+     */
+    @DataClass.Generated.Member
+    public Date getDate() {
+        return mDate;
+    }
+
+    /**
+     * If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn}
+     * to encourage its reuse.
+     */
+    @DataClass.Generated.Member
+    public Pattern getPattern() {
+        return mPattern;
+    }
+
+    /**
+     * For lists, when using a {@link Builder}, other than a regular
+     * {@link Builder#setLinkAddresses2(List) setter}, and additional
+     * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
+     */
+    @DataClass.Generated.Member
+    public List<LinkAddress> getLinkAddresses2() {
+        return mLinkAddresses2;
+    }
+
+    /**
+     * For aesthetics, you may want to consider providing a singular version of the plural field
+     * name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method.
+     *
+     * @see Builder#addLinkAddress(LinkAddress)
+     */
+    @DataClass.Generated.Member
+    public ArrayList<LinkAddress> getLinkAddresses() {
+        return mLinkAddresses;
+    }
+
+    /**
+     * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
+     * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
+     */
+    @DataClass.Generated.Member
+    public boolean isActive() {
+        return mActive;
+    }
+
+    /**
+     * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
+     * getter/constructor/setter/builder parameters, making for a nicer api.
+     *
+     * @see #getStateName
+     * @see Builder#setStateName
+     */
+    @DataClass.Generated.Member
+    public @StateName String getStateName() {
+        return mStateName;
+    }
+
+    /**
+     * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
+     */
+    @DataClass.Generated.Member
+    public @RequestFlags int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
+     */
+    @DataClass.Generated.Member
+    public @State int getState() {
+        return mState;
+    }
+
+    /**
+     * Final fields suppress generating a setter (when setters are requested).
+     */
+    @DataClass.Generated.Member
+    public LinkAddress[] getLinkAddresses5() {
+        return mLinkAddresses5;
+    }
+
+    /**
+     * Fields with certain annotations are automatically validated in constructor
+     *
+     * You can see overloads in {@link AnnotationValidations} for a list of currently
+     * supported ones.
+     *
+     * You can also extend support to your custom annotations by creating another corresponding
+     * overloads like
+     * {@link AnnotationValidations#validate(Class, UserIdInt, int)}.
+     *
+     * @see #SampleDataClass
+     */
+    @DataClass.Generated.Member
+    public @StringRes int getStringRes() {
+        return mStringRes;
+    }
+
+    /**
+     * Validation annotations may also have parameters.
+     *
+     * Parameter values will be supplied to validation method as name-value pairs.
+     *
+     * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
+     */
+    @DataClass.Generated.Member
+    public @android.annotation.IntRange(from = 0, to = 4) int getLimited() {
+        return mLimited;
+    }
+
+    /**
+     * Unnamed validation annotation parameter gets supplied to the validating method named as
+     * "value".
+     *
+     * Validation annotations following {@link Each} annotation, will be applied for each
+     * array/collection element instead.
+     *
+     * @see AnnotationValidations#validate(Class, Size, int, String, int)
+     */
+    @DataClass.Generated.Member
+    public @Size(2) @FloatRange(from = 0f) float[] getCoords() {
+        return mCoords;
+    }
+
+    /**
+     * When using transient fields for caching it's often also a good idea to initialize them
+     * lazily.
+     *
+     * You can declare a special method like {@link #lazyInitTmpStorage()}, to let the
+     * {@link #getTmpStorage getter} lazily-initialize the value on demand.
+     */
+    @DataClass.Generated.Member
+    public int[] getTmpStorage() {
+        int[] tmpStorage = mTmpStorage;
+        if (tmpStorage == null) {
+            // You can mark field as volatile for thread-safe double-check init
+            tmpStorage = mTmpStorage = lazyInitTmpStorage();
+        }
+        return tmpStorage;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "SampleDataClass { " +
+                "num = " + mNum + ", " +
+                "num2 = " + mNum2 + ", " +
+                "num4 = " + mNum4 + ", " +
+                "name = " + mName + ", " +
+                "name2 = " + mName2 + ", " +
+                "name4 = " + mName4 + ", " +
+                "otherParcelable = " + mOtherParcelable + ", " +
+                "date = " + mDate + ", " +
+                "pattern = " + mPattern + ", " +
+                "linkAddresses2 = " + mLinkAddresses2 + ", " +
+                "linkAddresses = " + mLinkAddresses + ", " +
+                "linkAddresses4 = " + java.util.Arrays.toString(mLinkAddresses4) + ", " +
+                "active = " + mActive + ", " +
+                "stateName = " + mStateName + ", " +
+                "flags = " + requestFlagsToString(mFlags) + ", " +
+                "state = " + stateToString(mState) + ", " +
+                "charSeq = " + charSeq + ", " +
+                "linkAddresses5 = " + java.util.Arrays.toString(mLinkAddresses5) + ", " +
+                "stringRes = " + mStringRes + ", " +
+                "limited = " + mLimited + ", " +
+                "coords = " + java.util.Arrays.toString(mCoords) +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(SampleDataClass other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        SampleDataClass that = (SampleDataClass) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mNum == that.mNum
+                && mNum2 == that.mNum2
+                && mNum4 == that.mNum4
+                && Objects.equals(mName, that.mName)
+                && Objects.equals(mName2, that.mName2)
+                && Objects.equals(mName4, that.mName4)
+                && Objects.equals(mOtherParcelable, that.mOtherParcelable)
+                && Objects.equals(mDate, that.mDate)
+                && patternEquals(that.mPattern)
+                && Objects.equals(mLinkAddresses2, that.mLinkAddresses2)
+                && Objects.equals(mLinkAddresses, that.mLinkAddresses)
+                && java.util.Arrays.equals(mLinkAddresses4, that.mLinkAddresses4)
+                && mActive == that.mActive
+                && Objects.equals(mStateName, that.mStateName)
+                && mFlags == that.mFlags
+                && mState == that.mState
+                && Objects.equals(charSeq, that.charSeq)
+                && java.util.Arrays.equals(mLinkAddresses5, that.mLinkAddresses5)
+                && mStringRes == that.mStringRes
+                && mLimited == that.mLimited
+                && java.util.Arrays.equals(mCoords, that.mCoords);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + mNum;
+        _hash = 31 * _hash + mNum2;
+        _hash = 31 * _hash + mNum4;
+        _hash = 31 * _hash + Objects.hashCode(mName);
+        _hash = 31 * _hash + Objects.hashCode(mName2);
+        _hash = 31 * _hash + Objects.hashCode(mName4);
+        _hash = 31 * _hash + Objects.hashCode(mOtherParcelable);
+        _hash = 31 * _hash + Objects.hashCode(mDate);
+        _hash = 31 * _hash + patternHashCode();
+        _hash = 31 * _hash + Objects.hashCode(mLinkAddresses2);
+        _hash = 31 * _hash + Objects.hashCode(mLinkAddresses);
+        _hash = 31 * _hash + java.util.Arrays.hashCode(mLinkAddresses4);
+        _hash = 31 * _hash + Boolean.hashCode(mActive);
+        _hash = 31 * _hash + Objects.hashCode(mStateName);
+        _hash = 31 * _hash + mFlags;
+        _hash = 31 * _hash + mState;
+        _hash = 31 * _hash + Objects.hashCode(charSeq);
+        _hash = 31 * _hash + java.util.Arrays.hashCode(mLinkAddresses5);
+        _hash = 31 * _hash + mStringRes;
+        _hash = 31 * _hash + mLimited;
+        _hash = 31 * _hash + java.util.Arrays.hashCode(mCoords);
+        return _hash;
+    }
+
+    @DataClass.Generated.Member
+    void forEachField(
+            DataClass.PerIntFieldAction<SampleDataClass> actionInt,
+            DataClass.PerObjectFieldAction<SampleDataClass> actionObject) {
+        actionInt.acceptInt(this, "num", mNum);
+        actionInt.acceptInt(this, "num2", mNum2);
+        actionInt.acceptInt(this, "num4", mNum4);
+        actionObject.acceptObject(this, "name", mName);
+        actionObject.acceptObject(this, "name2", mName2);
+        actionObject.acceptObject(this, "name4", mName4);
+        actionObject.acceptObject(this, "otherParcelable", mOtherParcelable);
+        actionObject.acceptObject(this, "date", mDate);
+        actionObject.acceptObject(this, "pattern", mPattern);
+        actionObject.acceptObject(this, "linkAddresses2", mLinkAddresses2);
+        actionObject.acceptObject(this, "linkAddresses", mLinkAddresses);
+        actionObject.acceptObject(this, "linkAddresses4", mLinkAddresses4);
+        actionObject.acceptObject(this, "active", mActive);
+        actionObject.acceptObject(this, "stateName", mStateName);
+        actionInt.acceptInt(this, "flags", mFlags);
+        actionInt.acceptInt(this, "state", mState);
+        actionObject.acceptObject(this, "charSeq", charSeq);
+        actionObject.acceptObject(this, "linkAddresses5", mLinkAddresses5);
+        actionInt.acceptInt(this, "stringRes", mStringRes);
+        actionInt.acceptInt(this, "limited", mLimited);
+        actionObject.acceptObject(this, "coords", mCoords);
+    }
+
+    /** @deprecated May cause boxing allocations - use with caution! */
+    @Deprecated
+    @DataClass.Generated.Member
+    void forEachField(DataClass.PerObjectFieldAction<SampleDataClass> action) {
+        action.acceptObject(this, "num", mNum);
+        action.acceptObject(this, "num2", mNum2);
+        action.acceptObject(this, "num4", mNum4);
+        action.acceptObject(this, "name", mName);
+        action.acceptObject(this, "name2", mName2);
+        action.acceptObject(this, "name4", mName4);
+        action.acceptObject(this, "otherParcelable", mOtherParcelable);
+        action.acceptObject(this, "date", mDate);
+        action.acceptObject(this, "pattern", mPattern);
+        action.acceptObject(this, "linkAddresses2", mLinkAddresses2);
+        action.acceptObject(this, "linkAddresses", mLinkAddresses);
+        action.acceptObject(this, "linkAddresses4", mLinkAddresses4);
+        action.acceptObject(this, "active", mActive);
+        action.acceptObject(this, "stateName", mStateName);
+        action.acceptObject(this, "flags", mFlags);
+        action.acceptObject(this, "state", mState);
+        action.acceptObject(this, "charSeq", charSeq);
+        action.acceptObject(this, "linkAddresses5", mLinkAddresses5);
+        action.acceptObject(this, "stringRes", mStringRes);
+        action.acceptObject(this, "limited", mLimited);
+        action.acceptObject(this, "coords", mCoords);
+    }
+
+    @DataClass.Generated.Member
+    static Parcelling<Date> sParcellingForDate =
+            Parcelling.Cache.get(
+                    DateParcelling.class);
+    static {
+        if (sParcellingForDate == null) {
+            sParcellingForDate = Parcelling.Cache.put(
+                    new DateParcelling());
+        }
+    }
+
+    @DataClass.Generated.Member
+    static Parcelling<Pattern> sParcellingForPattern =
+            Parcelling.Cache.get(
+                    Parcelling.BuiltIn.ForPattern.class);
+    static {
+        if (sParcellingForPattern == null) {
+            sParcellingForPattern = Parcelling.Cache.put(
+                    new Parcelling.BuiltIn.ForPattern());
+        }
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        long flg = 0;
+        if (mActive) flg |= 0x1000;
+        if (mName != null) flg |= 0x8;
+        if (mName2 != null) flg |= 0x10;
+        if (mOtherParcelable != null) flg |= 0x40;
+        if (mDate != null) flg |= 0x80;
+        if (mPattern != null) flg |= 0x100;
+        if (mLinkAddresses2 != null) flg |= 0x200;
+        if (mLinkAddresses != null) flg |= 0x400;
+        if (mLinkAddresses4 != null) flg |= 0x800;
+        if (mStateName != null) flg |= 0x2000;
+        if (charSeq != null) flg |= 0x10000;
+        if (mLinkAddresses5 != null) flg |= 0x20000;
+        if (mCoords != null) flg |= 0x100000;
+        dest.writeLong(flg);
+        dest.writeInt(mNum);
+        dest.writeInt(mNum2);
+        dest.writeInt(mNum4);
+        if (mName != null) dest.writeString(mName);
+        if (mName2 != null) dest.writeString(mName2);
+        dest.writeString(mName4);
+        if (mOtherParcelable != null) dest.writeTypedObject(mOtherParcelable, flags);
+        sParcellingForDate.parcel(mDate, dest, flags);
+        sParcellingForPattern.parcel(mPattern, dest, flags);
+        if (mLinkAddresses2 != null) dest.writeParcelableList(mLinkAddresses2, flags);
+        if (mLinkAddresses != null) dest.writeParcelableList(mLinkAddresses, flags);
+        if (mLinkAddresses4 != null) dest.writeTypedArray(mLinkAddresses4, flags);
+        if (mStateName != null) dest.writeString(mStateName);
+        dest.writeInt(mFlags);
+        dest.writeInt(mState);
+        if (charSeq != null) dest.writeCharSequence(charSeq);
+        if (mLinkAddresses5 != null) dest.writeTypedArray(mLinkAddresses5, flags);
+        dest.writeInt(mStringRes);
+        dest.writeInt(mLimited);
+        if (mCoords != null) dest.writeFloatArray(mCoords);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<SampleDataClass> CREATOR
+            = new Parcelable.Creator<SampleDataClass>() {
+        @Override
+        public SampleDataClass[] newArray(int size) {
+            return new SampleDataClass[size];
+        }
+
+        @Override
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        public SampleDataClass createFromParcel(Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            long flg = in.readLong();
+            boolean active = (flg & 0x1000) != 0;
+            int num = in.readInt();
+            int num2 = in.readInt();
+            int num4 = in.readInt();
+            String name = (flg & 0x8) == 0 ? null : in.readString();
+            String name2 = (flg & 0x10) == 0 ? null : in.readString();
+            String name4 = in.readString();
+            AccessibilityNodeInfo otherParcelable = (flg & 0x40) == 0 ? null : (AccessibilityNodeInfo) in.readTypedObject(AccessibilityNodeInfo.CREATOR);
+            Date date = sParcellingForDate.unparcel(in);
+            Pattern pattern = sParcellingForPattern.unparcel(in);
+            List<LinkAddress> linkAddresses2 = null;
+            if ((flg & 0x200) != 0) {
+                linkAddresses2 = new ArrayList<>();
+                in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader());
+            }
+            ArrayList<LinkAddress> linkAddresses = null;
+            if ((flg & 0x400) != 0) {
+                linkAddresses = new ArrayList<>();
+                in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader());
+            }
+            LinkAddress[] linkAddresses4 = (flg & 0x800) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
+            String stateName = (flg & 0x2000) == 0 ? null : in.readString();
+            int flags = in.readInt();
+            int state = in.readInt();
+            CharSequence _charSeq = (flg & 0x10000) == 0 ? null : (CharSequence) in.readCharSequence();
+            LinkAddress[] linkAddresses5 = (flg & 0x20000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
+            int stringRes = in.readInt();
+            int limited = in.readInt();
+            float[] coords = (flg & 0x100000) == 0 ? null : in.createFloatArray();
+            return new SampleDataClass(
+                    num,
+                    num2,
+                    num4,
+                    name,
+                    name2,
+                    name4,
+                    otherParcelable,
+                    date,
+                    pattern,
+                    linkAddresses2,
+                    linkAddresses,
+                    linkAddresses4,
+                    active,
+                    stateName,
+                    flags,
+                    state,
+                    _charSeq,
+                    linkAddresses5,
+                    stringRes,
+                    limited,
+                    coords);
+        }
+    };
+
+    /**
+     * A builder for {@link SampleDataClass}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static class Builder
+            extends android.provider.OneTimeUseBuilder<SampleDataClass> {
+
+        protected int mNum;
+        protected int mNum2;
+        protected int mNum4;
+        protected @Nullable String mName;
+        protected String mName2;
+        protected @NonNull String mName4;
+        protected AccessibilityNodeInfo mOtherParcelable;
+        protected Date mDate;
+        protected Pattern mPattern;
+        protected List<LinkAddress> mLinkAddresses2;
+        protected ArrayList<LinkAddress> mLinkAddresses;
+        protected @Nullable LinkAddress[] mLinkAddresses4;
+        protected boolean mActive;
+        protected @StateName String mStateName;
+        protected @RequestFlags int mFlags;
+        protected @State int mState;
+        protected CharSequence charSeq;
+        protected LinkAddress[] mLinkAddresses5;
+        protected @StringRes int mStringRes;
+        protected @android.annotation.IntRange(from = 0, to = 4) int mLimited;
+        protected @Size(2) @FloatRange(from = 0f) float[] mCoords;
+
+        protected long mBuilderFieldsSet = 0L;
+
+        public Builder() {};
+
+        /**
+         * Any property javadoc should go onto the field, and will be copied where appropriate,
+         * including getters, constructor parameters, builder setters, etc.
+         *
+         * <p>
+         * This allows to avoid the burden of maintaining copies of the same documentation
+         * pieces in multiple places for each field.
+         */
+        @DataClass.Generated.Member
+        public Builder setNum(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mNum = value;
+            return this;
+        }
+
+        /**
+         * Various javadoc features should work as expected when copied, e.g {@code code},
+         * {@link #mName links}, <a href="https://google.com">html links</a>, etc.
+         *
+         * @see #mNum2 ..and so should blocks at the bottom, e.g. {@code @see} blocks.
+         */
+        @DataClass.Generated.Member
+        public Builder setNum2(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mNum2 = value;
+            return this;
+        }
+
+        /**
+         * {@code @hide} javadoc annotation is also propagated, which can be used to adjust the
+         * desired public API surface.
+         *
+         * @see #getNum4() is hidden
+         * @see Builder#setNum4(int) also hidden
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public Builder setNum4(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mNum4 = value;
+            return this;
+        }
+
+        /**
+         * {@link Nullable} fields are considered optional and will not throw an exception if omitted
+         * (or set to null) when creating an instance either via a {@link Builder} or constructor.
+         */
+        @DataClass.Generated.Member
+        public Builder setName(@Nullable String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mName = value;
+            return this;
+        }
+
+        /**
+         * Fields with default value expressions ("mFoo = ...") are also optional, and are automatically
+         * initialized to the provided default expression, unless explicitly set.
+         */
+        @DataClass.Generated.Member
+        public Builder setName2(String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10;
+            mName2 = value;
+            return this;
+        }
+
+        /**
+         * Fields without {@link Nullable} annotation or default value are considered required.
+         *
+         * {@link NonNull} annotation is recommended on such non-primitive fields for documentation.
+         */
+        @DataClass.Generated.Member
+        public Builder setName4(@NonNull String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20;
+            mName4 = value;
+            return this;
+        }
+
+        /**
+         * For parcelling, any field type supported by {@link Parcel} is supported out of the box.
+         * E.g. {@link Parcelable} subclasses, {@link String}, {@link int}, {@link boolean}, etc.
+         */
+        @DataClass.Generated.Member
+        public Builder setOtherParcelable(AccessibilityNodeInfo value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x40;
+            mOtherParcelable = value;
+            return this;
+        }
+
+        /**
+         * Additionally, support for parcelling other types can be added by implementing a
+         * {@link Parcelling}, and referencing it in the {@link DataClass.ParcelWith} field annotation.
+         *
+         * @see DateParcelling an example {@link Parcelling} implementation
+         */
+        @DataClass.Generated.Member
+        public Builder setDate(Date value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x80;
+            mDate = value;
+            return this;
+        }
+
+        /**
+         * If a {@link Parcelling} is fairly common, consider putting it in {@link Parcelling.BuiltIn}
+         * to encourage its reuse.
+         */
+        @DataClass.Generated.Member
+        public Builder setPattern(Pattern value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x100;
+            mPattern = value;
+            return this;
+        }
+
+        /**
+         * For lists, when using a {@link Builder}, other than a regular
+         * {@link Builder#setLinkAddresses2(List) setter}, and additional
+         * {@link Builder#addLinkAddresses2(LinkAddress) add} method is generated for convenience.
+         */
+        @DataClass.Generated.Member
+        public Builder setLinkAddresses2(List<LinkAddress> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x200;
+            mLinkAddresses2 = value;
+            return this;
+        }
+
+        /** @see #setLinkAddresses2 */
+        @DataClass.Generated.Member
+        public Builder addLinkAddresses2(@NonNull LinkAddress value) {
+            // You can refine this method's name by providing item's singular name, e.g.:
+            // @DataClass.PluralOf("item")) mItems = ...
+
+            if (mLinkAddresses2 == null) setLinkAddresses2(new ArrayList<>());
+            mLinkAddresses2.add(value);
+            return this;
+        }
+
+        /**
+         * For aesthetics, you may want to consider providing a singular version of the plural field
+         * name, which would be used for the {@link #mLinkAddresses2 above mentioned} "add" method.
+         *
+         * @see Builder#addLinkAddress(LinkAddress)
+         */
+        @DataClass.Generated.Member
+        public Builder setLinkAddresses(ArrayList<LinkAddress> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x400;
+            mLinkAddresses = value;
+            return this;
+        }
+
+        /** @see #setLinkAddresses */
+        @DataClass.Generated.Member
+        public Builder addLinkAddress(@NonNull LinkAddress value) {
+            if (mLinkAddresses == null) setLinkAddresses(new ArrayList<>());
+            mLinkAddresses.add(value);
+            return this;
+        }
+
+        /**
+         * For array fields, when using a {@link Builder}, vararg argument format is used for
+         * convenience.
+         *
+         * @see Builder#setLinkAddresses4(LinkAddress...)
+         */
+        @DataClass.Generated.Member
+        public Builder setLinkAddresses4(@Nullable LinkAddress... value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x800;
+            mLinkAddresses4 = value;
+            return this;
+        }
+
+        /**
+         * For boolean fields, when using a {@link Builder}, in addition to a regular setter, methods
+         * like {@link Builder#markActive()} and {@link Builder#markNotActive()} are generated.
+         */
+        @DataClass.Generated.Member
+        public Builder setActive(boolean value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1000;
+            mActive = value;
+            return this;
+        }
+
+        /** @see #setActive */
+        @DataClass.Generated.Member
+        public Builder markActive() {
+            return setActive(true);
+        }
+
+        /** @see #setActive */
+        @DataClass.Generated.Member
+        public Builder markNotActive() {
+            return setActive(false);
+        }
+
+        /**
+         * {@link IntDef}/{@link StringDef}-annotated fields propagate the annotation to
+         * getter/constructor/setter/builder parameters, making for a nicer api.
+         *
+         * @see #getStateName
+         * @see Builder#setStateName
+         */
+        @DataClass.Generated.Member
+        public Builder setStateName(@StateName String value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2000;
+            mStateName = value;
+            return this;
+        }
+
+        /**
+         * Fields annotated with {@link IntDef} annotations also get a proper {@link #toString()} value.
+         */
+        @DataClass.Generated.Member
+        public Builder setFlags(@RequestFlags int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4000;
+            mFlags = value;
+            return this;
+        }
+
+        /**
+         * Above is true for both {@link IntDef#flag flags} and enum-like {@link IntDef}s
+         */
+        @DataClass.Generated.Member
+        public Builder setState(@State int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8000;
+            mState = value;
+            return this;
+        }
+
+        /**
+         * Making a field public will suppress getter generation in favor of accessing it directly.
+         */
+        @DataClass.Generated.Member
+        public Builder setCharSeq(CharSequence value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10000;
+            charSeq = value;
+            return this;
+        }
+
+        /**
+         * Final fields suppress generating a setter (when setters are requested).
+         */
+        @DataClass.Generated.Member
+        public Builder setLinkAddresses5(LinkAddress... value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x20000;
+            mLinkAddresses5 = value;
+            return this;
+        }
+
+        /**
+         * Fields with certain annotations are automatically validated in constructor
+         *
+         * You can see overloads in {@link AnnotationValidations} for a list of currently
+         * supported ones.
+         *
+         * You can also extend support to your custom annotations by creating another corresponding
+         * overloads like
+         * {@link AnnotationValidations#validate(Class, UserIdInt, int)}.
+         *
+         * @see #SampleDataClass
+         */
+        @DataClass.Generated.Member
+        public Builder setStringRes(@StringRes int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x40000;
+            mStringRes = value;
+            return this;
+        }
+
+        /**
+         * Validation annotations may also have parameters.
+         *
+         * Parameter values will be supplied to validation method as name-value pairs.
+         *
+         * @see AnnotationValidations#validate(Class, Size, int, String, int, String, int)
+         */
+        @DataClass.Generated.Member
+        public Builder setLimited(@android.annotation.IntRange(from = 0, to = 4) int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x80000;
+            mLimited = value;
+            return this;
+        }
+
+        /**
+         * Unnamed validation annotation parameter gets supplied to the validating method named as
+         * "value".
+         *
+         * Validation annotations following {@link Each} annotation, will be applied for each
+         * array/collection element instead.
+         *
+         * @see AnnotationValidations#validate(Class, Size, int, String, int)
+         */
+        @DataClass.Generated.Member
+        public Builder setCoords(@Size(2) @FloatRange(from = 0f) float... value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x100000;
+            mCoords = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public SampleDataClass build() {
+            markUsed();
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                throw new IllegalStateException("Required field not set: num");
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                throw new IllegalStateException("Required field not set: num2");
+            }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                throw new IllegalStateException("Required field not set: num4");
+            }
+            if ((mBuilderFieldsSet & 0x10) == 0) {
+                mName2 = "Bob";
+            }
+            if ((mBuilderFieldsSet & 0x20) == 0) {
+                throw new IllegalStateException("Required field not set: name4");
+            }
+            if ((mBuilderFieldsSet & 0x40) == 0) {
+                mOtherParcelable = null;
+            }
+            if ((mBuilderFieldsSet & 0x80) == 0) {
+                mDate = new Date(42 * 42);
+            }
+            if ((mBuilderFieldsSet & 0x100) == 0) {
+                mPattern = Pattern.compile("");
+            }
+            if ((mBuilderFieldsSet & 0x200) == 0) {
+                mLinkAddresses2 = new ArrayList<>();
+            }
+            if ((mBuilderFieldsSet & 0x400) == 0) {
+                mLinkAddresses = new ArrayList<>();
+            }
+            if ((mBuilderFieldsSet & 0x800) == 0) {
+                mLinkAddresses4 = null;
+            }
+            if ((mBuilderFieldsSet & 0x1000) == 0) {
+                mActive = true;
+            }
+            if ((mBuilderFieldsSet & 0x2000) == 0) {
+                mStateName = STATE_NAME_UNDEFINED;
+            }
+            if ((mBuilderFieldsSet & 0x4000) == 0) {
+                throw new IllegalStateException("Required field not set: flags");
+            }
+            if ((mBuilderFieldsSet & 0x8000) == 0) {
+                mState = STATE_UNDEFINED;
+            }
+            if ((mBuilderFieldsSet & 0x10000) == 0) {
+                charSeq = "";
+            }
+            if ((mBuilderFieldsSet & 0x20000) == 0) {
+                throw new IllegalStateException("Required field not set: linkAddresses5");
+            }
+            if ((mBuilderFieldsSet & 0x40000) == 0) {
+                mStringRes = 0;
+            }
+            if ((mBuilderFieldsSet & 0x80000) == 0) {
+                mLimited = 3;
+            }
+            if ((mBuilderFieldsSet & 0x100000) == 0) {
+                mCoords = new float[] { 0f, 0f };
+            }
+            SampleDataClass o = new SampleDataClass(
+                    mNum,
+                    mNum2,
+                    mNum4,
+                    mName,
+                    mName2,
+                    mName4,
+                    mOtherParcelable,
+                    mDate,
+                    mPattern,
+                    mLinkAddresses2,
+                    mLinkAddresses,
+                    mLinkAddresses4,
+                    mActive,
+                    mStateName,
+                    mFlags,
+                    mState,
+                    charSeq,
+                    mLinkAddresses5,
+                    mStringRes,
+                    mLimited,
+                    mCoords);
+            return o;
+        }
+    }
+
+}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
new file mode 100644
index 0000000..71e85ab
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.codegentest;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+
+import android.net.LinkAddress;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Tests {@link SampleDataClass} after it's augmented with dataclass codegen.
+ *
+ * Use {@code $ . runTest.sh} to run.
+ */
+@RunWith(AndroidJUnit4.class)
+public class SampleDataClassTest {
+
+    private SampleDataClass mSpecimen = newBuilder().build();
+
+    private static SampleDataClass.Builder newBuilder() {
+        return newIncompleteBuilder()
+                .setNum(42)
+                .setNum2(42)
+                .setNum4(42)
+                .setName4("foobar")
+                .setLinkAddresses5();
+    }
+
+    private static SampleDataClass.Builder newIncompleteBuilder() {
+        return new SampleDataClass.Builder()
+                .markActive()
+                .setName("some parcelable")
+                .setFlags(SampleDataClass.FLAG_MANUAL_REQUEST);
+    }
+
+    @Test
+    public void testParcelling_producesEqualInstance() {
+        SampleDataClass copy = parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR);
+        assertEquals(mSpecimen, copy);
+        assertEquals(mSpecimen.hashCode(), copy.hashCode());
+    }
+
+    @Test
+    public void testParcelling_producesInstanceWithEqualFields() {
+        SampleDataClass copy = parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR);
+        copy.forEachField((self, copyFieldName, copyFieldValue) -> {
+            mSpecimen.forEachField((self2, specimenFieldName, specimenFieldValue) -> {
+                if (copyFieldName.equals(specimenFieldName)
+                        && !copyFieldName.equals("pattern")
+                        && (specimenFieldValue == null
+                                || !specimenFieldValue.getClass().isArray())) {
+                    assertEquals("Mismatched field values for " + copyFieldName,
+                            specimenFieldValue, copyFieldValue);
+                }
+            });
+        });
+    }
+
+    @Test
+    public void testCustomParcelling_instanceIsCached() {
+        parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR);
+        parcelAndUnparcel(mSpecimen, SampleDataClass.CREATOR);
+        assertEquals(1, DateParcelling.sInstanceCount.get());
+    }
+
+    @Test
+    public void testDefaultFieldValue_isPropagated() {
+        assertEquals(new Date(42 * 42), mSpecimen.getDate());
+    }
+
+    @Test
+    public void testForEachField_avoidsBoxing() {
+        AtomicInteger intFieldCount = new AtomicInteger(0);
+        mSpecimen.forEachField(
+                (self, name, intValue) -> intFieldCount.getAndIncrement(),
+                (self, name, objectValue) -> {
+                    if (objectValue != null) {
+                        assertThat("Boxed field " + name,
+                                objectValue, not(instanceOf(Integer.class)));
+                    }
+                });
+        assertThat(intFieldCount.get(), greaterThanOrEqualTo(1));
+    }
+
+    @Test
+    public void testToString_containsEachField() {
+        String toString = mSpecimen.toString();
+
+        mSpecimen.forEachField((self, name, value) -> {
+            assertThat(toString, containsString(name));
+            if (value instanceof Integer) {
+                // Could be flags, their special toString tested separately
+            } else if (value instanceof Object[]) {
+                assertThat(toString, containsString(Arrays.toString((Object[]) value)));
+            } else if (value != null && value.getClass().isArray()) {
+                // Primitive array, uses multiple specialized Arrays.toString overloads
+            } else {
+                assertThat(toString, containsString("" + value));
+            }
+        });
+    }
+
+    @Test
+    public void testBuilder_propagatesValuesToInstance() {
+        assertEquals(43, newBuilder().setNum(43).build().getNum());
+    }
+
+    @Test
+    public void testPluralFields_canHaveCustomSingularBuilderName() {
+        newBuilder().addLinkAddress(new LinkAddress("127.0.0.1/24"));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuilder_usableOnlyOnce() {
+        SampleDataClass.Builder builder = newBuilder();
+        builder.build();
+        builder.build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testBuilder_throwsWhenRequiredFieldMissing() {
+        newIncompleteBuilder().build();
+    }
+
+    @Test
+    public void testIntDefs_haveCorrectToString() {
+        int flagsAsInt = SampleDataClass.FLAG_MANUAL_REQUEST
+                | SampleDataClass.FLAG_COMPATIBILITY_MODE_REQUEST;
+        String flagsAsString = SampleDataClass.requestFlagsToString(flagsAsInt);
+
+        assertThat(flagsAsString, containsString("MANUAL_REQUEST"));
+        assertThat(flagsAsString, containsString("COMPATIBILITY_MODE_REQUEST"));
+        assertThat(flagsAsString, not(containsString("1")));
+        assertThat(flagsAsString, not(containsString("" + flagsAsInt)));
+
+        String dataclassToString = newBuilder()
+                .setFlags(flagsAsInt)
+                .setState(SampleDataClass.STATE_UNDEFINED)
+                .build()
+                .toString();
+        assertThat(dataclassToString, containsString(flagsAsString));
+        assertThat(dataclassToString, containsString("UNDEFINED"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testFlags_getValidated() {
+        newBuilder().setFlags(12345).build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testIntEnums_getValidated() {
+        newBuilder().setState(12345).build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testStringEnums_getValidated() {
+        newBuilder().setStateName("foo").build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testCustomValidation_isTriggered() {
+        newBuilder().setNum2(-1).setNum4(1).build();
+    }
+
+    @Test
+    public void testLazyInit_isLazilyCalledOnce() {
+        assertNull(mSpecimen.mTmpStorage);
+
+        int[] tmpStorage = mSpecimen.getTmpStorage();
+        assertNotNull(tmpStorage);
+        assertSame(tmpStorage, mSpecimen.mTmpStorage);
+
+        int[] tmpStorageAgain = mSpecimen.getTmpStorage();
+        assertSame(tmpStorage, tmpStorageAgain);
+    }
+
+    private static <T extends Parcelable> T parcelAndUnparcel(
+            T original, Parcelable.Creator<T> creator) {
+        Parcel p = Parcel.obtain();
+        try {
+            original.writeToParcel(p, 0);
+            p.setDataPosition(0);
+            return creator.createFromParcel(p);
+        } finally {
+            p.recycle();
+        }
+    }
+}
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBoolTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBoolTest.java
index c21c403..3415d2e 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBoolTest.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBoolTest.java
@@ -384,55 +384,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBytesTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBytesTest.java
index 09fe40e..8796807 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBytesTest.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamBytesTest.java
@@ -306,55 +306,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamDoubleTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamDoubleTest.java
index 118fe34..2b54e96 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamDoubleTest.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamDoubleTest.java
@@ -611,55 +611,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamEnumTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamEnumTest.java
index f55d951..19bad70 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamEnumTest.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamEnumTest.java
@@ -454,55 +454,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed32Test.java
index df68476..2bc61a0 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed32Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed32Test.java
@@ -431,55 +431,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed64Test.java
index af4130b..a54ecf9 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed64Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFixed64Test.java
@@ -532,55 +532,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFloatTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFloatTest.java
index 9bc07dc..0477e9e 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFloatTest.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamFloatTest.java
@@ -563,55 +563,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt32Test.java
index 0065870..a7f3f65 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt32Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt32Test.java
@@ -449,55 +449,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt64Test.java
index 4d6d105..dc42468 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt64Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamInt64Test.java
@@ -529,55 +529,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamObjectTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamObjectTest.java
index 5e49eea..1c0832e 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamObjectTest.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamObjectTest.java
@@ -391,55 +391,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed32Test.java
index 75c88a4..d349ea2 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed32Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed32Test.java
@@ -431,55 +431,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed64Test.java
index 4c65cf4..81a9c59 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed64Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSFixed64Test.java
@@ -531,55 +531,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt32Test.java
index 6854cd8..9719444 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt32Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt32Test.java
@@ -431,55 +431,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt64Test.java
index c53e9d7..118476c 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt64Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamSInt64Test.java
@@ -506,55 +506,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamStringTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamStringTest.java
index 816d5f9..51ee78f 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamStringTest.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamStringTest.java
@@ -287,55 +287,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt32Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt32Test.java
index 50fc537..42f3e99 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt32Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt32Test.java
@@ -448,55 +448,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readLong(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt64Test.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt64Test.java
index 20969e9..8ba2c0c 100644
--- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt64Test.java
+++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamUInt64Test.java
@@ -525,55 +525,55 @@
         };
 
         ProtoInputStream pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readFloat(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readDouble(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readInt(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBoolean(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readBytes(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
 
         pi = new ProtoInputStream(protobuf);
-        pi.isNextField(fieldId1);
+        pi.nextField();
         try {
             pi.readString(fieldId1);
-            fail("Should have throw IllegalArgumentException");
+            fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException iae) {
             // good
         }
diff --git a/tests/libs-permissions/Android.bp b/tests/libs-permissions/Android.bp
index c7c4b10..330bfc9 100644
--- a/tests/libs-permissions/Android.bp
+++ b/tests/libs-permissions/Android.bp
@@ -14,16 +14,16 @@
 }
 
 java_library {
-    name: "com.android.test.libs.product_services",
+    name: "com.android.test.libs.system_ext",
     installable: true,
-    product_services_specific: true,
-    srcs: ["product_services/java/**/*.java"],
-    required: ["com.android.test.libs.product_services.xml"],
+    system_ext_specific: true,
+    srcs: ["system_ext/java/**/*.java"],
+    required: ["com.android.test.libs.system_ext.xml"],
 }
 
 prebuilt_etc {
-    name: "com.android.test.libs.product_services.xml",
-    src: "product_services/com.android.test.libs.product_services.xml",
+    name: "com.android.test.libs.system_ext.xml",
+    src: "system_ext/com.android.test.libs.system_ext.xml",
     sub_dir: "permissions",
-    product_services_specific: true,
+    system_ext_specific: true,
 }
diff --git a/tests/libs-permissions/product_services/com.android.test.libs.product_services.xml b/tests/libs-permissions/system_ext/com.android.test.libs.system_ext.xml
similarity index 81%
rename from tests/libs-permissions/product_services/com.android.test.libs.product_services.xml
rename to tests/libs-permissions/system_ext/com.android.test.libs.system_ext.xml
index 082a9be..fa56004 100644
--- a/tests/libs-permissions/product_services/com.android.test.libs.product_services.xml
+++ b/tests/libs-permissions/system_ext/com.android.test.libs.system_ext.xml
@@ -15,6 +15,6 @@
 -->
 
 <permissions>
-    <library name="com.android.test.libs.product_services"
-            file="/product_services/framework/com.android.test.libs.product_services.jar" />
+    <library name="com.android.test.libs.system_ext"
+            file="/system_ext/framework/com.android.test.libs.system_ext.jar" />
 </permissions>
diff --git a/tests/libs-permissions/product_services/java/com/android/test/libs/product_services/LibsProductServicesTest.java b/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java
similarity index 84%
rename from tests/libs-permissions/product_services/java/com/android/test/libs/product_services/LibsProductServicesTest.java
rename to tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java
index dcbdae8..9999aba 100644
--- a/tests/libs-permissions/product_services/java/com/android/test/libs/product_services/LibsProductServicesTest.java
+++ b/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.test.libs.product_services;
+package com.android.test.libs.system_ext;
 
 /**
- * Test class for product_services libs.
+ * Test class for system_ext libs.
  */
-public class LibsProductServicesTest {
+public class LibsSystemExtTest {
 
     /**
      * Dummy method for testing.
diff --git a/tests/privapp-permissions/Android.bp b/tests/privapp-permissions/Android.bp
index ca7864f..b661850 100644
--- a/tests/privapp-permissions/Android.bp
+++ b/tests/privapp-permissions/Android.bp
@@ -45,17 +45,17 @@
 }
 
 android_app {
-    name: "ProductServicesPrivAppPermissionTest",
+    name: "SystemExtPrivAppPermissionTest",
     sdk_version: "current",
     privileged: true,
-    manifest: "product_services/AndroidManifest.xml",
-    product_services_specific: true,
-    required: ["product_servicesprivapp-permissions-test.xml"],
+    manifest: "system_ext/AndroidManifest.xml",
+    system_ext_specific: true,
+    required: ["system_extprivapp-permissions-test.xml"],
 }
 
 prebuilt_etc {
-    name: "product_servicesprivapp-permissions-test.xml",
-    src: "product_services/privapp-permissions-test.xml",
+    name: "system_extprivapp-permissions-test.xml",
+    src: "system_ext/privapp-permissions-test.xml",
     sub_dir: "permissions",
-    product_services_specific: true,
+    system_ext_specific: true,
 }
diff --git a/tests/privapp-permissions/product_services/AndroidManifest.xml b/tests/privapp-permissions/system_ext/AndroidManifest.xml
similarity index 97%
rename from tests/privapp-permissions/product_services/AndroidManifest.xml
rename to tests/privapp-permissions/system_ext/AndroidManifest.xml
index 511ddee..4a0e82f 100644
--- a/tests/privapp-permissions/product_services/AndroidManifest.xml
+++ b/tests/privapp-permissions/system_ext/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.framework.permission.privapp.tests.product_services">
+          package="com.android.framework.permission.privapp.tests.system_ext">
 
     <!-- MANAGE_USB is signature|privileged -->
     <uses-permission android:name="android.permission.MANAGE_USB"/>
diff --git a/tests/privapp-permissions/product_services/privapp-permissions-test.xml b/tests/privapp-permissions/system_ext/privapp-permissions-test.xml
similarity index 85%
rename from tests/privapp-permissions/product_services/privapp-permissions-test.xml
rename to tests/privapp-permissions/system_ext/privapp-permissions-test.xml
index 43baebb..ad63e86 100644
--- a/tests/privapp-permissions/product_services/privapp-permissions-test.xml
+++ b/tests/privapp-permissions/system_ext/privapp-permissions-test.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <permissions>
-    <privapp-permissions package="com.android.framework.permission.privapp.tests.product_services">
+    <privapp-permissions package="com.android.framework.permission.privapp.tests.system_ext">
         <permission name="android.permission.MANAGE_USB"/>
     </privapp-permissions>
 </permissions>
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index 7f4a3ed..0be7dad 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -57,7 +57,7 @@
   std::unordered_set<std::string> kept_artifacts;
 
   // Whether or not to shorten resource paths in the APK.
-  bool shorten_resource_paths;
+  bool shorten_resource_paths = false;
 
   // Path to the output map of original resource paths to shortened paths.
   Maybe<std::string> shortened_paths_map_path;
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 11150dd..b725920 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -386,6 +386,9 @@
   manifest_action["package-verifier"];
   manifest_action["meta-data"] = meta_data_action;
   manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
+  manifest_action["queries"]["package"].Action(RequiredNameIsJavaPackage);
+  manifest_action["queries"]["intent"] = intent_filter_action;
+  // TODO: more complicated component name tag
 
   manifest_action["key-sets"]["key-set"]["public-key"];
   manifest_action["key-sets"]["upgrade-key-set"];
diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp
index 6b11de7..7f5d104 100644
--- a/tools/aapt2/optimize/ResourcePathShortener.cpp
+++ b/tools/aapt2/optimize/ResourcePathShortener.cpp
@@ -16,7 +16,6 @@
 
 #include "optimize/ResourcePathShortener.h"
 
-#include <math.h>
 #include <unordered_set>
 
 #include "androidfw/StringPiece.h"
@@ -51,18 +50,15 @@
 }
 
 
-// Calculate the optimal hash length such that an average of 10% of resources
-// collide in their shortened path.
+// Return the optimal hash length such that at most 10% of resources collide in
+// their shortened path.
 // Reference: http://matt.might.net/articles/counting-hash-collisions/
 int OptimalShortenedLength(int num_resources) {
-  int num_chars = 2;
-  double N = 64*64; // hash space when hash is 2 chars long
-  double max_collisions = num_resources * 0.1;
-  while (num_resources - N + N * pow((N - 1) / N, num_resources) > max_collisions) {
-    N *= 64;
-    num_chars++;
+  if (num_resources > 4000) {
+    return 3;
+  } else {
+    return 2;
   }
-  return num_chars;
 }
 
 std::string GetShortenedPath(const android::StringPiece& shortened_filename,
diff --git a/tools/codegen/.gitignore b/tools/codegen/.gitignore
new file mode 100755
index 0000000..9fb18b4
--- /dev/null
+++ b/tools/codegen/.gitignore
@@ -0,0 +1,2 @@
+.idea
+out
diff --git a/tools/codegen/Android.bp b/tools/codegen/Android.bp
new file mode 100644
index 0000000..805b296
--- /dev/null
+++ b/tools/codegen/Android.bp
@@ -0,0 +1,18 @@
+java_binary_host {
+    name: "codegen",
+    manifest: "manifest.txt",
+    srcs: [
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "javaparser",
+    ],
+}
+
+java_library_host {
+    name: "codegen-version-info",
+
+    srcs: [
+        "src/**/SharedConstants.kt",
+    ],
+}
diff --git a/tools/codegen/OWNERS b/tools/codegen/OWNERS
new file mode 100644
index 0000000..da723b3
--- /dev/null
+++ b/tools/codegen/OWNERS
@@ -0,0 +1 @@
+eugenesusla@google.com
\ No newline at end of file
diff --git a/tools/codegen/manifest.txt b/tools/codegen/manifest.txt
new file mode 100644
index 0000000..6e1018b
--- /dev/null
+++ b/tools/codegen/manifest.txt
@@ -0,0 +1 @@
+Main-class: com.android.codegen.MainKt
diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt
new file mode 100644
index 0000000..7ee79f6
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt
@@ -0,0 +1,49 @@
+package com.android.codegen
+
+import com.github.javaparser.JavaParser
+import com.github.javaparser.ParseProblemException
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
+
+open class ClassInfo(val sourceLines: List<String>) {
+
+    private val userSourceCode = (sourceLines + "}").joinToString("\n")
+    val fileAst = try {
+        JavaParser.parse(userSourceCode)!!
+    } catch (e: ParseProblemException) {
+        throw RuntimeException("Failed to parse code:\n" +
+                userSourceCode
+                        .lines()
+                        .mapIndexed { lnNum, ln -> "/*$lnNum*/$ln" }
+                        .joinToString("\n"),
+                e)
+    }
+    val classAst = fileAst.types[0] as ClassOrInterfaceDeclaration
+
+    fun hasMethod(name: String, vararg argTypes: String): Boolean {
+        return classAst.methods.any {
+            it.name.asString() == name &&
+                    it.parameters.map { it.type.asString() } == argTypes.toList()
+        }
+    }
+
+    val superInterfaces = (fileAst.types[0] as ClassOrInterfaceDeclaration)
+            .implementedTypes.map { it.asString() }
+
+    val ClassName = classAst.nameAsString
+    private val genericArgsAst = classAst.typeParameters
+    val genericArgs = if (genericArgsAst.isEmpty()) "" else {
+        genericArgsAst.map { it.nameAsString }.joinToString(", ").let { "<$it>" }
+    }
+    val ClassType = ClassName + genericArgs
+
+    val constDefs = mutableListOf<ConstDef>()
+
+    val fields = classAst.fields
+            .filterNot { it.isTransient || it.isStatic }
+            .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
+            .apply { lastOrNull()?.isLast = true }
+    val lazyTransientFields = classAst.fields
+            .filter { it.isTransient && !it.isStatic }
+            .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
+            .filter { hasMethod("lazyInit${it.NameUpperCamel}") }
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
new file mode 100644
index 0000000..33256b7
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -0,0 +1,311 @@
+package com.android.codegen
+
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
+import com.github.javaparser.ast.body.TypeDeclaration
+import com.github.javaparser.ast.expr.BooleanLiteralExpr
+import com.github.javaparser.ast.expr.NormalAnnotationExpr
+import com.github.javaparser.ast.type.ClassOrInterfaceType
+
+/**
+ * [ClassInfo] + utilities for printing out new class code with proper indentation and imports
+ */
+class ClassPrinter(
+    source: List<String>,
+    private val stringBuilder: StringBuilder,
+    var cliArgs: Array<String>
+) : ClassInfo(source) {
+
+    val GENERATED_MEMBER_HEADER by lazy { "@$GeneratedMember" }
+
+    // Imports
+    val NonNull by lazy { classRef("android.annotation.NonNull") }
+    val NonEmpty by lazy { classRef("android.annotation.NonEmpty") }
+    val Nullable by lazy { classRef("android.annotation.Nullable") }
+    val TextUtils by lazy { classRef("android.text.TextUtils") }
+    val LinkedHashMap by lazy { classRef("java.util.LinkedHashMap") }
+    val Collections by lazy { classRef("java.util.Collections") }
+    val Preconditions by lazy { classRef("com.android.internal.util.Preconditions") }
+    val ArrayList by lazy { classRef("java.util.ArrayList") }
+    val DataClass by lazy { classRef("com.android.internal.util.DataClass") }
+    val DataClassEnum by lazy { classRef("com.android.internal.util.DataClass.Enum") }
+    val ParcelWith by lazy { classRef("com.android.internal.util.DataClass.ParcelWith") }
+    val PluralOf by lazy { classRef("com.android.internal.util.DataClass.PluralOf") }
+    val Each by lazy { classRef("com.android.internal.util.DataClass.Each") }
+    val DataClassGenerated by lazy { classRef("com.android.internal.util.DataClass.Generated") }
+    val GeneratedMember by lazy { classRef("com.android.internal.util.DataClass.Generated.Member") }
+    val Parcelling by lazy { classRef("com.android.internal.util.Parcelling") }
+    val UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") }
+
+
+    /**
+     * Optionally shortens a class reference if there's a corresponding import present
+     */
+    fun classRef(fullName: String): String {
+        if (cliArgs.contains(FLAG_NO_FULL_QUALIFIERS)) {
+            return fullName.split(".").dropWhile { it[0].isLowerCase() }.joinToString(".")
+        }
+
+        val pkg = fullName.substringBeforeLast(".")
+        val simpleName = fullName.substringAfterLast(".")
+        if (fileAst.imports.any { imprt ->
+                    imprt.nameAsString == fullName
+                            || (imprt.isAsterisk && imprt.nameAsString == pkg)
+                }) {
+            return simpleName
+        } else {
+            val outerClass = pkg.substringAfterLast(".", "")
+            if (outerClass.firstOrNull()?.isUpperCase() ?: false) {
+                return classRef(pkg) + "." + simpleName
+            }
+        }
+        return fullName
+    }
+
+    /** @see classRef */
+    inline fun <reified T : Any> classRef(): String {
+        return classRef(T::class.java.name)
+    }
+
+    /** @see classRef */
+    fun memberRef(fullName: String): String {
+        val className = fullName.substringBeforeLast(".")
+        val methodName = fullName.substringAfterLast(".")
+        return if (fileAst.imports.any {
+                    it.isStatic
+                            && (it.nameAsString == fullName
+                            || (it.isAsterisk && it.nameAsString == className))
+                }) {
+            className.substringAfterLast(".") + "." + methodName
+        } else {
+            classRef(className) + "." + methodName
+        }
+    }
+
+    val dataClassAnnotationFeatures = classAst.annotations
+            .find { it.nameAsString == DataClass }
+            ?.let { it as? NormalAnnotationExpr }
+            ?.pairs
+            ?.map { pair -> pair.nameAsString to (pair.value as BooleanLiteralExpr).value }
+            ?.toMap()
+            ?: emptyMap()
+
+    val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, Each, UnsupportedAppUsage)
+
+    /**
+     * @return whether the given feature is enabled
+     */
+    operator fun FeatureFlag.invoke(): Boolean {
+        if (cliArgs.contains("--no-$kebabCase")) return false
+        if (cliArgs.contains("--$kebabCase")) return true
+
+        val annotationKey = "gen$upperCamelCase"
+        if (dataClassAnnotationFeatures.containsKey(annotationKey)) {
+            return dataClassAnnotationFeatures[annotationKey]!!
+        }
+
+        if (cliArgs.contains("--all")) return true
+        if (hidden) return true
+
+        return when (this) {
+            FeatureFlag.SETTERS ->
+                !FeatureFlag.CONSTRUCTOR() && !FeatureFlag.BUILDER() && fields.any { !it.isFinal }
+            FeatureFlag.BUILDER -> cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS) || onByDefault
+            FeatureFlag.CONSTRUCTOR -> !FeatureFlag.BUILDER()
+            FeatureFlag.PARCELABLE -> "Parcelable" in superInterfaces
+            FeatureFlag.AIDL -> FeatureFlag.PARCELABLE()
+            FeatureFlag.IMPLICIT_NONNULL -> fields.any { it.isNullable }
+                    && fields.none { "@$NonNull" in it.annotations }
+            else -> onByDefault
+        }
+    }
+
+    val FeatureFlag.hidden
+        get(): Boolean = when {
+            cliArgs.contains("--hidden-$kebabCase") -> true
+            this == FeatureFlag.BUILD_UPON -> FeatureFlag.BUILDER.hidden
+            else -> false
+        }
+
+    var currentIndent = INDENT_SINGLE
+        private set
+
+    fun pushIndent() {
+        currentIndent += INDENT_SINGLE
+    }
+
+    fun popIndent() {
+        currentIndent = currentIndent.substring(0, currentIndent.length - INDENT_SINGLE.length)
+    }
+
+    fun backspace() = stringBuilder.setLength(stringBuilder.length - 1)
+    val lastChar get() = stringBuilder[stringBuilder.length - 1]
+
+    private fun appendRaw(s: String) {
+        stringBuilder.append(s)
+    }
+
+    fun append(s: String) {
+        if (s.isBlank() && s != "\n") {
+            appendRaw(s)
+        } else {
+            appendRaw(s.lines().map { line ->
+                if (line.startsWith(" *")) line else line.trimStart()
+            }.joinToString("\n$currentIndent"))
+        }
+    }
+
+    fun appendSameLine(s: String) {
+        while (lastChar.isWhitespace() || lastChar.isNewline()) {
+            backspace()
+        }
+        appendRaw(s)
+    }
+
+    fun rmEmptyLine() {
+        while (lastChar.isWhitespaceNonNewline()) backspace()
+        if (lastChar.isNewline()) backspace()
+    }
+
+    /**
+     * Syntactic sugar for:
+     * ```
+     * +"code()";
+     * ```
+     * to append the given string plus a newline
+     */
+    operator fun String.unaryPlus() = append("$this\n")
+
+    /**
+     * Syntactic sugar for:
+     * ```
+     * !"code()";
+     * ```
+     * to append the given string without a newline
+     */
+    operator fun String.not() = append(this)
+
+    /**
+     * Syntactic sugar for:
+     * ```
+     * ... {
+     *     ...
+     * }+";"
+     * ```
+     * to append a ';' on same line after a block, and a newline afterwards
+     */
+    operator fun Unit.plus(s: String) {
+        appendSameLine(s)
+        +""
+    }
+
+    /**
+     * A multi-purpose syntactic sugar for appending the given string plus anything generated in
+     * the given [block], the latter with the appropriate deeper indent,
+     * and resetting the indent back to original at the end
+     *
+     * Usage examples:
+     *
+     * ```
+     * "if (...)" {
+     *     ...
+     * }
+     * ```
+     * to append a corresponding if block appropriate indentation
+     *
+     * ```
+     * "void foo(...)" {
+     *      ...
+     * }
+     * ```
+     * similar to the previous one, plus an extra empty line after the function body
+     *
+     * ```
+     * "void foo(" {
+     *      <args code>
+     * }
+     * ```
+     * to use proper indentation for args code and close the bracket on same line at end
+     *
+     * ```
+     * "..." {
+     *     ...
+     * }
+     * to use the correct indentation for inner code, resetting it at the end
+     */
+    inline operator fun String.invoke(block: ClassPrinter.() -> Unit) {
+        if (this == " {") {
+            appendSameLine(this)
+        } else {
+            append(this)
+        }
+        when {
+            endsWith("(") -> {
+                indentedBy(2, block)
+                appendSameLine(")")
+            }
+            endsWith("{") || endsWith(")") -> {
+                if (!endsWith("{")) appendSameLine(" {")
+                indentedBy(1, block)
+                +"}"
+                if ((endsWith(") {") || endsWith(")") || this == " {")
+                        && !startsWith("synchronized")
+                        && !startsWith("switch")
+                        && !startsWith("if ")
+                        && !contains(" else ")
+                        && !contains("new ")
+                        && !contains("return ")) {
+                    +"" // extra line after function definitions
+                }
+            }
+            else -> indentedBy(2, block)
+        }
+    }
+
+    inline fun indentedBy(level: Int, block: ClassPrinter.() -> Unit) {
+        append("\n")
+        level times {
+            append(INDENT_SINGLE)
+            pushIndent()
+        }
+        block()
+        level times { popIndent() }
+        rmEmptyLine()
+        +""
+    }
+
+    inline fun Iterable<FieldInfo>.forEachTrimmingTrailingComma(b: FieldInfo.() -> Unit) {
+        forEachApply {
+            b()
+            if (isLast) {
+                while (lastChar == ' ' || lastChar == '\n') backspace()
+                if (lastChar == ',') backspace()
+            }
+        }
+    }
+
+    inline operator fun <R> invoke(f: ClassPrinter.() -> R): R = run(f)
+
+    var BuilderClass = CANONICAL_BUILDER_CLASS
+    var BuilderType = BuilderClass + genericArgs
+
+    init {
+        val builderFactoryOverride = classAst.methods.find {
+            it.isStatic && it.nameAsString == "builder"
+        }
+        if (builderFactoryOverride != null) {
+            BuilderClass = (builderFactoryOverride.type as ClassOrInterfaceType).nameAsString
+            BuilderType = builderFactoryOverride.type.asString()
+        } else {
+            val builderExtension = (fileAst.types
+                    + classAst.childNodes.filterIsInstance(TypeDeclaration::class.java)).find {
+                it.nameAsString == CANONICAL_BUILDER_CLASS
+            }
+            if (builderExtension != null) {
+                BuilderClass = GENERATED_BUILDER_CLASS
+                val tp = (builderExtension as ClassOrInterfaceDeclaration).typeParameters
+                BuilderType = if (tp.isEmpty()) BuilderClass
+                else "$BuilderClass<${tp.map { it.nameAsString }.joinToString(", ")}>"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/ConstDef.kt b/tools/codegen/src/com/android/codegen/ConstDef.kt
new file mode 100644
index 0000000..f559d6f
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/ConstDef.kt
@@ -0,0 +1,17 @@
+package com.android.codegen
+
+import com.github.javaparser.ast.body.FieldDeclaration
+
+/**
+ * `@IntDef` or `@StringDef`
+ */
+data class ConstDef(val type: Type, val AnnotationName: String, val values: List<FieldDeclaration>) {
+
+    enum class Type {
+        INT, INT_FLAGS, STRING;
+
+        val isInt get() = this == INT || this == INT_FLAGS
+    }
+
+    val CONST_NAMES get() = values.flatMap { it.variables }.map { it.nameAsString }
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/FeatureFlag.kt b/tools/codegen/src/com/android/codegen/FeatureFlag.kt
new file mode 100644
index 0000000..24150d6
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/FeatureFlag.kt
@@ -0,0 +1,27 @@
+package com.android.codegen
+
+
+/**
+ * See also [ClassPrinter.invoke] for more default flag values resolution rules
+ */
+enum class FeatureFlag(val onByDefault: Boolean, val desc: String = "") {
+    PARCELABLE(false, "implement Parcelable contract"),
+    AIDL(false, "generate a 'parcelable declaration' .aidl file alongside"),
+    CONSTRUCTOR(true, "an all-argument constructor"),
+    BUILDER(false, "e.g. MyClass.builder().setFoo(..).build();"),
+    GETTERS(true, "getters, e.g. getFoo()"),
+    SETTERS(false, "chainable/fluent setters, e.g. setFoo(..).setBar(..)"),
+    WITHERS(false, "'immutable setters' returning a new instance, " +
+            "e.g. newFoo = foo.withBar(barValue)"),
+    EQUALS_HASH_CODE(false, "equals + hashCode based on fields"),
+    TO_STRING(false, "toString based on fields"),
+    BUILD_UPON(false, "builder factory from existing instance, " +
+            "e.g. instance.buildUpon().setFoo(..).build()"),
+    IMPLICIT_NONNULL(true, "treat lack of @Nullable as @NonNull for Object fields"),
+    COPY_CONSTRUCTOR(false, "a constructor for an instance identical to the given one"),
+    CONST_DEFS(true, "@Int/StringDef's based on declared static constants"),
+    FOR_EACH_FIELD(false, "forEachField((name, value) -> ...)");
+
+    val kebabCase = name.toLowerCase().replace("_", "-")
+    val upperCamelCase = name.split("_").map { it.toLowerCase().capitalize() }.joinToString("")
+}
diff --git a/tools/codegen/src/com/android/codegen/FieldInfo.kt b/tools/codegen/src/com/android/codegen/FieldInfo.kt
new file mode 100644
index 0000000..f326fd5
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/FieldInfo.kt
@@ -0,0 +1,216 @@
+package com.android.codegen
+
+import com.github.javaparser.JavaParser
+import com.github.javaparser.ast.body.FieldDeclaration
+import com.github.javaparser.ast.expr.ClassExpr
+import com.github.javaparser.ast.expr.Name
+import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr
+import com.github.javaparser.ast.expr.StringLiteralExpr
+import com.github.javaparser.ast.type.ArrayType
+import com.github.javaparser.ast.type.ClassOrInterfaceType
+import com.github.javaparser.javadoc.Javadoc
+import java.lang.Long
+
+data class FieldInfo(
+    val index: Int,
+    val fieldAst: FieldDeclaration,
+    private val classInfo: ClassInfo
+) {
+
+    val classPrinter = classInfo as ClassPrinter
+
+    // AST
+    internal val variableAst = fieldAst.variables[0]
+    val typeAst = variableAst.type
+
+    // Field type
+    val Type = typeAst.asString()
+    val FieldClass = Type.takeWhile { it != '<' }
+    val isPrimitive = Type in PRIMITIVE_TYPES
+
+    // Javadoc
+    val javadoc: Javadoc? = fieldAst.javadoc.orElse(null)
+    private val javadocText = javadoc?.toText()?.let {
+        // Workaround for a bug in Javaparser for javadocs starting with {
+        if (it.hasUnbalancedCurlyBrace()) "{$it" else it
+    }
+    val javadocTextNoAnnotationLines = javadocText
+            ?.lines()
+            ?.dropLastWhile { it.startsWith("@") || it.isBlank() }
+            ?.let { if (it.isEmpty()) null else it }
+    val javadocFull = javadocText
+            ?.trimBlankLines()
+            ?.mapLines { " * $this" }
+            ?.let { "/**\n$it\n */" }
+
+
+    // Field name
+    val name = variableAst.name.asString()!!
+    private val isNameHungarian = name[0] == 'm' && name[1].isUpperCase()
+    val NameUpperCamel = if (isNameHungarian) name.substring(1) else name.capitalize()
+    val nameLowerCamel = if (isNameHungarian) NameUpperCamel.decapitalize() else name
+    val _name = if (name != nameLowerCamel) nameLowerCamel else "_$nameLowerCamel"
+    val SingularNameOrNull by lazy {
+        classPrinter {
+            fieldAst.annotations
+                    .find { it.nameAsString == PluralOf }
+                    ?.let { it as? SingleMemberAnnotationExpr }
+                    ?.memberValue
+                    ?.let { it as? StringLiteralExpr }
+                    ?.value
+                    ?.toLowerCamel()
+                    ?.capitalize()
+        }
+    }
+    val SingularName by lazy { SingularNameOrNull ?: NameUpperCamel }
+
+
+    // Field value
+    val mayBeNull: Boolean
+        get() = when {
+            isPrimitive -> false
+            "@${classPrinter.NonNull}" in annotations -> false
+            "@${classPrinter.NonEmpty}" in annotations -> false
+            isNullable -> true
+            lazyInitializer != null -> true
+            else -> classPrinter { !FeatureFlag.IMPLICIT_NONNULL() }
+        }
+    val lazyInitializer
+        get() = classInfo.classAst.methods.find { method ->
+            method.nameAsString == "lazyInit$NameUpperCamel" && method.parameters.isEmpty()
+        }?.nameAsString
+    val internalGetter get() = if (lazyInitializer != null) "get$NameUpperCamel()" else name
+    val defaultExpr: Any?
+        get() {
+            variableAst.initializer.orElse(null)?.let { return it }
+            classInfo.classAst.methods.find {
+                it.nameAsString == "default$NameUpperCamel" && it.parameters.isEmpty()
+            }?.run { "$nameAsString()" }?.let { return it }
+            if (FieldClass == "List") return "${classPrinter.memberRef("java.util.Collections.emptyList")}()"
+            return null
+        }
+    val hasDefault get() = defaultExpr != null
+
+
+    // Generic args
+    val isArray = Type.endsWith("[]")
+    val isList = FieldClass == "List" || FieldClass == "ArrayList"
+    val fieldBit = "0x${Long.toHexString(1L shl index)}"
+    var isLast = false
+    val isFinal = fieldAst.isFinal
+    val fieldTypeGenegicArgs = when (typeAst) {
+        is ArrayType -> listOf(fieldAst.elementType.asString())
+        is ClassOrInterfaceType -> {
+            typeAst.typeArguments.orElse(null)?.map { it.asString() } ?: emptyList()
+        }
+        else -> emptyList()
+    }
+    val FieldInnerType = fieldTypeGenegicArgs.firstOrNull()
+    val FieldInnerClass = FieldInnerType?.takeWhile { it != '<' }
+
+
+    // Annotations
+    var intOrStringDef = null as ConstDef?
+    val annotations by lazy {
+        if (FieldClass in BUILTIN_SPECIAL_PARCELLINGS) {
+            classPrinter {
+                fieldAst.addAnnotation(SingleMemberAnnotationExpr(
+                        Name(ParcelWith),
+                        ClassExpr(JavaParser.parseClassOrInterfaceType(
+                                "$Parcelling.BuiltIn.For$FieldClass"))))
+            }
+        }
+        fieldAst.annotations.map { it.removeComment().toString() }
+    }
+    val annotationsNoInternal by lazy {
+        annotations.filterNot { ann ->
+            classPrinter {
+                internalAnnotations.any {
+                    it in ann
+                }
+            }
+        }
+    }
+
+    fun hasAnnotation(a: String) = annotations.any { it.startsWith(a) }
+    val isNullable by lazy { hasAnnotation("@Nullable") }
+    val isNonEmpty by lazy { hasAnnotation("@${classPrinter.NonEmpty}") }
+    val customParcellingClass by lazy {
+        fieldAst.annotations.find { it.nameAsString == classPrinter.ParcelWith }
+                ?.singleArgAs<ClassExpr>()
+                ?.type
+                ?.asString()
+    }
+    val annotationsAndType by lazy { (annotationsNoInternal + Type).joinToString(" ") }
+    val sParcelling by lazy { customParcellingClass?.let { "sParcellingFor$NameUpperCamel" } }
+    val annotatedTypeForSetterParam by lazy {
+        (annotationsNoInternal + if (isArray) "$FieldInnerType..." else Type).joinToString(" ")
+    }
+
+    // Utilities
+
+    /**
+     * `mFoo.size()`
+     */
+    val ClassPrinter.sizeExpr get() = when {
+        isArray && FieldInnerClass !in PRIMITIVE_TYPES ->
+            memberRef("com.android.internal.util.ArrayUtils.size") + "($name)"
+        isArray -> "$name.length"
+        listOf("List", "Set", "Map").any { FieldClass.endsWith(it) } ->
+            memberRef("com.android.internal.util.CollectionUtils.size") + "($name)"
+        Type == "String" -> memberRef("android.text.TextUtils.length") + "($name)"
+        Type == "CharSequence" -> "$name.length()"
+        else -> "$name.size()"
+    }
+    /**
+     * `mFoo.get(0)`
+     */
+    fun elemAtIndexExpr(indexExpr: String) = when {
+        isArray -> "$name[$indexExpr]"
+        FieldClass == "ArraySet" -> "$name.valueAt($indexExpr)"
+        else -> "$name.get($indexExpr)"
+    }
+    /**
+     * `mFoo.isEmpty()`
+     */
+    val ClassPrinter.isEmptyExpr get() = when {
+        isArray || Type == "CharSequence" -> "$sizeExpr == 0"
+        else -> "$name.isEmpty()"
+    }
+
+    /**
+     * `mFoo == that` or `Objects.equals(mFoo, that)`, etc.
+     */
+    fun ClassPrinter.isEqualToExpr(that: String) = when {
+        Type in PRIMITIVE_TYPES -> "$internalGetter == $that"
+        isArray -> "${memberRef("java.util.Arrays.equals")}($internalGetter, $that)"
+        else -> "${memberRef("java.util.Objects.equals")}($internalGetter, $that)"
+    }
+
+    /**
+     * Parcel.write* and Parcel.read* method name wildcard values
+     */
+    val ParcelMethodsSuffix = when {
+        FieldClass in PRIMITIVE_TYPES - "char" - "boolean" +
+                listOf("String", "CharSequence", "Exception", "Size", "SizeF", "Bundle",
+                        "FileDescriptor", "SparseBooleanArray", "SparseIntArray", "SparseArray") ->
+            FieldClass
+        FieldClass == "Map" && fieldTypeGenegicArgs[0] == "String" -> "Map"
+        isArray -> when {
+            FieldInnerType!! in (PRIMITIVE_TYPES + "String") -> FieldInnerType + "Array"
+            isBinder(FieldInnerType) -> "BinderArray"
+            else -> "TypedArray"
+        }
+        isList -> when {
+            FieldInnerType == "String" -> "StringList"
+            isBinder(FieldInnerType!!) -> "BinderList"
+            else -> "ParcelableList"
+        }
+        isIInterface(Type) -> "StrongInterface"
+        isBinder(Type) -> "StrongBinder"
+        else -> "TypedObject"
+    }.capitalize()
+
+    private fun isBinder(type: String) = type == "Binder" || type == "IBinder" || isIInterface(type)
+    private fun isIInterface(type: String) = type.length >= 2 && type[0] == 'I' && type[1].isUpperCase()
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
new file mode 100644
index 0000000..ab64f4e
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -0,0 +1,847 @@
+package com.android.codegen
+
+import com.github.javaparser.ast.body.FieldDeclaration
+import com.github.javaparser.ast.body.VariableDeclarator
+import com.github.javaparser.ast.expr.*
+import java.io.File
+
+
+/**
+ * IntDefs and StringDefs based on constants
+ */
+fun ClassPrinter.generateConstDefs() {
+    val consts = classAst.fields.filter {
+        it.isStatic && it.isFinal && it.variables.all { variable ->
+            val initializer = variable.initializer.orElse(null)
+            val isLiteral = initializer is LiteralExpr
+                    || (initializer is UnaryExpr && initializer.expression is LiteralExpr)
+            isLiteral && variable.type.asString() in listOf("int", "String")
+        }
+    }.flatMap { field -> field.variables.map { it to field } }
+    val intConsts = consts.filter { it.first.type.asString() == "int" }
+    val strConsts = consts.filter { it.first.type.asString() == "String" }
+    val intGroups = intConsts.groupBy { it.first.nameAsString.split("_")[0] }.values
+    val strGroups = strConsts.groupBy { it.first.nameAsString.split("_")[0] }.values
+    intGroups.forEach {
+        generateConstDef(it)
+    }
+    strGroups.forEach {
+        generateConstDef(it)
+    }
+}
+
+fun ClassPrinter.generateConstDef(consts: List<Pair<VariableDeclarator, FieldDeclaration>>) {
+    if (consts.size <= 1) return
+
+    val names = consts.map { it.first.nameAsString!! }
+    val prefix = names
+            .reduce { a, b -> a.commonPrefixWith(b) }
+            .dropLastWhile { it != '_' }
+            .dropLast(1)
+    if (prefix.isEmpty()) {
+        println("Failed to generate const def for $names")
+        return
+    }
+    var AnnotationName = prefix.split("_")
+            .filterNot { it.isBlank() }
+            .map { it.toLowerCase().capitalize() }
+            .joinToString("")
+    val annotatedConst = consts.find { it.second.annotations.isNonEmpty }
+    if (annotatedConst != null) {
+        AnnotationName = annotatedConst.second.annotations.first().nameAsString
+    }
+    val type = consts[0].first.type.asString()
+    val flag = type == "int" && consts.all { it.first.initializer.get().toString().startsWith("0x") }
+    val constDef = ConstDef(type = when {
+        type == "String" -> ConstDef.Type.STRING
+        flag -> ConstDef.Type.INT_FLAGS
+        else -> ConstDef.Type.INT
+    },
+            AnnotationName = AnnotationName,
+            values = consts.map { it.second }
+    )
+    constDefs += constDef
+    fields.forEachApply {
+        if (fieldAst.annotations.any { it.nameAsString == AnnotationName }) {
+            this.intOrStringDef = constDef
+        }
+    }
+
+    val visibility = if (consts[0].second.isPublic) "public" else "/* package-*/"
+
+    val Retention = classRef("java.lang.annotation.Retention")
+    val RetentionPolicySource = memberRef("java.lang.annotation.RetentionPolicy.SOURCE")
+    val ConstDef = classRef("android.annotation.${type.capitalize()}Def")
+
+    "@$ConstDef(${if_(flag, "flag = true, ")}prefix = \"${prefix}_\", value = {" {
+        names.forEachLastAware { name, isLast ->
+            +"$name${if_(!isLast, ",")}"
+        }
+    } + ")"
+    +"@$Retention($RetentionPolicySource)"
+    +GENERATED_MEMBER_HEADER
+    +"$visibility @interface $AnnotationName {}"
+    +""
+
+    if (type == "int") {
+        +GENERATED_MEMBER_HEADER
+        val methodDefLine = "$visibility static String ${AnnotationName.decapitalize()}ToString(" +
+                "@$AnnotationName int value)"
+        if (flag) {
+            val flg2str = memberRef("com.android.internal.util.BitUtils.flagsToString")
+            methodDefLine {
+                "return $flg2str(" {
+                    +"value, $ClassName::single${AnnotationName}ToString"
+                } + ";"
+            }
+            +GENERATED_MEMBER_HEADER
+            !"static String single${AnnotationName}ToString(@$AnnotationName int value)"
+        } else {
+            !methodDefLine
+        }
+        " {" {
+            "switch (value) {" {
+                names.forEach { name ->
+                    "case $name:" {
+                        +"return \"$name\";"
+                    }
+                }
+                +"default: return Integer.toHexString(value);"
+            }
+        }
+    }
+}
+
+fun ClassPrinter.generateAidl(javaFile: File) {
+    val aidl = File(javaFile.path.substringBeforeLast(".java") + ".aidl")
+    if (aidl.exists()) return
+    aidl.writeText(buildString {
+        sourceLines.dropLastWhile { !it.startsWith("package ") }.forEach {
+            appendln(it)
+        }
+        append("\nparcelable $ClassName;\n")
+    })
+}
+
+/**
+ * ```
+ * Foo newFoo = oldFoo.withBar(newBar);
+ * ```
+ */
+fun ClassPrinter.generateWithers() {
+    fields.forEachApply {
+        val metodName = "with$NameUpperCamel"
+        if (!hasMethod(metodName, Type)) {
+            generateFieldJavadoc(forceHide = FeatureFlag.WITHERS.hidden)
+            """@$NonNull
+                        $GENERATED_MEMBER_HEADER
+                        public $ClassType $metodName($annotatedTypeForSetterParam value)""" {
+                val changedFieldName = name
+
+                "return new $ClassType(" {
+                    fields.forEachTrimmingTrailingComma {
+                        if (name == changedFieldName) +"value," else +"$name,"
+                    }
+                } + ";"
+            }
+        }
+    }
+}
+
+fun ClassPrinter.generateCopyConstructor() {
+    if (classAst.constructors.any {
+                it.parameters.size == 1 &&
+                        it.parameters[0].type.asString() == ClassType
+            }) {
+        return
+    }
+
+    +"/** Copy constructor */"
+    +GENERATED_MEMBER_HEADER
+    "public $ClassName(@$NonNull $ClassName orig)" {
+        fields.forEachApply {
+            +"$name = orig.$name;"
+        }
+    }
+}
+
+/**
+ * ```
+ * Foo newFoo = oldFoo.buildUpon().setBar(newBar).build();
+ * ```
+ */
+fun ClassPrinter.generateBuildUpon() {
+    if (hasMethod("buildUpon")) return
+
+    +"/**"
+    +" * Provides an instance of {@link $BuilderClass} with state corresponding to this instance."
+    if (FeatureFlag.BUILD_UPON.hidden) {
+        +" * @hide"
+    }
+    +" */"
+    +GENERATED_MEMBER_HEADER
+    "public $BuilderType buildUpon()" {
+        "return new $BuilderType()" {
+            fields.forEachApply {
+                +".set$NameUpperCamel($internalGetter)"
+            } + ";"
+        }
+    }
+}
+
+fun ClassPrinter.generateBuilder() {
+    val setterVisibility = if (cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS))
+        "protected" else "public"
+    val constructorVisibility = if (BuilderClass == CANONICAL_BUILDER_CLASS)
+        "public" else "/* package-*/"
+
+    val OneTimeUseBuilder = classRef("android.provider.OneTimeUseBuilder")
+
+    +"/**"
+    +" * A builder for {@link $ClassName}"
+    if (FeatureFlag.BUILDER.hidden) +" * @hide"
+    +" */"
+    +"@SuppressWarnings(\"WeakerAccess\")"
+    +GENERATED_MEMBER_HEADER
+    "public static class $BuilderClass$genericArgs" {
+        +"extends $OneTimeUseBuilder<$ClassType>"
+    }
+    " {" {
+
+        +""
+        fields.forEachApply {
+            +"protected $annotationsAndType $name;"
+        }
+        +""
+        +"protected long mBuilderFieldsSet = 0L;"
+        +""
+        +"$constructorVisibility $BuilderClass() {};"
+        +""
+
+        generateBuilderSetters(setterVisibility)
+
+        generateBuilderBuild()
+
+        rmEmptyLine()
+    }
+}
+
+private fun ClassPrinter.generateBuilderSetters(visibility: String) {
+
+    fields.forEachApply {
+        val maybeCast =
+                if_(BuilderClass != CANONICAL_BUILDER_CLASS, " ($CANONICAL_BUILDER_CLASS)")
+
+        generateFieldJavadoc()
+        +GENERATED_MEMBER_HEADER
+        "$visibility $CANONICAL_BUILDER_CLASS set$NameUpperCamel($annotatedTypeForSetterParam value)" {
+            +"checkNotUsed();"
+            +"mBuilderFieldsSet |= $fieldBit;"
+            +"$name = value;"
+            +"return$maybeCast this;"
+        }
+
+
+        val javadocSeeSetter = "/** @see #set$NameUpperCamel */"
+        val singularNameCustomizationHint = if (SingularNameOrNull == null) {
+            "// You can refine this method's name by providing item's singular name, e.g.:\n" +
+                    "// @DataClass.PluralOf(\"item\")) mItems = ...\n\n"
+        } else ""
+
+        if (isList && FieldInnerType != null) {
+
+            +javadocSeeSetter
+            +GENERATED_MEMBER_HEADER
+            "$visibility $CANONICAL_BUILDER_CLASS add$SingularName(@$NonNull $FieldInnerType value)" {
+                !singularNameCustomizationHint
+                +"if ($name == null) set$NameUpperCamel(new $ArrayList<>());"
+                +"$name.add(value);"
+                +"return$maybeCast this;"
+            }
+        }
+
+        if (Type.contains("Map<")) {
+            val (Key, Value) = fieldTypeGenegicArgs
+
+            +javadocSeeSetter
+            +GENERATED_MEMBER_HEADER
+            "$visibility $CANONICAL_BUILDER_CLASS add$SingularName($Key key, $Value value)" {
+                !singularNameCustomizationHint
+                +"if ($name == null) set$NameUpperCamel(new $LinkedHashMap());"
+                +"$name.put(key, value);"
+                +"return$maybeCast this;"
+            }
+        }
+
+        if (Type == "boolean") {
+            +javadocSeeSetter
+            +GENERATED_MEMBER_HEADER
+            "$visibility $CANONICAL_BUILDER_CLASS mark$NameUpperCamel()" {
+                +"return set$NameUpperCamel(true);"
+            }
+
+            +javadocSeeSetter
+            +GENERATED_MEMBER_HEADER
+            "$visibility $CANONICAL_BUILDER_CLASS markNot$NameUpperCamel()" {
+                +"return set$NameUpperCamel(false);"
+            }
+        }
+    }
+}
+
+private fun ClassPrinter.generateBuilderBuild() {
+    +"/** Builds the instance. This builder should not be touched after calling this! */"
+    "public $ClassType build()" {
+        +"markUsed();"
+        fields.forEachApply {
+            if (!isNullable || hasDefault) {
+                "if ((mBuilderFieldsSet & $fieldBit) == 0)" {
+                    if (!isNullable && !hasDefault) {
+                        +"throw new IllegalStateException(\"Required field not set: $nameLowerCamel\");"
+                    } else {
+                        +"$name = $defaultExpr;"
+                    }
+                }
+            }
+        }
+        "$ClassType o = new $ClassType(" {
+            fields.forEachTrimmingTrailingComma {
+                +"$name,"
+            }
+        } + ";"
+        +"return o;"
+    }
+}
+
+fun ClassPrinter.generateParcelable() {
+    val booleanFields = fields.filter { it.Type == "boolean" }
+    val objectFields = fields.filter { it.Type !in PRIMITIVE_TYPES }
+    val nullableFields = objectFields.filter { it.mayBeNull }
+    val nonBooleanFields = fields - booleanFields
+
+
+    val flagStorageType = when (fields.size) {
+        in 0..7 -> "byte"
+        in 8..15 -> "int"
+        in 16..31 -> "long"
+        else -> throw NotImplementedError("32+ field classes not yet supported")
+    }
+    val FlagStorageType = flagStorageType.capitalize()
+
+    fields.forEachApply {
+        if (sParcelling != null) {
+            +GENERATED_MEMBER_HEADER
+            "static $Parcelling<$Type> $sParcelling =" {
+                "$Parcelling.Cache.get(" {
+                    +"$customParcellingClass.class"
+                } + ";"
+            }
+            "static {" {
+                "if ($sParcelling == null)" {
+                    "$sParcelling = $Parcelling.Cache.put(" {
+                        +"new $customParcellingClass()"
+                    } + ";"
+                }
+            }
+            +""
+        }
+    }
+
+    val Parcel = classRef("android.os.Parcel")
+    if (!hasMethod("writeToParcel", Parcel, "int")) {
+        +"@Override"
+        +GENERATED_MEMBER_HEADER
+        "public void writeToParcel($Parcel dest, int flags)" {
+            +"// You can override field parcelling by defining methods like:"
+            +"// void parcelFieldName(Parcel dest, int flags) { ... }"
+            +""
+
+            if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) {
+                +"$flagStorageType flg = 0;"
+                booleanFields.forEachApply {
+                    +"if ($internalGetter) flg |= $fieldBit;"
+                }
+                nullableFields.forEachApply {
+                    +"if ($internalGetter != null) flg |= $fieldBit;"
+                }
+                +"dest.write$FlagStorageType(flg);"
+            }
+
+            nonBooleanFields.forEachApply {
+                val customParcellingMethod = "parcel$NameUpperCamel"
+                when {
+                    hasMethod(customParcellingMethod, Parcel, "int") ->
+                        +"$customParcellingMethod(dest, flags);"
+                    customParcellingClass != null -> +"$sParcelling.parcel($name, dest, flags);"
+                    hasAnnotation("@$DataClassEnum") ->
+                        +"dest.writeInt($internalGetter == null ? -1 : $internalGetter.ordinal());"
+                    else -> {
+                        if (mayBeNull) !"if ($internalGetter != null) "
+                        var args = internalGetter
+                        if (ParcelMethodsSuffix.startsWith("Parcelable")
+                                || ParcelMethodsSuffix.startsWith("TypedObject")
+                                || ParcelMethodsSuffix == "TypedArray") {
+                            args += ", flags"
+                        }
+                        +"dest.write$ParcelMethodsSuffix($args);"
+                    }
+                }
+            }
+        }
+    }
+
+    if (!hasMethod("describeContents")) {
+        +"@Override"
+        +GENERATED_MEMBER_HEADER
+        +"public int describeContents() { return 0; }"
+        +""
+    }
+
+    if (classAst.fields.none { it.variables[0].nameAsString == "CREATOR" }) {
+        val Creator = classRef("android.os.Parcelable.Creator")
+
+        +GENERATED_MEMBER_HEADER
+        "public static final @$NonNull $Creator<$ClassName> CREATOR" {
+            +"= new $Creator<$ClassName>()"
+        }; " {" {
+
+            +"@Override"
+            "public $ClassName[] newArray(int size)" {
+                +"return new $ClassName[size];"
+            }
+
+            +"@Override"
+            +"@SuppressWarnings({\"unchecked\", \"RedundantCast\"})"
+            "public $ClassName createFromParcel($Parcel in)" {
+                +"// You can override field unparcelling by defining methods like:"
+                +"// static FieldType unparcelFieldName(Parcel in) { ... }"
+                +""
+                if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) {
+                    +"$flagStorageType flg = in.read$FlagStorageType();"
+                }
+                booleanFields.forEachApply {
+                    +"$Type $_name = (flg & $fieldBit) != 0;"
+                }
+                nonBooleanFields.forEachApply {
+
+                    // Handle customized parceling
+                    val customParcellingMethod = "unparcel$NameUpperCamel"
+                    if (hasMethod(customParcellingMethod, Parcel)) {
+                        +"$Type $_name = $customParcellingMethod(in);"
+                    } else if (customParcellingClass != null) {
+                        +"$Type $_name = $sParcelling.unparcel(in);"
+                    } else if (hasAnnotation("@$DataClassEnum")) {
+                        val ordinal = "${_name}Ordinal"
+                        +"int $ordinal = in.readInt();"
+                        +"$Type $_name = $ordinal < 0 ? null : $FieldClass.values()[$ordinal];"
+                    } else {
+                        val methodArgs = mutableListOf<String>()
+
+                        // Create container if any
+                        val containerInitExpr = when {
+                            FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()"
+                            FieldClass == "List" || FieldClass == "ArrayList" ->
+                                "new ${classRef("java.util.ArrayList")}<>()"
+//                            isArray && FieldInnerType in (PRIMITIVE_TYPES + "String") ->
+//                                "new $FieldInnerType[in.readInt()]"
+                            else -> ""
+                        }
+                        val passContainer = containerInitExpr.isNotEmpty()
+
+                        // nullcheck +
+                        // "FieldType fieldName = (FieldType)"
+                        if (passContainer) {
+                            methodArgs.add(_name)
+                            !"$Type $_name = "
+                            if (mayBeNull) {
+                                +"null;"
+                                !"if ((flg & $fieldBit) != 0) {"
+                                pushIndent()
+                                +""
+                                !"$_name = "
+                            }
+                            +"$containerInitExpr;"
+                        } else {
+                            !"$Type $_name = "
+                            if (mayBeNull) !"(flg & $fieldBit) == 0 ? null : "
+                            if (ParcelMethodsSuffix == "StrongInterface") {
+                                !"$FieldClass.Stub.asInterface("
+                            } else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" &&
+                                    (!isArray || FieldInnerType !in PRIMITIVE_TYPES + "String") &&
+                                    ParcelMethodsSuffix != "Parcelable") {
+                                !"($Type) "
+                            }
+                        }
+
+                        // Determine method args
+                        when {
+                            ParcelMethodsSuffix == "Parcelable" ->
+                                methodArgs += "$FieldClass.class.getClassLoader()"
+                            ParcelMethodsSuffix == "TypedObject" ->
+                                methodArgs += "$FieldClass.CREATOR"
+                            ParcelMethodsSuffix == "TypedArray" ->
+                                methodArgs += "$FieldInnerClass.CREATOR"
+                            ParcelMethodsSuffix.startsWith("Parcelable")
+                                    || FieldClass == "Map"
+                                    || (isList || isArray)
+                                    && FieldInnerType !in PRIMITIVE_TYPES + "String" ->
+                                methodArgs += "$FieldInnerClass.class.getClassLoader()"
+                        }
+
+                        // ...in.readFieldType(args...);
+                        when {
+                            ParcelMethodsSuffix == "StrongInterface" -> !"in.readStrongBinder"
+                            isArray -> !"in.create$ParcelMethodsSuffix"
+                            else -> !"in.read$ParcelMethodsSuffix"
+                        }
+                        !"(${methodArgs.joinToString(", ")})"
+                        if (ParcelMethodsSuffix == "StrongInterface") !")"
+                        +";"
+
+                        // Cleanup if passContainer
+                        if (passContainer && mayBeNull) {
+                            popIndent()
+                            rmEmptyLine()
+                            +"\n}"
+                        }
+                    }
+                }
+                "return new $ClassType(" {
+                    fields.forEachTrimmingTrailingComma {
+                        +"$_name,"
+                    }
+                } + ";"
+            }
+            rmEmptyLine()
+        } + ";"
+        +""
+    }
+}
+
+fun ClassPrinter.generateEqualsHashcode() {
+    if (!hasMethod("equals", "Object")) {
+        +"@Override"
+        +GENERATED_MEMBER_HEADER
+        "public boolean equals(Object o)" {
+            +"// You can override field equality logic by defining either of the methods like:"
+            +"// boolean fieldNameEquals($ClassName other) { ... }"
+            +"// boolean fieldNameEquals(FieldType otherValue) { ... }"
+            +""
+            """if (this == o) return true;
+                        if (o == null || getClass() != o.getClass()) return false;
+                        @SuppressWarnings("unchecked")
+                        $ClassType that = ($ClassType) o;
+                        //noinspection PointlessBooleanExpression
+                        return true""" {
+                fields.forEachApply {
+                    val sfx = if (isLast) ";" else ""
+                    val customEquals = "${nameLowerCamel}Equals"
+                    when {
+                        hasMethod(customEquals, Type) -> +"&& $customEquals(that.$internalGetter)$sfx"
+                        hasMethod(customEquals, ClassType) -> +"&& $customEquals(that)$sfx"
+                        else -> +"&& ${isEqualToExpr("that.$internalGetter")}$sfx"
+                    }
+                }
+            }
+        }
+    }
+
+    if (!hasMethod("hashCode")) {
+        +"@Override"
+        +GENERATED_MEMBER_HEADER
+        "public int hashCode()" {
+            +"// You can override field hashCode logic by defining methods like:"
+            +"// int fieldNameHashCode() { ... }"
+            +""
+            +"int _hash = 1;"
+            fields.forEachApply {
+                !"_hash = 31 * _hash + "
+                val customHashCode = "${nameLowerCamel}HashCode"
+                when {
+                    hasMethod(customHashCode) -> +"$customHashCode();"
+                    Type == "int" || Type == "byte" -> +"$internalGetter;"
+                    Type in PRIMITIVE_TYPES -> +"${Type.capitalize()}.hashCode($internalGetter);"
+                    isArray -> +"${memberRef("java.util.Arrays.hashCode")}($internalGetter);"
+                    else -> +"${memberRef("java.util.Objects.hashCode")}($internalGetter);"
+                }
+            }
+            +"return _hash;"
+        }
+    }
+}
+
+//TODO support IntDef flags?
+fun ClassPrinter.generateToString() {
+    if (!hasMethod("toString")) {
+        +"@Override"
+        +GENERATED_MEMBER_HEADER
+        "public String toString()" {
+            +"// You can override field toString logic by defining methods like:"
+            +"// String fieldNameToString() { ... }"
+            +""
+            "return \"$ClassName { \" +" {
+                fields.forEachApply {
+                    val customToString = "${nameLowerCamel}ToString"
+                    val expr = when {
+                        hasMethod(customToString) -> "$customToString()"
+                        isArray -> "${memberRef("java.util.Arrays.toString")}($internalGetter)"
+                        intOrStringDef?.type?.isInt == true ->
+                            "${intOrStringDef!!.AnnotationName.decapitalize()}ToString($name)"
+                        else -> internalGetter
+                    }
+                    +"\"$nameLowerCamel = \" + $expr${if_(!isLast, " + \", \"")} +"
+                }
+            }
+            +"\" }\";"
+        }
+    }
+}
+
+fun ClassPrinter.generateSetters() {
+    fields.forEachApply {
+        if (!hasMethod("set$NameUpperCamel", Type)
+                && !fieldAst.isPublic
+                && !isFinal) {
+
+            generateFieldJavadoc(forceHide = FeatureFlag.SETTERS.hidden)
+            +GENERATED_MEMBER_HEADER
+            "public $ClassType set$NameUpperCamel($annotatedTypeForSetterParam value)" {
+                generateSetFrom("value")
+                +"return this;"
+            }
+        }
+    }
+}
+
+fun ClassPrinter.generateGetters() {
+    (fields + lazyTransientFields).forEachApply {
+        val methodPrefix = if (Type == "boolean") "is" else "get"
+        val methodName = methodPrefix + NameUpperCamel
+
+        if (!hasMethod(methodName) && !fieldAst.isPublic) {
+
+            generateFieldJavadoc(forceHide = FeatureFlag.GETTERS.hidden)
+            +GENERATED_MEMBER_HEADER
+            "public $annotationsAndType $methodName()" {
+                if (lazyInitializer == null) {
+                    +"return $name;"
+                } else {
+                    +"$Type $_name = $name;"
+                    "if ($_name == null)" {
+                        if (fieldAst.isVolatile) {
+                            "synchronized(this)" {
+                                +"$_name = $name;"
+                                "if ($_name == null)" {
+                                    +"$_name = $name = $lazyInitializer();"
+                                }
+                            }
+                        } else {
+                            +"// You can mark field as volatile for thread-safe double-check init"
+                            +"$_name = $name = $lazyInitializer();"
+                        }
+                    }
+                    +"return $_name;"
+                }
+            }
+        }
+    }
+}
+
+fun FieldInfo.generateFieldJavadoc(forceHide: Boolean = false) = classPrinter {
+    if (javadocFull != null || forceHide) {
+        var hidden = false
+        (javadocFull ?: "/**\n */").lines().forEach {
+            if (it.contains("@hide")) hidden = true
+            if (it.contains("*/") && forceHide && !hidden) {
+                if (javadocFull != null) +" *"
+                +" * @hide"
+            }
+            +it
+        }
+    }
+}
+
+fun FieldInfo.generateSetFrom(source: String) = classPrinter {
+    !"$name = "
+    if (Type in PRIMITIVE_TYPES || mayBeNull) {
+        +"$source;"
+    } else if (defaultExpr != null) {
+        "$source != null" {
+            +"? $source"
+            +": $defaultExpr;"
+        }
+    } else {
+        val checkNotNull = memberRef("com.android.internal.util.Preconditions.checkNotNull")
+        +"$checkNotNull($source);"
+    }
+    if (isNonEmpty) {
+        "if ($isEmptyExpr)" {
+            +"throw new IllegalArgumentException(\"$nameLowerCamel cannot be empty\");"
+        }
+    }
+}
+
+fun ClassPrinter.generateConstructor(visibility: String = "public") {
+    if (visibility == "public") {
+        generateConstructorJavadoc()
+    }
+    +GENERATED_MEMBER_HEADER
+    "$visibility $ClassName(" {
+        fields.forEachApply {
+            +"$annotationsAndType $nameLowerCamel${if_(!isLast, ",")}"
+        }
+    }
+    " {" {
+        fields.forEachApply {
+            !"this."
+            generateSetFrom(nameLowerCamel)
+        }
+
+        generateStateValidation()
+
+        generateOnConstructedCallback()
+    }
+}
+
+private fun ClassPrinter.generateConstructorJavadoc() {
+    if (fields.all { it.javadoc == null } && !FeatureFlag.CONSTRUCTOR.hidden) return
+    +"/**"
+    fields.filter { it.javadoc != null }.forEachApply {
+        javadocTextNoAnnotationLines?.apply {
+            +" * @param $nameLowerCamel"
+            forEach {
+                +" *   $it"
+            }
+        }
+    }
+    if (FeatureFlag.CONSTRUCTOR.hidden) +" * @hide"
+    +" */"
+}
+
+private fun ClassPrinter.generateStateValidation() {
+    val Size = classRef("android.annotation.Size")
+    val knownNonValidationAnnotations = internalAnnotations + Nullable
+
+    val validate = memberRef("com.android.internal.util.AnnotationValidations.validate")
+    fun appendValidateCall(annotation: AnnotationExpr, valueToValidate: String) {
+        "$validate(" {
+            !"${annotation.nameAsString}.class, null, $valueToValidate"
+            val params = when (annotation) {
+                is MarkerAnnotationExpr -> emptyMap()
+                is SingleMemberAnnotationExpr -> mapOf("value" to annotation.memberValue)
+                is NormalAnnotationExpr ->
+                    annotation.pairs.map { it.name.asString() to it.value }.toMap()
+                else -> throw IllegalStateException()
+            }
+            params.forEach { name, value ->
+                !",\n\"$name\", $value"
+            }
+        }
+        +";"
+    }
+
+    fields.forEachApply {
+        if (intOrStringDef != null) {
+            if (intOrStringDef!!.type == ConstDef.Type.INT_FLAGS) {
+                +""
+                +"//noinspection PointlessBitwiseExpression"
+                "$Preconditions.checkFlagsArgument(" {
+                    "$name, 0" {
+                        intOrStringDef!!.CONST_NAMES.forEach {
+                            +"| $it"
+                        }
+                    }
+                }
+                +";"
+            } else {
+                +""
+                +"//noinspection PointlessBooleanExpression"
+                "if (true" {
+                    intOrStringDef!!.CONST_NAMES.forEach { CONST_NAME ->
+                        +"&& !(${isEqualToExpr(CONST_NAME)})"
+                    }
+                }; rmEmptyLine(); ") {" {
+                    "throw new ${classRef<IllegalArgumentException>()}(" {
+                        "\"$nameLowerCamel was \" + $internalGetter + \" but must be one of: \"" {
+
+                            intOrStringDef!!.CONST_NAMES.forEachLastAware { CONST_NAME, isLast ->
+                                +"""+ "$CONST_NAME(" + $CONST_NAME + ")${if_(!isLast, ", ")}""""
+                            }
+                        }
+                    }
+                    +";"
+                }
+            }
+        }
+
+        val eachLine = fieldAst.annotations.find { it.nameAsString == Each }?.range?.orElse(null)?.end?.line
+        val perElementValidations = if (eachLine == null) emptyList() else fieldAst.annotations.filter {
+            it.nameAsString != Each &&
+                it.range.orElse(null)?.begin?.line?.let { it >= eachLine } ?: false
+        }
+
+        fieldAst.annotations.filterNot {
+            it.nameAsString == intOrStringDef?.AnnotationName
+                    || it.nameAsString in knownNonValidationAnnotations
+                    || it in perElementValidations
+        }.forEach { annotation ->
+            appendValidateCall(annotation,
+                    valueToValidate = if (annotation.nameAsString == Size) sizeExpr else name)
+        }
+
+        if (perElementValidations.isNotEmpty()) {
+            +"int ${nameLowerCamel}Size = $sizeExpr;"
+            "for (int i = 0; i < ${nameLowerCamel}Size; i++) {" {
+                perElementValidations.forEach { annotation ->
+                    appendValidateCall(annotation,
+                            valueToValidate = elemAtIndexExpr("i"))
+                }
+            }
+        }
+    }
+}
+
+private fun ClassPrinter.generateOnConstructedCallback(prefix: String = "") {
+    +""
+    val call = "${prefix}onConstructed();"
+    if (hasMethod("onConstructed")) {
+        +call
+    } else {
+        +"// $call // You can define this method to get a callback"
+    }
+}
+
+fun ClassPrinter.generateForEachField() {
+    val specializations = listOf("Object", "int")
+    val usedSpecializations = fields.map { if (it.Type in specializations) it.Type else "Object" }
+    val usedSpecializationsSet = usedSpecializations.toSet()
+
+    val PerObjectFieldAction = classRef("com.android.internal.util.DataClass.PerObjectFieldAction")
+
+    +GENERATED_MEMBER_HEADER
+    "void forEachField(" {
+        usedSpecializationsSet.toList().forEachLastAware { specType, isLast ->
+            val SpecType = specType.capitalize()
+            val ActionClass = classRef("com.android.internal.util.DataClass.Per${SpecType}FieldAction")
+            +"$ActionClass<$ClassType> action$SpecType${if_(!isLast, ",")}"
+        }
+    }; " {" {
+        usedSpecializations.forEachIndexed { i, specType ->
+            val SpecType = specType.capitalize()
+            fields[i].apply {
+                +"action$SpecType.accept$SpecType(this, \"$nameLowerCamel\", $name);"
+            }
+        }
+    }
+
+    if (usedSpecializationsSet.size > 1) {
+        +"/** @deprecated May cause boxing allocations - use with caution! */"
+        +"@Deprecated"
+        +GENERATED_MEMBER_HEADER
+        "void forEachField($PerObjectFieldAction<$ClassType> action)" {
+            fields.forEachApply {
+                +"action.acceptObject(this, \"$nameLowerCamel\", $name);"
+            }
+        }
+    }
+}
diff --git a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
new file mode 100644
index 0000000..d1dc88f
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
@@ -0,0 +1,122 @@
+package com.android.codegen
+
+import com.github.javaparser.ast.body.TypeDeclaration
+import com.github.javaparser.ast.expr.*
+import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations
+import com.github.javaparser.ast.type.ClassOrInterfaceType
+import com.github.javaparser.ast.type.Type
+
+
+fun ClassPrinter.getInputSignatures(): List<String> {
+    return classAst.fields.map { fieldAst ->
+        buildString {
+            append(fieldAst.modifiers.joinToString(" ") {it.asString()})
+            append(" ")
+            append(annotationsToString(fieldAst))
+            append(" ")
+            append(getFullClassName(fieldAst.commonType))
+            append(" ")
+            append(fieldAst.variables.joinToString(", ") { it.nameAsString })
+        }
+    } + classAst.methods.map { methodAst ->
+        buildString {
+            append(methodAst.modifiers.joinToString(" ") {it.asString()})
+            append(" ")
+            append(annotationsToString(methodAst))
+            append(" ")
+            append(getFullClassName(methodAst.type))
+            append(" ")
+            append(methodAst.nameAsString)
+            append("(")
+            append(methodAst.parameters.joinToString(",") {getFullClassName(it.type)})
+            append(")")
+        }
+    }
+}
+
+private fun ClassPrinter.annotationsToString(annotatedAst: NodeWithAnnotations<*>): String {
+    return annotatedAst.annotations.joinToString(" ") {
+        annotationToString(it)
+    }
+}
+
+private fun ClassPrinter.annotationToString(ann: AnnotationExpr): String {
+    return buildString {
+        append("@")
+        append(getFullClassName(ann.nameAsString))
+        if (ann is MarkerAnnotationExpr) return@buildString
+
+        append("(")
+
+        when (ann) {
+            is SingleMemberAnnotationExpr -> {
+                appendExpr(this, ann.memberValue)
+            }
+            is NormalAnnotationExpr -> {
+                ann.pairs.forEachLastAware { pair, isLast ->
+                    append(pair.nameAsString)
+                    append("=")
+                    appendExpr(this, pair.value)
+                    if (!isLast) append(", ")
+                }
+            }
+        }
+
+        append(")")
+    }.replace("\"", "\\\"")
+}
+
+private fun ClassPrinter.appendExpr(sb: StringBuilder, ex: Expression?) {
+    when (ex) {
+        is ClassExpr -> sb.append(getFullClassName(ex.typeAsString)).append(".class")
+        is IntegerLiteralExpr -> sb.append(ex.asInt()).append("L")
+        is LongLiteralExpr -> sb.append(ex.asLong()).append("L")
+        is DoubleLiteralExpr -> sb.append(ex.asDouble())
+        else -> sb.append(ex)
+    }
+}
+
+private fun ClassPrinter.getFullClassName(type: Type): String {
+    return if (type is ClassOrInterfaceType) {
+        getFullClassName(buildString {
+            type.scope.ifPresent { append(it).append(".") }
+            type.isArrayType
+            append(type.nameAsString)
+        }) + (type.typeArguments.orElse(null)?.let { args -> args.joinToString(", ") {getFullClassName(it)}}?.let { "<$it>" } ?: "")
+    } else getFullClassName(type.asString())
+}
+
+private fun ClassPrinter.getFullClassName(className: String): String {
+    if (className.endsWith("[]")) return getFullClassName(className.removeSuffix("[]")) + "[]"
+
+    if (className.matches("\\.[a-z]".toRegex())) return className //qualified name
+
+    if ("." in className) return getFullClassName(className.substringBeforeLast(".")) + "." + className.substringAfterLast(".")
+
+    fileAst.imports.find { imp ->
+        imp.nameAsString.endsWith(".$className")
+    }?.nameAsString?.let { return it }
+
+    val thisPackagePrefix = fileAst.packageDeclaration.map { it.nameAsString + "." }.orElse("")
+    val thisClassPrefix = thisPackagePrefix + classAst.nameAsString + "."
+
+    classAst.childNodes.filterIsInstance<TypeDeclaration<*>>().find {
+        it.nameAsString == className
+    }?.let { return thisClassPrefix + it.nameAsString }
+
+    constDefs.find { it.AnnotationName == className }?.let { return thisClassPrefix + className }
+
+    if (tryOrNull { Class.forName("java.lang.$className") } != null) {
+        return "java.lang.$className"
+    }
+
+    if (className[0].isLowerCase()) return className //primitive
+
+    return thisPackagePrefix + className
+}
+
+private inline fun <T> tryOrNull(f: () -> T?) = try {
+    f()
+} catch (e: Exception) {
+    null
+}
diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt
new file mode 100755
index 0000000..8fafa7c
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/Main.kt
@@ -0,0 +1,199 @@
+package com.android.codegen
+
+import java.io.File
+
+
+const val THIS_SCRIPT_LOCATION = ""
+const val GENERATED_WARNING_PREFIX = "Code below generated by $CODEGEN_NAME"
+const val INDENT_SINGLE = "    "
+
+val PRIMITIVE_TYPES = listOf("byte", "short", "int", "long", "char", "float", "double", "boolean")
+
+const val CANONICAL_BUILDER_CLASS = "Builder"
+const val GENERATED_BUILDER_CLASS = "GeneratedBuilder"
+
+val BUILTIN_SPECIAL_PARCELLINGS = listOf("Pattern")
+
+const val FLAG_BUILDER_PROTECTED_SETTERS = "--builder-protected-setters"
+const val FLAG_NO_FULL_QUALIFIERS = "--no-full-qualifiers"
+
+
+/** @see [FeatureFlag] */
+val USAGE = """
+Usage: $CODEGEN_NAME [--[PREFIX-]FEATURE...] JAVAFILE
+
+Generates boilerplade parcelable/data class code at the bottom of JAVAFILE, based o fields' declaration in the given JAVAFILE's top-level class
+
+FEATURE represents some generatable code, and can be among:
+${FeatureFlag.values().map { feature ->
+    "  ${feature.kebabCase}" to feature.desc
+}.columnize(" - ")}
+
+And PREFIX can be:
+  <empty> - request to generate the feature
+    no    - suppress generation of the feature
+  hidden  - request to generate the feature with @hide
+
+Extra options:
+  --help        - view this help
+  --update-only - auto-detect flags from the previously auto-generated comment within the file
+  $FLAG_NO_FULL_QUALIFIERS
+                - when referring to classes don't use package name prefix; handy with IDE auto-import
+  $FLAG_BUILDER_PROTECTED_SETTERS
+                - make builder's setters protected to expose them as public in a subclass on a whitelist basis
+
+
+Special field modifiers and annotations:
+  transient                 - ignore the field completely
+  @Nullable                 - support null value when parcelling, and never throw on null input
+  @NonNull                  - throw on null input and don't parcel the nullness bit for the field
+  @DataClass.Enum           - parcel field as an enum value by ordinal
+  @DataClass.PluralOf(..)   - provide a singular version of a collection field name to be used in the builder's 'addFoo(..)'
+  @DataClass.ParcelWith(..) - provide a custom Parcelling class, specifying the custom (un)parcelling logic for this field
+  = <initializer>;          - provide default value and never throw if this field was not provided e.g. when using builder
+  /** ... */                - copy given javadoc on field's getters/setters/constructor params/builder setters etc.
+  @hide (in javadoc)        - force field's getters/setters/withers/builder setters to be @hide-den if generated
+
+
+Special methods/etc. you can define:
+
+  <any auto-generatable method>
+      For any method to be generated, if a method with same name and argument types is already
+      defined, than that method will not be generated.
+      This allows you to override certain details on granular basis.
+
+  void onConstructed()
+      Will be called in constructor, after all the fields have been initialized.
+      This is a good place to put any custom validation logic that you may have
+
+  static class $CANONICAL_BUILDER_CLASS extends $GENERATED_BUILDER_CLASS
+      If a class extending $GENERATED_BUILDER_CLASS is specified, generated builder's setters will
+      return the provided $CANONICAL_BUILDER_CLASS type.
+      $GENERATED_BUILDER_CLASS's constructor(s) will be package-private to encourage using $CANONICAL_BUILDER_CLASS instead
+      This allows you to extend the generated builder, adding or overriding any methods you may want
+
+
+In addition, for any field mMyField(or myField) of type FieldType you can define the following methods:
+
+  void parcelMyField(Parcel dest, int flags)
+      Allows you to provide custom logic for storing mMyField into a Parcel
+
+  static FieldType unparcelMyField(Parcel in)
+      Allows you to provide custom logic to deserialize the value of mMyField from a Parcel
+
+  String myFieldToString()
+      Allows you to provide a custom toString representation of mMyField's value
+
+  FieldType lazyInitMyField()
+      Requests a lazy initialization in getMyField(), with the provided method being the constructor
+      You may additionally mark the fields as volatile to cause this to generate a thread-safe
+      double-check locking lazy initialization
+
+  FieldType defaultMyField()
+      Allows you to provide a default value to initialize the field to, in case an explicit one
+      was not provided.
+      This is an alternative to providing a field initializer that, unlike the initializer,
+      you can use with final fields.
+
+Version: $CODEGEN_VERSION
+Questions? Feedback? Contact: eugenesusla@
+"""
+
+fun main(args: Array<String>) {
+    if (args.contains("--help")) {
+        println(USAGE)
+        System.exit(0)
+    }
+    if (args.contains("--version")) {
+        println(CODEGEN_VERSION)
+        System.exit(0)
+    }
+    val file = File(args.last())
+    val sourceLinesNoClosingBrace = file.readLines().dropLastWhile {
+        it.startsWith("}") || it.all(Char::isWhitespace)
+    }
+    val cliArgs = handleUpdateFlag(args, sourceLinesNoClosingBrace)
+    val sourceLinesAsIs = discardGeneratedCode(sourceLinesNoClosingBrace)
+    val sourceLines = sourceLinesAsIs
+            .filterNot { it.trim().startsWith("//") }
+            .map { it.trimEnd().dropWhile { it == '\n' } }
+
+    val stringBuilder = StringBuilder(sourceLinesAsIs.joinToString("\n"))
+    ClassPrinter(sourceLines, stringBuilder, cliArgs).run {
+
+        val cliExecutable = "$THIS_SCRIPT_LOCATION$CODEGEN_NAME"
+        val fileEscaped = file.absolutePath.replace(
+                System.getenv("ANDROID_BUILD_TOP"), "\$ANDROID_BUILD_TOP")
+
+
+        +"""
+
+
+
+        // $GENERATED_WARNING_PREFIX v$CODEGEN_VERSION.
+        //   on ${currentTimestamp()}
+        //
+        // DO NOT MODIFY!
+        //
+        // To regenerate run:
+        // $ $cliExecutable ${cliArgs.dropLast(1).joinToString("") { "$it " }}$fileEscaped
+        //
+        // CHECKSTYLE:OFF Generated code
+        """
+
+        if (FeatureFlag.CONST_DEFS()) generateConstDefs()
+
+        "@$DataClassGenerated(" {
+            +"time = ${System.currentTimeMillis()}L,"
+            +"codegenVersion = \"$CODEGEN_VERSION\","
+            +"sourceFile = \"${file.relativeTo(File(System.getenv("ANDROID_BUILD_TOP")))}\","
+            +"inputSignatures = \"${getInputSignatures().joinToString("\\n")}\""
+        }
+        +"\n"
+
+
+        if (FeatureFlag.CONSTRUCTOR()) {
+            generateConstructor("public")
+        } else if (FeatureFlag.BUILDER()
+                || FeatureFlag.COPY_CONSTRUCTOR()
+                || FeatureFlag.WITHERS()
+                || FeatureFlag.PARCELABLE()) {
+            generateConstructor("/* package-private */")
+        }
+
+        if (FeatureFlag.GETTERS()) generateGetters()
+        if (FeatureFlag.SETTERS()) generateSetters()
+        if (FeatureFlag.TO_STRING()) generateToString()
+        if (FeatureFlag.EQUALS_HASH_CODE()) generateEqualsHashcode()
+
+        if (FeatureFlag.FOR_EACH_FIELD()) generateForEachField()
+
+        if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor()
+        if (FeatureFlag.WITHERS()) generateWithers()
+
+        if (FeatureFlag.PARCELABLE()) generateParcelable()
+
+        if (FeatureFlag.BUILDER() && FeatureFlag.BUILD_UPON()) generateBuildUpon()
+        if (FeatureFlag.BUILDER()) generateBuilder()
+
+        if (FeatureFlag.AIDL()) generateAidl(file)
+
+        rmEmptyLine()
+    }
+    stringBuilder.append("\n}\n")
+    file.writeText(stringBuilder.toString().mapLines { trimEnd() })
+}
+
+internal fun discardGeneratedCode(sourceLinesNoClosingBrace: List<String>): List<String> {
+    return sourceLinesNoClosingBrace
+            .takeWhile { GENERATED_WARNING_PREFIX !in it }
+            .dropLastWhile(String::isBlank)
+}
+
+private fun handleUpdateFlag(cliArgs: Array<String>, sourceLines: List<String>): Array<String> {
+    if ("--update-only" in cliArgs
+            && sourceLines.none { GENERATED_WARNING_PREFIX in it || it.startsWith("@DataClass") }) {
+        System.exit(0)
+    }
+    return cliArgs - "--update-only"
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
new file mode 100644
index 0000000..41641f6
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -0,0 +1,4 @@
+package com.android.codegen
+
+const val CODEGEN_NAME = "codegen"
+const val CODEGEN_VERSION = "0.0.1"
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
new file mode 100644
index 0000000..95c9909
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -0,0 +1,76 @@
+package com.android.codegen
+
+import com.github.javaparser.ast.expr.AnnotationExpr
+import com.github.javaparser.ast.expr.Expression
+import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr
+import java.time.Instant
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+import java.time.format.FormatStyle
+
+/**
+ * [Iterable.forEach] + [Any.apply]
+ */
+inline fun <T> Iterable<T>.forEachApply(block: T.() -> Unit) = forEach(block)
+
+inline fun String.mapLines(f: String.() -> String?) = lines().mapNotNull(f).joinToString("\n")
+inline fun <T> Iterable<T>.trim(f: T.() -> Boolean) = dropWhile(f).dropLastWhile(f)
+fun String.trimBlankLines() = lines().trim { isBlank() }.joinToString("\n")
+
+fun Char.isNewline() = this == '\n' || this == '\r'
+fun Char.isWhitespaceNonNewline() = isWhitespace() && !isNewline()
+
+fun if_(cond: Boolean, then: String) = if (cond) then else ""
+
+inline infix fun Int.times(action: () -> Unit) {
+    for (i in 1..this) action()
+}
+
+/**
+ * a bbb
+ * cccc dd
+ *
+ * ->
+ *
+ * a    bbb
+ * cccc dd
+ */
+fun Iterable<Pair<String, String>>.columnize(separator: String = " | "): String {
+    val col1w = map { (a, _) -> a.length }.max()!!
+    val col2w = map { (_, b) -> b.length }.max()!!
+    return map { it.first.padEnd(col1w) + separator + it.second.padEnd(col2w) }.joinToString("\n")
+}
+
+fun String.hasUnbalancedCurlyBrace(): Boolean {
+    var braces = 0
+    forEach {
+        if (it == '{') braces++
+        if (it == '}') braces--
+        if (braces < 0) return true
+    }
+    return false
+}
+
+fun String.toLowerCamel(): String {
+    if (length >= 2 && this[0] == 'm' && this[1].isUpperCase()) return substring(1).capitalize()
+    if (all { it.isLetterOrDigit() }) return decapitalize()
+    return split("[^a-zA-Z0-9]".toRegex())
+            .map { it.toLowerCase().capitalize() }
+            .joinToString("")
+            .decapitalize()
+}
+
+inline fun <T> List<T>.forEachLastAware(f: (T, Boolean) -> Unit) {
+    forEachIndexed { index, t -> f(t, index == size - 1) }
+}
+
+@Suppress("UNCHECKED_CAST")
+fun <T : Expression> AnnotationExpr.singleArgAs()
+        = ((this as SingleMemberAnnotationExpr).memberValue as T)
+
+inline operator fun <reified T> Array<T>.minus(item: T) = toList().minus(item).toTypedArray()
+
+fun currentTimestamp() = DateTimeFormatter
+        .ofLocalizedDateTime(/* date */ FormatStyle.MEDIUM, /* time */ FormatStyle.LONG)
+        .withZone(ZoneId.systemDefault())
+        .format(Instant.now())
\ No newline at end of file
diff --git a/tools/lock_agent/Android.bp b/tools/lock_agent/Android.bp
index 408946b..79dce4a 100644
--- a/tools/lock_agent/Android.bp
+++ b/tools/lock_agent/Android.bp
@@ -12,13 +12,9 @@
     ],
     sdk_version: "current",
     stl: "c++_static",
-    include_dirs: [
-        // NDK headers aren't available in platform NDK builds.
-        "libnativehelper/include_jni",
-        // Use ScopedUtfChars.
-        "libnativehelper/header_only_include",
-    ],
     header_libs: [
+        // Use ScopedUtfChars.
+        "libnativehelper_header_only",
         "libopenjdkjvmti_headers",
     ],
     compile_multilib: "both",
@@ -32,13 +28,9 @@
         "libz",
         "slicer",
     ],
-    include_dirs: [
-        // NDK headers aren't available in platform NDK builds.
-        "libnativehelper/include_jni",
-        // Use ScopedUtfChars.
-        "libnativehelper/header_only_include",
-    ],
     header_libs: [
+        // Use ScopedUtfChars.
+        "libnativehelper_header_only",
         "libopenjdkjvmti_headers",
     ],
 }
diff --git a/tools/preload2/Android.mk b/tools/preload2/Android.mk
deleted file mode 100644
index d3ee1d3..0000000
--- a/tools/preload2/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-
-# To connect to devices (and take hprof dumps).
-LOCAL_STATIC_JAVA_LIBRARIES := ddmlib-prebuilt tools-common-prebuilt
-
-# To process hprof dumps.
-LOCAL_STATIC_JAVA_LIBRARIES += perflib-prebuilt trove-prebuilt guavalib
-
-# For JDWP access we use the framework in the JDWP tests from Apache Harmony, for
-# convenience (and to not depend on internal JDK APIs).
-LOCAL_STATIC_JAVA_LIBRARIES += apache-harmony-jdwp-tests-host junit-host
-
-LOCAL_MODULE:= preload2
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-# Copy to build artifacts
-$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE):$(LOCAL_MODULE).jar)
-
-# Copy the preload-tool shell script to the host's bin directory.
-include $(CLEAR_VARS)
-LOCAL_IS_HOST_MODULE := true
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE := preload-tool
-LOCAL_SRC_FILES := preload-tool
-LOCAL_REQUIRED_MODULES := preload2
-include $(BUILD_PREBUILT)
diff --git a/tools/preload2/preload-tool b/tools/preload2/preload-tool
deleted file mode 100644
index 322b62f..0000000
--- a/tools/preload2/preload-tool
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This script is used on the host only. It uses a common subset
-# shell dialect that should work well. It is partially derived
-# from art/tools/art.
-
-function follow_links() {
-  if [ z"$BASH_SOURCE" != z ]; then
-    file="$BASH_SOURCE"
-  else
-    file="$0"
-  fi
-  while [ -h "$file" ]; do
-    # On Mac OS, readlink -f doesn't work.
-    file="$(readlink "$file")"
-  done
-  echo "$file"
-}
-
-
-PROG_NAME="$(follow_links)"
-PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-ANDROID_ROOT=$PROG_DIR/..
-
-java -cp $ANDROID_ROOT/framework/preload2.jar com.android.preload.Main $@
diff --git a/tools/preload2/src/com/android/preload/ClientUtils.java b/tools/preload2/src/com/android/preload/ClientUtils.java
deleted file mode 100644
index 71ef025..0000000
--- a/tools/preload2/src/com/android/preload/ClientUtils.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload;
-
-import com.android.ddmlib.AndroidDebugBridge;
-import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-
-/**
- * Helper class for common communication with a Client (the ddms name for a running application).
- *
- * Instances take a default timeout parameter that's applied to all functions without explicit
- * timeout. Timeouts are in milliseconds.
- */
-public class ClientUtils {
-
-    private int defaultTimeout;
-
-    public ClientUtils() {
-        this(10000);
-    }
-
-    public ClientUtils(int defaultTimeout) {
-        this.defaultTimeout = defaultTimeout;
-    }
-
-    /**
-     * Shortcut for findClient with default timeout.
-     */
-    public Client findClient(IDevice device, String processName, int processPid) {
-        return findClient(device, processName, processPid, defaultTimeout);
-    }
-
-    /**
-     * Find the client with the given process name or process id. The name takes precedence over
-     * the process id (if valid). Stop looking after the given timeout.
-     *
-     * @param device The device to communicate with.
-     * @param processName The name of the process. May be null.
-     * @param processPid The pid of the process. Values less than or equal to zero are ignored.
-     * @param timeout The amount of milliseconds to wait, at most.
-     * @return The client, if found. Otherwise null.
-     */
-    public Client findClient(IDevice device, String processName, int processPid, int timeout) {
-        WaitForClient wfc = new WaitForClient(device, processName, processPid, timeout);
-        return wfc.get();
-    }
-
-    /**
-     * Shortcut for findAllClients with default timeout.
-     */
-    public Client[] findAllClients(IDevice device) {
-        return findAllClients(device, defaultTimeout);
-    }
-
-    /**
-     * Retrieve all clients known to the given device. Wait at most the given timeout.
-     *
-     * @param device The device to investigate.
-     * @param timeout The amount of milliseconds to wait, at most.
-     * @return An array of clients running on the given device. May be null depending on the
-     *         device implementation.
-     */
-    public Client[] findAllClients(IDevice device, int timeout) {
-        if (device.hasClients()) {
-            return device.getClients();
-        }
-        WaitForClients wfc = new WaitForClients(device, timeout);
-        return wfc.get();
-    }
-
-    private static class WaitForClient implements IClientChangeListener {
-
-        private IDevice device;
-        private String processName;
-        private int processPid;
-        private long timeout;
-        private Client result;
-
-        public WaitForClient(IDevice device, String processName, int processPid, long timeout) {
-            this.device = device;
-            this.processName = processName;
-            this.processPid = processPid;
-            this.timeout = timeout;
-            this.result = null;
-        }
-
-        public Client get() {
-            synchronized (this) {
-                AndroidDebugBridge.addClientChangeListener(this);
-
-                // Maybe it's already there.
-                if (result == null) {
-                    result = searchForClient(device);
-                }
-
-                if (result == null) {
-                    try {
-                        wait(timeout);
-                    } catch (InterruptedException e) {
-                        // Note: doesn't guard for spurious wakeup.
-                    }
-                }
-            }
-
-            AndroidDebugBridge.removeClientChangeListener(this);
-            return result;
-        }
-
-        private Client searchForClient(IDevice device) {
-            if (processName != null) {
-                Client tmp = device.getClient(processName);
-                if (tmp != null) {
-                    return tmp;
-                }
-            }
-            if (processPid > 0) {
-                String name = device.getClientName(processPid);
-                if (name != null && !name.isEmpty()) {
-                    Client tmp = device.getClient(name);
-                    if (tmp != null) {
-                        return tmp;
-                    }
-                }
-            }
-            if (processPid > 0) {
-                // Try manual search.
-                for (Client cl : device.getClients()) {
-                    if (cl.getClientData().getPid() == processPid
-                            && cl.getClientData().getClientDescription() != null) {
-                        return cl;
-                    }
-                }
-            }
-            return null;
-        }
-
-        private boolean isTargetClient(Client c) {
-            if (processPid > 0 && c.getClientData().getPid() == processPid) {
-                return true;
-            }
-            if (processName != null
-                    && processName.equals(c.getClientData().getClientDescription())) {
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public void clientChanged(Client arg0, int arg1) {
-            synchronized (this) {
-                if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) {
-                    if (isTargetClient(arg0)) {
-                        result = arg0;
-                        notifyAll();
-                    }
-                }
-            }
-        }
-    }
-
-    private static class WaitForClients implements IClientChangeListener {
-
-        private IDevice device;
-        private long timeout;
-
-        public WaitForClients(IDevice device, long timeout) {
-            this.device = device;
-            this.timeout = timeout;
-        }
-
-        public Client[] get() {
-            synchronized (this) {
-                AndroidDebugBridge.addClientChangeListener(this);
-
-                if (device.hasClients()) {
-                    return device.getClients();
-                }
-
-                try {
-                    wait(timeout); // Note: doesn't guard for spurious wakeup.
-                } catch (InterruptedException exc) {
-                }
-
-                // We will be woken up when the first client data arrives. Sleep a little longer
-                // to give (hopefully all of) the rest of the clients a chance to become available.
-                // Note: a loop with timeout is brittle as well and complicated, just accept this
-                //       for now.
-                try {
-                    Thread.sleep(500);
-                } catch (InterruptedException exc) {
-                }
-            }
-
-            AndroidDebugBridge.removeClientChangeListener(this);
-
-            return device.getClients();
-        }
-
-        @Override
-        public void clientChanged(Client arg0, int arg1) {
-            synchronized (this) {
-                if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) {
-                    notifyAll();
-                }
-            }
-        }
-    }
-}
diff --git a/tools/preload2/src/com/android/preload/DeviceUtils.java b/tools/preload2/src/com/android/preload/DeviceUtils.java
deleted file mode 100644
index 18cab7b..0000000
--- a/tools/preload2/src/com/android/preload/DeviceUtils.java
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload;
-
-import com.android.ddmlib.AdbCommandRejectedException;
-import com.android.ddmlib.AndroidDebugBridge;
-import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
-import com.android.preload.classdataretrieval.hprof.Hprof;
-import com.android.ddmlib.DdmPreferences;
-import com.android.ddmlib.IDevice;
-import com.android.ddmlib.IShellOutputReceiver;
-import com.android.ddmlib.SyncException;
-import com.android.ddmlib.TimeoutException;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Date;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Helper class for some device routines.
- */
-public class DeviceUtils {
-
-  // Locations
-  private static final String PRELOADED_CLASSES_FILE = "/etc/preloaded-classes";
-  // Shell commands
-  private static final String CREATE_EMPTY_PRELOADED_CMD = "touch " + PRELOADED_CLASSES_FILE;
-  private static final String DELETE_CACHE_CMD = "rm /data/dalvik-cache/*/*boot.art";
-  private static final String DELETE_PRELOADED_CMD = "rm " + PRELOADED_CLASSES_FILE;
-  private static final String READ_PRELOADED_CMD = "cat " + PRELOADED_CLASSES_FILE;
-  private static final String START_SHELL_CMD = "start";
-  private static final String STOP_SHELL_CMD = "stop";
-  private static final String REMOUNT_SYSTEM_CMD = "mount -o rw,remount /system";
-  private static final String UNSET_BOOTCOMPLETE_CMD = "setprop dev.bootcomplete \"0\"";
-
-  public static void init(int debugPort) {
-    DdmPreferences.setSelectedDebugPort(debugPort);
-
-    Hprof.init();
-
-    AndroidDebugBridge.init(true);
-
-    AndroidDebugBridge.createBridge();
-  }
-
-  /**
-   * Run a command in the shell on the device.
-   */
-  public static void doShell(IDevice device, String cmdline, long timeout, TimeUnit unit) {
-    doShell(device, cmdline, new NullShellOutputReceiver(), timeout, unit);
-  }
-
-  /**
-   * Run a command in the shell on the device. Collects and returns the console output.
-   */
-  public static String doShellReturnString(IDevice device, String cmdline, long timeout,
-      TimeUnit unit) {
-    CollectStringShellOutputReceiver rec = new CollectStringShellOutputReceiver();
-    doShell(device, cmdline, rec, timeout, unit);
-    return rec.toString();
-  }
-
-  /**
-   * Run a command in the shell on the device, directing all output to the given receiver.
-   */
-  public static void doShell(IDevice device, String cmdline, IShellOutputReceiver receiver,
-      long timeout, TimeUnit unit) {
-    try {
-      device.executeShellCommand(cmdline, receiver, timeout, unit);
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-
-  /**
-   * Run am start on the device.
-   */
-  public static void doAMStart(IDevice device, String name, String activity) {
-    doShell(device, "am start -n " + name + " /." + activity, 30, TimeUnit.SECONDS);
-  }
-
-  /**
-   * Find the device with the given serial. Give up after the given timeout (in milliseconds).
-   */
-  public static IDevice findDevice(String serial, int timeout) {
-    WaitForDevice wfd = new WaitForDevice(serial, timeout);
-    return wfd.get();
-  }
-
-  /**
-   * Get all devices ddms knows about. Wait at most for the given timeout.
-   */
-  public static IDevice[] findDevices(int timeout) {
-    WaitForDevice wfd = new WaitForDevice(null, timeout);
-    wfd.get();
-    return AndroidDebugBridge.getBridge().getDevices();
-  }
-
-  /**
-   * Return the build type of the given device. This is the value of the "ro.build.type"
-   * system property.
-   */
-  public static String getBuildType(IDevice device) {
-    try {
-      Future<String> buildType = device.getSystemProperty("ro.build.type");
-      return buildType.get(500, TimeUnit.MILLISECONDS);
-    } catch (Exception e) {
-    }
-    return null;
-  }
-
-  /**
-   * Check whether the given device has a pre-optimized boot image. More precisely, checks
-   * whether /system/framework/ * /boot.art exists.
-   */
-  public static boolean hasPrebuiltBootImage(IDevice device) {
-    String ret =
-        doShellReturnString(device, "ls /system/framework/*/boot.art", 500, TimeUnit.MILLISECONDS);
-
-    return !ret.contains("No such file or directory");
-  }
-
-    /**
-     * Write over the preloaded-classes file with an empty or existing file and regenerate the boot
-     * image as necessary.
-     *
-     * @param device
-     * @param pcFile
-     * @param bootTimeout
-     * @throws AdbCommandRejectedException
-     * @throws IOException
-     * @throws TimeoutException
-     * @throws SyncException
-     * @return true if successfully overwritten, false otherwise
-     */
-    public static boolean overwritePreloaded(IDevice device, File pcFile, long bootTimeout)
-            throws AdbCommandRejectedException, IOException, TimeoutException, SyncException {
-        boolean writeEmpty = (pcFile == null);
-        if (writeEmpty) {
-            // Check if the preloaded-classes file is already empty.
-            String oldContent =
-                    doShellReturnString(device, READ_PRELOADED_CMD, 1, TimeUnit.SECONDS);
-            if (oldContent.trim().equals("")) {
-                System.out.println("Preloaded-classes already empty.");
-                return true;
-            }
-        }
-
-        // Stop the system server etc.
-        doShell(device, STOP_SHELL_CMD, 1, TimeUnit.SECONDS);
-        // Remount the read-only system partition
-        doShell(device, REMOUNT_SYSTEM_CMD, 1, TimeUnit.SECONDS);
-        // Delete the preloaded-classes file
-        doShell(device, DELETE_PRELOADED_CMD, 1, TimeUnit.SECONDS);
-        // Delete the dalvik cache files
-        doShell(device, DELETE_CACHE_CMD, 1, TimeUnit.SECONDS);
-        if (writeEmpty) {
-            // Write an empty preloaded-classes file
-            doShell(device, CREATE_EMPTY_PRELOADED_CMD, 500, TimeUnit.MILLISECONDS);
-        } else {
-            // Push the new preloaded-classes file
-            device.pushFile(pcFile.getAbsolutePath(), PRELOADED_CLASSES_FILE);
-        }
-        // Manually reset the boot complete flag
-        doShell(device, UNSET_BOOTCOMPLETE_CMD, 1, TimeUnit.SECONDS);
-        // Restart system server on the device
-        doShell(device, START_SHELL_CMD, 1, TimeUnit.SECONDS);
-        // Wait for the boot complete flag and return the outcome.
-        return waitForBootComplete(device, bootTimeout);
-  }
-
-  private static boolean waitForBootComplete(IDevice device, long timeout) {
-    // Do a loop checking each second whether bootcomplete. Wait for at most the given
-    // threshold.
-    Date startDate = new Date();
-    for (;;) {
-      try {
-        Thread.sleep(1000);
-      } catch (InterruptedException e) {
-        // Ignore spurious wakeup.
-      }
-      // Check whether bootcomplete.
-      String ret =
-          doShellReturnString(device, "getprop dev.bootcomplete", 500, TimeUnit.MILLISECONDS);
-      if (ret.trim().equals("1")) {
-        break;
-      }
-      System.out.println("Still not booted: " + ret);
-
-      // Check whether we timed out. This is a simplistic check that doesn't take into account
-      // things like switches in time.
-      Date endDate = new Date();
-      long seconds =
-          TimeUnit.SECONDS.convert(endDate.getTime() - startDate.getTime(), TimeUnit.MILLISECONDS);
-      if (seconds > timeout) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  /**
-   * Enable method-tracing on device. The system should be restarted after this.
-   */
-  public static void enableTracing(IDevice device) {
-    // Disable selinux.
-    doShell(device, "setenforce 0", 100, TimeUnit.MILLISECONDS);
-
-    // Make the profile directory world-writable.
-    doShell(device, "chmod 777 /data/dalvik-cache/profiles", 100, TimeUnit.MILLISECONDS);
-
-    // Enable streaming method tracing with a small 1K buffer.
-    doShell(device, "setprop dalvik.vm.method-trace true", 100, TimeUnit.MILLISECONDS);
-    doShell(device, "setprop dalvik.vm.method-trace-file "
-                    + "/data/dalvik-cache/profiles/zygote.trace.bin", 100, TimeUnit.MILLISECONDS);
-    doShell(device, "setprop dalvik.vm.method-trace-file-siz 1024", 100, TimeUnit.MILLISECONDS);
-    doShell(device, "setprop dalvik.vm.method-trace-stream true", 100, TimeUnit.MILLISECONDS);
-  }
-
-  private static class NullShellOutputReceiver implements IShellOutputReceiver {
-    @Override
-    public boolean isCancelled() {
-      return false;
-    }
-
-    @Override
-    public void flush() {}
-
-    @Override
-    public void addOutput(byte[] arg0, int arg1, int arg2) {}
-  }
-
-  private static class CollectStringShellOutputReceiver implements IShellOutputReceiver {
-
-    private StringBuilder builder = new StringBuilder();
-
-    @Override
-    public String toString() {
-      String ret = builder.toString();
-      // Strip trailing newlines. They are especially ugly because adb uses DOS line endings.
-      while (ret.endsWith("\r") || ret.endsWith("\n")) {
-        ret = ret.substring(0, ret.length() - 1);
-      }
-      return ret;
-    }
-
-    @Override
-    public void addOutput(byte[] arg0, int arg1, int arg2) {
-      builder.append(new String(arg0, arg1, arg2));
-    }
-
-    @Override
-    public void flush() {}
-
-    @Override
-    public boolean isCancelled() {
-      return false;
-    }
-  }
-
-  private static class WaitForDevice {
-
-    private String serial;
-    private long timeout;
-    private IDevice device;
-
-    public WaitForDevice(String serial, long timeout) {
-      this.serial = serial;
-      this.timeout = timeout;
-      device = null;
-    }
-
-    public IDevice get() {
-      if (device == null) {
-          WaitForDeviceListener wfdl = new WaitForDeviceListener(serial);
-          synchronized (wfdl) {
-              AndroidDebugBridge.addDeviceChangeListener(wfdl);
-
-              // Check whether we already know about this device.
-              IDevice[] devices = AndroidDebugBridge.getBridge().getDevices();
-              if (serial != null) {
-                  for (IDevice d : devices) {
-                      if (serial.equals(d.getSerialNumber())) {
-                          // Only accept if there are clients already. Else wait for the callback informing
-                          // us that we now have clients.
-                          if (d.hasClients()) {
-                              device = d;
-                          }
-
-                          break;
-                      }
-                  }
-              } else {
-                  if (devices.length > 0) {
-                      device = devices[0];
-                  }
-              }
-
-              if (device == null) {
-                  try {
-                      wfdl.wait(timeout);
-                  } catch (InterruptedException e) {
-                      // Ignore spurious wakeups.
-                  }
-                  device = wfdl.getDevice();
-              }
-
-              AndroidDebugBridge.removeDeviceChangeListener(wfdl);
-          }
-      }
-
-      if (device != null) {
-          // Wait for clients.
-          WaitForClientsListener wfcl = new WaitForClientsListener(device);
-          synchronized (wfcl) {
-              AndroidDebugBridge.addDeviceChangeListener(wfcl);
-
-              if (!device.hasClients()) {
-                  try {
-                      wfcl.wait(timeout);
-                  } catch (InterruptedException e) {
-                      // Ignore spurious wakeups.
-                  }
-              }
-
-              AndroidDebugBridge.removeDeviceChangeListener(wfcl);
-          }
-      }
-
-      return device;
-    }
-
-    private static class WaitForDeviceListener implements IDeviceChangeListener {
-
-        private String serial;
-        private IDevice device;
-
-        public WaitForDeviceListener(String serial) {
-            this.serial = serial;
-        }
-
-        public IDevice getDevice() {
-            return device;
-        }
-
-        @Override
-        public void deviceChanged(IDevice arg0, int arg1) {
-            // We may get a device changed instead of connected. Handle like a connection.
-            deviceConnected(arg0);
-        }
-
-        @Override
-        public void deviceConnected(IDevice arg0) {
-            if (device != null) {
-                // Ignore updates.
-                return;
-            }
-
-            if (serial == null || serial.equals(arg0.getSerialNumber())) {
-                device = arg0;
-                synchronized (this) {
-                    notifyAll();
-                }
-            }
-        }
-
-        @Override
-        public void deviceDisconnected(IDevice arg0) {
-            // Ignore disconnects.
-        }
-
-    }
-
-    private static class WaitForClientsListener implements IDeviceChangeListener {
-
-        private IDevice myDevice;
-
-        public WaitForClientsListener(IDevice myDevice) {
-            this.myDevice = myDevice;
-        }
-
-        @Override
-        public void deviceChanged(IDevice arg0, int arg1) {
-            if (arg0 == myDevice && (arg1 & IDevice.CHANGE_CLIENT_LIST) != 0) {
-                // Got a client list, done here.
-                synchronized (this) {
-                    notifyAll();
-                }
-            }
-        }
-
-        @Override
-        public void deviceConnected(IDevice arg0) {
-        }
-
-        @Override
-        public void deviceDisconnected(IDevice arg0) {
-        }
-
-    }
-  }
-
-}
diff --git a/tools/preload2/src/com/android/preload/DumpData.java b/tools/preload2/src/com/android/preload/DumpData.java
deleted file mode 100644
index d997224..0000000
--- a/tools/preload2/src/com/android/preload/DumpData.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Holds the collected data for a process.
- */
-public class DumpData {
-    /**
-     * Name of the package (=application).
-     */
-    String packageName;
-
-    /**
-     * A map of class name to a string for the classloader. This may be a toString equivalent,
-     * or just a unique ID.
-     */
-    Map<String, String> dumpData;
-
-    /**
-     * The Date when this data was captured. Mostly for display purposes.
-     */
-    Date date;
-
-    /**
-     * A cached value for the number of boot classpath classes (classloader value in dumpData is
-     * null).
-     */
-    int bcpClasses;
-
-    public DumpData(String packageName, Map<String, String> dumpData, Date date) {
-        this.packageName = packageName;
-        this.dumpData = dumpData;
-        this.date = date;
-
-        countBootClassPath();
-    }
-
-    public String getPackageName() {
-        return packageName;
-    }
-
-    public Date getDate() {
-        return date;
-    }
-
-    public Map<String, String> getDumpData() {
-        return dumpData;
-    }
-
-    public void countBootClassPath() {
-        bcpClasses = 0;
-        for (Map.Entry<String, String> e : dumpData.entrySet()) {
-            if (e.getValue() == null) {
-                bcpClasses++;
-            }
-        }
-    }
-
-    // Return an inverted mapping.
-    public Map<String, Set<String>> invertData() {
-        Map<String, Set<String>> ret = new HashMap<>();
-        for (Map.Entry<String, String> e : dumpData.entrySet()) {
-            if (!ret.containsKey(e.getValue())) {
-                ret.put(e.getValue(), new HashSet<String>());
-            }
-            ret.get(e.getValue()).add(e.getKey());
-        }
-        return ret;
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/DumpDataIO.java b/tools/preload2/src/com/android/preload/DumpDataIO.java
deleted file mode 100644
index 28625c5..0000000
--- a/tools/preload2/src/com/android/preload/DumpDataIO.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
-
-import java.io.File;
-import java.io.FileReader;
-import java.text.DateFormat;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * Helper class for serialization and deserialization of a collection of DumpData objects to XML.
- */
-public class DumpDataIO {
-
-  /**
-   * Serialize the given collection to an XML document. Returns the produced string.
-   */
-  public static String serialize(Collection<DumpData> data) {
-      // We'll do this by hand, constructing a DOM or similar is too complicated for our simple
-      // use case.
-
-      StringBuilder sb = new StringBuilder();
-      sb.append("<preloaded-classes-data>\n");
-
-      for (DumpData d : data) {
-          serialize(d, sb);
-      }
-
-      sb.append("</preloaded-classes-data>\n");
-      return sb.toString();
-  }
-
-  private static void serialize(DumpData d, StringBuilder sb) {
-      sb.append("<data package=\"" + d.packageName + "\" date=\"" +
-              DateFormat.getDateTimeInstance().format(d.date) +"\">\n");
-
-      for (Map.Entry<String, String> e : d.dumpData.entrySet()) {
-          sb.append("<class name=\"" + e.getKey() + "\" classloader=\"" + e.getValue() + "\"/>\n");
-      }
-
-      sb.append("</data>\n");
-  }
-
-  /**
-   * Load a collection of DumpData objects from the given file.
-   */
-  public static Collection<DumpData> deserialize(File f) throws Exception {
-      // Use SAX parsing. Our format is very simple. Don't do any schema validation or such.
-
-      SAXParserFactory spf = SAXParserFactory.newInstance();
-      spf.setNamespaceAware(false);
-      SAXParser saxParser = spf.newSAXParser();
-
-      XMLReader xmlReader = saxParser.getXMLReader();
-      DumpDataContentHandler ddch = new DumpDataContentHandler();
-      xmlReader.setContentHandler(ddch);
-      xmlReader.parse(new InputSource(new FileReader(f)));
-
-      return ddch.data;
-  }
-
-  private static class DumpDataContentHandler extends DefaultHandler {
-      Collection<DumpData> data = new LinkedList<DumpData>();
-      DumpData openData = null;
-
-      @Override
-      public void startElement(String uri, String localName, String qName, Attributes attributes)
-              throws SAXException {
-          if (qName.equals("data")) {
-              if (openData != null) {
-                  throw new IllegalStateException();
-              }
-              String pkg = attributes.getValue("package");
-              String dateString = attributes.getValue("date");
-
-              if (pkg == null || dateString == null) {
-                  throw new IllegalArgumentException();
-              }
-
-              try {
-                  Date date = DateFormat.getDateTimeInstance().parse(dateString);
-                  openData = new DumpData(pkg, new HashMap<String, String>(), date);
-              } catch (Exception e) {
-                  throw new RuntimeException(e);
-              }
-          } else if (qName.equals("class")) {
-              if (openData == null) {
-                  throw new IllegalStateException();
-              }
-              String className = attributes.getValue("name");
-              String classLoader = attributes.getValue("classloader");
-
-              if (className == null || classLoader == null) {
-                  throw new IllegalArgumentException();
-              }
-
-              openData.dumpData.put(className, classLoader.equals("null") ? null : classLoader);
-          }
-      }
-
-      @Override
-      public void endElement(String uri, String localName, String qName) throws SAXException {
-          if (qName.equals("data")) {
-              if (openData == null) {
-                  throw new IllegalStateException();
-              }
-              openData.countBootClassPath();
-
-              data.add(openData);
-              openData = null;
-          }
-      }
-  }
-}
diff --git a/tools/preload2/src/com/android/preload/DumpTableModel.java b/tools/preload2/src/com/android/preload/DumpTableModel.java
deleted file mode 100644
index d97cbf0..0000000
--- a/tools/preload2/src/com/android/preload/DumpTableModel.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.table.AbstractTableModel;
-
-/**
- * A table model for collected DumpData. This is both the internal storage as well as the model
- * for display.
- */
-public class DumpTableModel extends AbstractTableModel {
-
-    private List<DumpData> data = new ArrayList<DumpData>();
-
-    public void addData(DumpData d) {
-        data.add(d);
-        fireTableRowsInserted(data.size() - 1, data.size() - 1);
-    }
-
-    public void clear() {
-        int size = data.size();
-        if (size > 0) {
-            data.clear();
-            fireTableRowsDeleted(0, size - 1);
-        }
-    }
-
-    public List<DumpData> getData() {
-        return data;
-    }
-
-    @Override
-    public int getRowCount() {
-        return data.size();
-    }
-
-    @Override
-    public int getColumnCount() {
-        return 4;
-    }
-
-    @Override
-    public String getColumnName(int column) {
-        switch (column) {
-            case 0:
-                return "Package";
-            case 1:
-                return "Date";
-            case 2:
-                return "# All Classes";
-            case 3:
-                return "# Boot Classpath Classes";
-
-            default:
-                throw new IndexOutOfBoundsException(String.valueOf(column));
-        }
-    }
-
-    @Override
-    public Object getValueAt(int rowIndex, int columnIndex) {
-        DumpData d = data.get(rowIndex);
-        switch (columnIndex) {
-            case 0:
-                return d.packageName;
-            case 1:
-                return d.date;
-            case 2:
-                return d.dumpData.size();
-            case 3:
-                return d.bcpClasses;
-
-            default:
-                throw new IndexOutOfBoundsException(String.valueOf(columnIndex));
-        }
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/Main.java b/tools/preload2/src/com/android/preload/Main.java
deleted file mode 100644
index 2265e95..0000000
--- a/tools/preload2/src/com/android/preload/Main.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.actions.ClearTableAction;
-import com.android.preload.actions.ComputeThresholdAction;
-import com.android.preload.actions.ComputeThresholdXAction;
-import com.android.preload.actions.DeviceSpecific;
-import com.android.preload.actions.ExportAction;
-import com.android.preload.actions.ImportAction;
-import com.android.preload.actions.ReloadListAction;
-import com.android.preload.actions.RunMonkeyAction;
-import com.android.preload.actions.ScanAllPackagesAction;
-import com.android.preload.actions.ScanPackageAction;
-import com.android.preload.actions.ShowDataAction;
-import com.android.preload.actions.WritePreloadedClassesAction;
-import com.android.preload.classdataretrieval.ClassDataRetriever;
-import com.android.preload.classdataretrieval.hprof.Hprof;
-import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
-import com.android.preload.ui.IUI;
-import com.android.preload.ui.SequenceUI;
-import com.android.preload.ui.SwingUI;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import javax.swing.Action;
-import javax.swing.DefaultListModel;
-
-public class Main {
-
-    /**
-     * Enable tracing mode. This is a work-in-progress to derive compiled-methods data, so it is
-     * off for now.
-     */
-    public final static boolean ENABLE_TRACING = false;
-
-    /**
-     * Ten-second timeout.
-     */
-    public final static int DEFAULT_TIMEOUT_MILLIS = 10 * 1000;
-
-    /**
-     * Hprof timeout. Two minutes.
-     */
-    public final static int HPROF_TIMEOUT_MILLIS = 120 * 1000;
-
-    private IDevice device;
-    private static ClientUtils clientUtils;
-
-    private DumpTableModel dataTableModel;
-    private DefaultListModel<Client> clientListModel;
-
-    private IUI ui;
-
-    // Actions that need to be updated once a device is selected.
-    private Collection<DeviceSpecific> deviceSpecificActions;
-
-    // Current main instance.
-    private static Main top;
-    private static boolean useJdwpClassDataRetriever = false;
-
-    public final static String CLASS_PRELOAD_BLACKLIST = "android.app.AlarmManager$" + "|"
-            + "android.app.SearchManager$" + "|" + "android.os.FileObserver$" + "|"
-            + "com.android.server.PackageManagerService\\$AppDirObserver$" + "|" +
-
-
-            // Threads
-            "android.os.AsyncTask$" + "|" + "android.pim.ContactsAsyncHelper$" + "|"
-            + "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|"
-            + "(.*\\$NoPreloadHolder$)";
-
-    public final static String SCAN_ALL_CMD = "scan-all";
-    public final static String SCAN_PACKAGE_CMD = "scan";
-    public final static String COMPUTE_FILE_CMD = "comp";
-    public final static String EXPORT_CMD = "export";
-    public final static String IMPORT_CMD = "import";
-    public final static String WRITE_CMD = "write";
-
-    /**
-     * @param args
-     */
-    public static void main(String[] args) {
-        Main m;
-        if (args.length > 0 && args[0].equals("--seq")) {
-            m = createSequencedMain(args);
-        } else {
-            m = new Main(new SwingUI());
-        }
-
-        top = m;
-        m.startUp();
-    }
-
-    public Main(IUI ui) {
-        this.ui = ui;
-
-        clientListModel = new DefaultListModel<Client>();
-        dataTableModel = new DumpTableModel();
-
-        clientUtils = new ClientUtils(DEFAULT_TIMEOUT_MILLIS);  // Client utils with 10s timeout.
-
-        List<Action> actions = new ArrayList<Action>();
-        actions.add(new ReloadListAction(clientUtils, null, clientListModel));
-        actions.add(new ClearTableAction(dataTableModel));
-        actions.add(new RunMonkeyAction(null, dataTableModel));
-        actions.add(new ScanPackageAction(clientUtils, null, dataTableModel));
-        actions.add(new ScanAllPackagesAction(clientUtils, null, dataTableModel));
-        actions.add(new ComputeThresholdAction("Compute preloaded-classes", dataTableModel, 2,
-                CLASS_PRELOAD_BLACKLIST));
-        actions.add(new ComputeThresholdAction("Compute compiled-classes", dataTableModel, 1,
-                null));
-        actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel,
-                CLASS_PRELOAD_BLACKLIST));
-        actions.add(new WritePreloadedClassesAction(clientUtils, null, dataTableModel));
-        actions.add(new ShowDataAction(dataTableModel));
-        actions.add(new ImportAction(dataTableModel));
-        actions.add(new ExportAction(dataTableModel));
-
-        deviceSpecificActions = new ArrayList<DeviceSpecific>();
-        for (Action a : actions) {
-            if (a instanceof DeviceSpecific) {
-                deviceSpecificActions.add((DeviceSpecific)a);
-            }
-        }
-
-        ui.prepare(clientListModel, dataTableModel, actions);
-    }
-
-    /**
-     * @param args
-     * @return
-     */
-    private static Main createSequencedMain(String[] args) {
-        SequenceUI ui = new SequenceUI();
-        Main main = new Main(ui);
-
-        Iterator<String> it = Arrays.asList(args).iterator();
-        it.next();  // --seq
-        // Setup
-        ui.choice("#" + it.next());  // Device.
-        ui.confirmNo();              // Prepare: no.
-        // Actions
-        try {
-            while (it.hasNext()) {
-                String op = it.next();
-                // Operation: Scan a single package
-                if (SCAN_PACKAGE_CMD.equals(op)) {
-                    System.out.println("Scanning package.");
-                    ui.action(ScanPackageAction.class);
-                    ui.client(it.next());
-                // Operation: Scan all packages
-                } else if (SCAN_ALL_CMD.equals(op)) {
-                    System.out.println("Scanning all packages.");
-                    ui.action(ScanAllPackagesAction.class);
-                // Operation: Export the output to a file
-                } else if (EXPORT_CMD.equals(op)) {
-                    System.out.println("Exporting data.");
-                    ui.action(ExportAction.class);
-                    ui.output(new File(it.next()));
-                // Operation: Import the input from a file or directory
-                } else if (IMPORT_CMD.equals(op)) {
-                    System.out.println("Importing data.");
-                    File file = new File(it.next());
-                    if (!file.exists()) {
-                        throw new RuntimeException(
-                                String.format("File does not exist, %s.", file.getAbsolutePath()));
-                    } else if (file.isFile()) {
-                        ui.action(ImportAction.class);
-                        ui.input(file);
-                    } else if (file.isDirectory()) {
-                        for (File content : file.listFiles()) {
-                            ui.action(ImportAction.class);
-                            ui.input(content);
-                        }
-                    }
-                // Operation: Compute preloaded classes with specific threshold
-                } else if (COMPUTE_FILE_CMD.equals(op)) {
-                    System.out.println("Compute preloaded classes.");
-                    ui.action(ComputeThresholdXAction.class);
-                    ui.input(it.next());
-                    ui.confirmYes();
-                    ui.output(new File(it.next()));
-                // Operation: Write preloaded classes from a specific file
-                } else if (WRITE_CMD.equals(op)) {
-                    System.out.println("Writing preloaded classes.");
-                    ui.action(WritePreloadedClassesAction.class);
-                    ui.input(new File(it.next()));
-                }
-            }
-        } catch (NoSuchElementException e) {
-            System.out.println("Failed to parse action sequence correctly.");
-            throw e;
-        }
-
-        return main;
-    }
-
-    public static IUI getUI() {
-        return top.ui;
-    }
-
-    public static ClassDataRetriever getClassDataRetriever() {
-        if (useJdwpClassDataRetriever) {
-            return new JDWPClassDataRetriever();
-        } else {
-            return new Hprof(HPROF_TIMEOUT_MILLIS);
-        }
-    }
-
-    public IDevice getDevice() {
-        return device;
-    }
-
-    public void setDevice(IDevice device) {
-        this.device = device;
-        for (DeviceSpecific ds : deviceSpecificActions) {
-            ds.setDevice(device);
-        }
-    }
-
-    public DefaultListModel<Client> getClientListModel() {
-        return clientListModel;
-    }
-
-    static class DeviceWrapper {
-        IDevice device;
-
-        public DeviceWrapper(IDevice d) {
-            device = d;
-        }
-
-        @Override
-        public String toString() {
-            return device.getName() + " (#" + device.getSerialNumber() + ")";
-        }
-    }
-
-    private void startUp() {
-        getUI().showWaitDialog();
-        initDevice();
-
-        // Load clients.
-        new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
-
-        getUI().hideWaitDialog();
-        getUI().ready();
-    }
-
-    private void initDevice() {
-        DeviceUtils.init(DEFAULT_TIMEOUT_MILLIS);
-
-        IDevice devices[] = DeviceUtils.findDevices(DEFAULT_TIMEOUT_MILLIS);
-        if (devices == null || devices.length == 0) {
-            throw new RuntimeException("Could not find any devices...");
-        }
-
-        getUI().hideWaitDialog();
-
-        DeviceWrapper deviceWrappers[] = new DeviceWrapper[devices.length];
-        for (int i = 0; i < devices.length; i++) {
-            deviceWrappers[i] = new DeviceWrapper(devices[i]);
-        }
-
-        DeviceWrapper ret = Main.getUI().showChoiceDialog("Choose a device", "Choose device",
-                deviceWrappers);
-        if (ret != null) {
-            setDevice(ret.device);
-        } else {
-            System.exit(0);
-        }
-
-        boolean prepare = Main.getUI().showConfirmDialog("Prepare device?",
-                "Do you want to prepare the device? This is highly recommended.");
-        if (prepare) {
-            String buildType = DeviceUtils.getBuildType(device);
-            if (buildType == null || (!buildType.equals("userdebug") && !buildType.equals("eng"))) {
-                Main.getUI().showMessageDialog("Need a userdebug or eng build! (Found " + buildType
-                        + ")");
-                return;
-            }
-            if (DeviceUtils.hasPrebuiltBootImage(device)) {
-                Main.getUI().showMessageDialog("Cannot prepare a device with pre-optimized boot "
-                        + "image!");
-                return;
-            }
-
-            if (ENABLE_TRACING) {
-                DeviceUtils.enableTracing(device);
-            }
-
-            Main.getUI().showMessageDialog("The device will reboot. This will potentially take a "
-                    + "long time. Please be patient.");
-            boolean success = false;
-            try {
-                success = DeviceUtils.overwritePreloaded(device, null, 15 * 60);
-            } catch (Exception e) {
-                System.err.println(e);
-            } finally {
-                if (!success) {
-                    Main.getUI().showMessageDialog(
-                            "Removing preloaded-classes failed unexpectedly!");
-                }
-            }
-        }
-    }
-
-    public static Map<String, String> findAndGetClassData(IDevice device, String packageName)
-            throws Exception {
-        Client client = clientUtils.findClient(device, packageName, -1);
-        if (client == null) {
-            throw new RuntimeException("Could not find client...");
-        }
-        System.out.println("Found client: " + client);
-
-        return getClassDataRetriever().getClassData(client);
-    }
-
-}
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
deleted file mode 100644
index 5787d85..0000000
--- a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.preload.Main;
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-
-public abstract class AbstractThreadedAction extends AbstractAction implements Runnable {
-
-    protected AbstractThreadedAction(String title) {
-        super(title);
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        if (Main.getUI().isSingleThreaded()) {
-            run();
-        } else {
-            new Thread(this).start();
-        }
-    }
-
-}
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java
deleted file mode 100644
index 7906417..0000000
--- a/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.ddmlib.IDevice;
-
-import java.awt.event.ActionEvent;
-
-public abstract class AbstractThreadedDeviceSpecificAction extends AbstractThreadedAction
-        implements DeviceSpecific {
-
-    protected IDevice device;
-
-    protected AbstractThreadedDeviceSpecificAction(String title, IDevice device) {
-        super(title);
-        this.device = device;
-    }
-
-    @Override
-    public void setDevice(IDevice device) {
-        this.device = device;
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        if (device == null) {
-            return;
-        }
-        super.actionPerformed(e);
-    }
-}
diff --git a/tools/preload2/src/com/android/preload/actions/ClearTableAction.java b/tools/preload2/src/com/android/preload/actions/ClearTableAction.java
deleted file mode 100644
index c0e4795..0000000
--- a/tools/preload2/src/com/android/preload/actions/ClearTableAction.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.preload.DumpTableModel;
-
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-
-public class ClearTableAction extends AbstractAction {
-    private final DumpTableModel dataTableModel;
-
-    public ClearTableAction(DumpTableModel dataTableModel) {
-        super("Clear");
-        this.dataTableModel = dataTableModel;
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        dataTableModel.clear();
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
deleted file mode 100644
index 3a7f7f7..0000000
--- a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.regex.Pattern;
-
-import javax.swing.AbstractAction;
-
-/**
- * Compute an intersection of classes from the given data. A class is in the intersection if it
- * appears in at least the number of threshold given packages. An optional blacklist can be
- * used to filter classes from the intersection.
- */
-public class ComputeThresholdAction extends AbstractThreadedAction {
-    protected int threshold;
-    private Pattern blacklist;
-    private DumpTableModel dataTableModel;
-
-    /**
-     * Create an action with the given parameters. The blacklist is a regular expression
-     * that filters classes.
-     */
-    public ComputeThresholdAction(String name, DumpTableModel dataTableModel, int threshold,
-            String blacklist) {
-        super(name);
-        this.dataTableModel = dataTableModel;
-        this.threshold = threshold;
-        if (blacklist != null) {
-            this.blacklist = Pattern.compile(blacklist);
-        }
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        List<DumpData> data = dataTableModel.getData();
-        if (data.size() == 0) {
-            Main.getUI().showMessageDialog("No data available, please scan packages or run "
-                    + "monkeys.");
-            return;
-        }
-        if (data.size() == 1) {
-            Main.getUI().showMessageDialog("Cannot compute list from only one data set, please "
-                    + "scan packages or run monkeys.");
-            return;
-        }
-
-        super.actionPerformed(e);
-    }
-
-    @Override
-    public void run() {
-        Main.getUI().showWaitDialog();
-
-        Map<String, Set<String>> uses = new HashMap<String, Set<String>>();
-        for (DumpData d : dataTableModel.getData()) {
-            Main.getUI().updateWaitDialog("Merging " + d.getPackageName());
-            updateClassUse(d.getPackageName(), uses, getBootClassPathClasses(d.getDumpData()));
-        }
-
-        Main.getUI().updateWaitDialog("Computing thresholded set");
-        Set<String> result = fromThreshold(uses, blacklist, threshold);
-        Main.getUI().hideWaitDialog();
-
-        boolean ret = Main.getUI().showConfirmDialog("Computed a set with " + result.size()
-                + " classes, would you like to save to disk?", "Save?");
-        if (ret) {
-            File f = Main.getUI().showSaveDialog();
-            if (f != null) {
-                saveSet(result, f);
-            }
-        }
-    }
-
-    private Set<String> fromThreshold(Map<String, Set<String>> classUses, Pattern blacklist,
-            int threshold) {
-        TreeSet<String> ret = new TreeSet<>(); // TreeSet so it's nicely ordered by name.
-
-        for (Map.Entry<String, Set<String>> e : classUses.entrySet()) {
-            if (e.getValue().size() >= threshold) {
-                if (blacklist == null || !blacklist.matcher(e.getKey()).matches()) {
-                    ret.add(e.getKey());
-                }
-            }
-        }
-
-        return ret;
-    }
-
-    private static void updateClassUse(String pkg, Map<String, Set<String>> classUses,
-            Set<String> classes) {
-        for (String className : classes) {
-            Set<String> old = classUses.get(className);
-            if (old == null) {
-                classUses.put(className, new HashSet<String>());
-            }
-            classUses.get(className).add(pkg);
-        }
-    }
-
-    private static Set<String> getBootClassPathClasses(Map<String, String> source) {
-        Set<String> ret = new HashSet<>();
-        for (Map.Entry<String, String> e : source.entrySet()) {
-            if (e.getValue() == null) {
-                ret.add(e.getKey());
-            }
-        }
-        return ret;
-    }
-
-    private static void saveSet(Set<String> result, File f) {
-        try {
-            PrintWriter out = new PrintWriter(f);
-            for (String s : result) {
-                out.println(s);
-            }
-            out.close();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java
deleted file mode 100644
index 3ec0a4c..0000000
--- a/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-public class ComputeThresholdXAction extends ComputeThresholdAction {
-
-    public ComputeThresholdXAction(String name, DumpTableModel dataTableModel,
-            String blacklist) {
-        super(name, dataTableModel, 1, blacklist);
-    }
-
-    @Override
-    public void run() {
-        String value = Main.getUI().showInputDialog("Threshold?");
-
-        if (value != null) {
-            try {
-                threshold = Integer.parseInt(value);
-                super.run();
-            } catch (Exception exc) {
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java b/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java
deleted file mode 100644
index 35a8f26..0000000
--- a/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.ddmlib.IDevice;
-
-/**
- * Marks an action as being device-specific. The user must set the device through the specified
- * method if the device selection changes.
- *
- * Implementors must tolerate a null device (for example, with a no-op). This includes calling
- * any methods before setDevice has been called.
- */
-public interface DeviceSpecific {
-
-    /**
-     * Set the device that should be used. Note that there is no restriction on calling other
-     * methods of the implementor before a setDevice call. Neither is device guaranteed to be
-     * non-null.
-     *
-     * @param device The device to use going forward.
-     */
-    public void setDevice(IDevice device);
-}
diff --git a/tools/preload2/src/com/android/preload/actions/ExportAction.java b/tools/preload2/src/com/android/preload/actions/ExportAction.java
deleted file mode 100644
index 848a568..0000000
--- a/tools/preload2/src/com/android/preload/actions/ExportAction.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.preload.DumpDataIO;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.PrintWriter;
-
-public class ExportAction extends AbstractThreadedAction {
-    private File lastSaveFile;
-    private DumpTableModel dataTableModel;
-
-    public ExportAction(DumpTableModel dataTableModel) {
-        super("Export data");
-        this.dataTableModel = dataTableModel;
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        lastSaveFile = Main.getUI().showSaveDialog();
-        if (lastSaveFile != null) {
-            super.actionPerformed(e);
-        }
-    }
-
-    @Override
-    public void run() {
-        Main.getUI().showWaitDialog();
-
-        String serialized = DumpDataIO.serialize(dataTableModel.getData());
-
-        if (serialized != null) {
-            try {
-                PrintWriter out = new PrintWriter(lastSaveFile);
-                out.println(serialized);
-                out.close();
-
-                Main.getUI().hideWaitDialog();
-            } catch (Exception e) {
-                Main.getUI().hideWaitDialog();
-                Main.getUI().showMessageDialog("Failed writing: " + e.getMessage());
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ImportAction.java b/tools/preload2/src/com/android/preload/actions/ImportAction.java
deleted file mode 100644
index bfeeb83..0000000
--- a/tools/preload2/src/com/android/preload/actions/ImportAction.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.preload.DumpData;
-import com.android.preload.DumpDataIO;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.util.Collection;
-
-import javax.swing.AbstractAction;
-
-public class ImportAction extends AbstractThreadedAction {
-    private File[] lastOpenFiles;
-    private DumpTableModel dataTableModel;
-
-    public ImportAction(DumpTableModel dataTableModel) {
-        super("Import data");
-        this.dataTableModel = dataTableModel;
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        lastOpenFiles = Main.getUI().showOpenDialog(true);
-        if (lastOpenFiles != null) {
-            super.actionPerformed(e);
-        }
-    }
-
-    @Override
-    public void run() {
-        Main.getUI().showWaitDialog();
-
-        try {
-            for (File f : lastOpenFiles) {
-                try {
-                    Collection<DumpData> data = DumpDataIO.deserialize(f);
-
-                    for (DumpData d : data) {
-                        dataTableModel.addData(d);
-                    }
-                } catch (Exception e) {
-                    Main.getUI().showMessageDialog("Failed reading: " + e.getMessage());
-                }
-            }
-        } finally {
-            Main.getUI().hideWaitDialog();
-        }
-
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ReloadListAction.java b/tools/preload2/src/com/android/preload/actions/ReloadListAction.java
deleted file mode 100644
index 29f0557..0000000
--- a/tools/preload2/src/com/android/preload/actions/ReloadListAction.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-
-import java.util.Arrays;
-import java.util.Comparator;
-
-import javax.swing.DefaultListModel;
-
-public class ReloadListAction extends AbstractThreadedDeviceSpecificAction {
-
-    private ClientUtils clientUtils;
-    private final DefaultListModel<Client> clientListModel;
-
-    public ReloadListAction(ClientUtils utils, IDevice device,
-            DefaultListModel<Client> clientListModel) {
-        super("Reload", device);
-        this.clientUtils = utils;
-        this.clientListModel = clientListModel;
-    }
-
-    @Override
-    public void run() {
-        Client[] clients = clientUtils.findAllClients(device);
-        if (clients != null) {
-            Arrays.sort(clients, new ClientComparator());
-        }
-        clientListModel.removeAllElements();
-        for (Client c : clients) {
-            clientListModel.addElement(c);
-        }
-    }
-
-    private static class ClientComparator implements Comparator<Client> {
-
-        @Override
-        public int compare(Client o1, Client o2) {
-            String s1 = o1.getClientData().getClientDescription();
-            String s2 = o2.getClientData().getClientDescription();
-
-            if (s1 == null || s2 == null) {
-                // Not good, didn't get all data?
-                return (s1 == null) ? -1 : 1;
-            }
-
-            return s1.compareTo(s2);
-        }
-
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
deleted file mode 100644
index 29464fc..0000000
--- a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.ddmlib.IDevice;
-import com.android.preload.DeviceUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.util.Date;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import javax.swing.AbstractAction;
-
-public class RunMonkeyAction extends AbstractAction implements DeviceSpecific {
-
-    private final static String DEFAULT_MONKEY_PACKAGES =
-            "com.android.calendar,com.android.gallery3d";
-
-    private IDevice device;
-    private DumpTableModel dataTableModel;
-
-    public RunMonkeyAction(IDevice device, DumpTableModel dataTableModel) {
-        super("Run monkey");
-        this.device = device;
-        this.dataTableModel = dataTableModel;
-    }
-
-    @Override
-    public void setDevice(IDevice device) {
-        this.device = device;
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        String packages = Main.getUI().showInputDialog("Please enter packages name to run with"
-                + " the monkey, or leave empty for default.");
-        if (packages == null) {
-            return;
-        }
-        if (packages.isEmpty()) {
-            packages = DEFAULT_MONKEY_PACKAGES;
-        }
-        Runnable r = new RunMonkeyRunnable(packages);
-        if (Main.getUI().isSingleThreaded()) {
-            r.run();
-        } else {
-            new Thread(r).start();
-        }
-    }
-
-    private class RunMonkeyRunnable implements Runnable {
-
-        private String packages;
-        private final static int ITERATIONS = 1000;
-
-        public RunMonkeyRunnable(String packages) {
-            this.packages = packages;
-        }
-
-        @Override
-        public void run() {
-            Main.getUI().showWaitDialog();
-
-            try {
-                String pkgs[] = packages.split(",");
-
-                for (String pkg : pkgs) {
-                    Main.getUI().updateWaitDialog("Running monkey on " + pkg);
-
-                    try {
-                        // Stop running app.
-                        forceStop(pkg);
-
-                        // Little bit of breather here.
-                        try {
-                            Thread.sleep(1000);
-                        } catch (Exception e) {
-                        }
-
-                        DeviceUtils.doShell(device, "monkey -p " + pkg + " " + ITERATIONS, 1,
-                                TimeUnit.MINUTES);
-
-                        Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
-                        Map<String, String> data = Main.findAndGetClassData(device, pkg);
-                        DumpData dumpData = new DumpData(pkg, data, new Date());
-                        dataTableModel.addData(dumpData);
-                    } catch (Exception e) {
-                        e.printStackTrace();
-                    } finally {
-                        // Stop running app.
-                        forceStop(pkg);
-                    }
-                }
-            } finally {
-                Main.getUI().hideWaitDialog();
-            }
-        }
-
-        private void forceStop(String packageName) {
-            // Stop running app.
-            DeviceUtils.doShell(device, "force-stop " + packageName, 5, TimeUnit.SECONDS);
-            DeviceUtils.doShell(device, "kill " + packageName, 5, TimeUnit.SECONDS);
-            DeviceUtils.doShell(device, "kill `pid " + packageName + "`", 5, TimeUnit.SECONDS);
-        }
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java b/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java
deleted file mode 100644
index d74b8a3..0000000
--- a/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.util.Date;
-import java.util.Map;
-
-public class ScanAllPackagesAction extends AbstractThreadedDeviceSpecificAction {
-
-    private ClientUtils clientUtils;
-    private DumpTableModel dataTableModel;
-
-    public ScanAllPackagesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
-        super("Scan all packages", device);
-        this.clientUtils = utils;
-        this.dataTableModel = dataTableModel;
-    }
-
-    @Override
-    public void run() {
-        Main.getUI().showWaitDialog();
-
-        try {
-            Client[] clients = clientUtils.findAllClients(device);
-            for (Client c : clients) {
-                String pkg = c.getClientData().getClientDescription();
-                Main.getUI().showWaitDialog();
-                Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
-
-                try {
-                    Map<String, String> data = Main.getClassDataRetriever().getClassData(c);
-                    DumpData dumpData = new DumpData(pkg, data, new Date());
-                    dataTableModel.addData(dumpData);
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        } finally {
-            Main.getUI().hideWaitDialog();
-        }
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java b/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java
deleted file mode 100644
index 98492bd..0000000
--- a/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.util.Date;
-import java.util.Map;
-
-public class ScanPackageAction extends AbstractThreadedDeviceSpecificAction {
-
-    private ClientUtils clientUtils;
-    private DumpTableModel dataTableModel;
-
-    public ScanPackageAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
-        super("Scan package", device);
-        this.clientUtils = utils;
-        this.dataTableModel = dataTableModel;
-    }
-
-    @Override
-    public void run() {
-        Main.getUI().showWaitDialog();
-
-        try {
-            Client client = Main.getUI().getSelectedClient();
-            if (client != null) {
-                work(client);
-            } else {
-                Client[] clients = clientUtils.findAllClients(device);
-                if (clients.length > 0) {
-                    ClientWrapper[] clientWrappers = new ClientWrapper[clients.length];
-                    for (int i = 0; i < clientWrappers.length; i++) {
-                        clientWrappers[i] = new ClientWrapper(clients[i]);
-                    }
-                    Main.getUI().hideWaitDialog();
-
-                    ClientWrapper ret = Main.getUI().showChoiceDialog("Choose a package to scan",
-                            "Choose package",
-                            clientWrappers);
-                    if (ret != null) {
-                        work(ret.client);
-                    }
-                }
-            }
-        } finally {
-            Main.getUI().hideWaitDialog();
-        }
-    }
-
-    private void work(Client c) {
-        String pkg = c.getClientData().getClientDescription();
-        Main.getUI().showWaitDialog();
-        Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
-
-        try {
-            Map<String, String> data = Main.findAndGetClassData(device, pkg);
-            DumpData dumpData = new DumpData(pkg, data, new Date());
-            dataTableModel.addData(dumpData);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    private static class ClientWrapper {
-        private Client client;
-
-        public ClientWrapper(Client c) {
-            client = c;
-        }
-
-        @Override
-        public String toString() {
-            return client.getClientData().getClientDescription() + " (pid "
-                    + client.getClientData().getPid() + ")";
-        }
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ShowDataAction.java b/tools/preload2/src/com/android/preload/actions/ShowDataAction.java
deleted file mode 100644
index 2bb175f..0000000
--- a/tools/preload2/src/com/android/preload/actions/ShowDataAction.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.swing.AbstractAction;
-import javax.swing.JFrame;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-
-public class ShowDataAction extends AbstractAction {
-    private DumpTableModel dataTableModel;
-
-    public ShowDataAction(DumpTableModel dataTableModel) {
-        super("Show data");
-        this.dataTableModel = dataTableModel;
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        // TODO(agampe): Auto-generated method stub
-        int selRow = Main.getUI().getSelectedDataTableRow();
-        if (selRow != -1) {
-            DumpData data = dataTableModel.getData().get(selRow);
-            Map<String, Set<String>> inv = data.invertData();
-
-            StringBuilder builder = new StringBuilder();
-
-            // First bootclasspath.
-            add(builder, "Boot classpath:", inv.get(null));
-
-            // Now everything else.
-            for (String k : inv.keySet()) {
-                if (k != null) {
-                    builder.append("==================\n\n");
-                    add(builder, k, inv.get(k));
-                }
-            }
-
-            JFrame newFrame = new JFrame(data.getPackageName() + " " + data.getDate());
-            newFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
-            newFrame.getContentPane().add(new JScrollPane(new JTextArea(builder.toString())),
-                    BorderLayout.CENTER);
-            newFrame.setSize(800, 600);
-            newFrame.setLocationRelativeTo(null);
-            newFrame.setVisible(true);
-        }
-    }
-
-    private void add(StringBuilder builder, String head, Set<String> set) {
-        builder.append(head);
-        builder.append('\n');
-        addSet(builder, set);
-        builder.append('\n');
-    }
-
-    private void addSet(StringBuilder builder, Set<String> set) {
-        if (set == null) {
-            builder.append("  NONE\n");
-            return;
-        }
-        List<String> sorted = new ArrayList<>(set);
-        Collections.sort(sorted);
-        for (String s : sorted) {
-            builder.append(s);
-            builder.append('\n');
-        }
-    }
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java b/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java
deleted file mode 100644
index 9b97f11..0000000
--- a/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.actions;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.IDevice;
-import com.android.preload.ClientUtils;
-import com.android.preload.DeviceUtils;
-import com.android.preload.DumpData;
-import com.android.preload.DumpTableModel;
-import com.android.preload.Main;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.util.Date;
-import java.util.Map;
-
-public class WritePreloadedClassesAction extends AbstractThreadedDeviceSpecificAction {
-    private File preloadedClassFile;
-
-    public WritePreloadedClassesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
-        super("Write preloaded classes action", device);
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        File[] files = Main.getUI().showOpenDialog(true);
-        if (files != null && files.length > 0) {
-            preloadedClassFile = files[0];
-            super.actionPerformed(e);
-        }
-    }
-
-    @Override
-    public void run() {
-        Main.getUI().showWaitDialog();
-        try {
-            // Write the new file with a 5-minute timeout
-            DeviceUtils.overwritePreloaded(device, preloadedClassFile, 5 * 60);
-        } catch (Exception e) {
-            System.err.println(e);
-        } finally {
-            Main.getUI().hideWaitDialog();
-        }
-    }
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java b/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java
deleted file mode 100644
index f04360f..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.classdataretrieval;
-
-import com.android.ddmlib.Client;
-
-import java.util.Map;
-
-/**
- * Retrieve a class-to-classloader map for loaded classes from the client.
- */
-public interface ClassDataRetriever {
-
-    public Map<String, String> getClassData(Client client);
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java
deleted file mode 100644
index 8d797ee..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.classdataretrieval.hprof;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData.IHprofDumpHandler;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class GeneralHprofDumpHandler implements IHprofDumpHandler {
-
-    private List<IHprofDumpHandler> handlers = new ArrayList<>();
-
-    public void addHandler(IHprofDumpHandler h) {
-      synchronized (handlers) {
-        handlers.add(h);
-      }
-    }
-
-    public void removeHandler(IHprofDumpHandler h) {
-      synchronized (handlers) {
-        handlers.remove(h);
-      }
-    }
-
-    private List<IHprofDumpHandler> getIterationList() {
-      synchronized (handlers) {
-        return new ArrayList<>(handlers);
-      }
-    }
-
-    @Override
-    public void onEndFailure(Client arg0, String arg1) {
-      List<IHprofDumpHandler> iterList = getIterationList();
-      for (IHprofDumpHandler h : iterList) {
-        h.onEndFailure(arg0, arg1);
-      }
-    }
-
-    @Override
-    public void onSuccess(String arg0, Client arg1) {
-      List<IHprofDumpHandler> iterList = getIterationList();
-      for (IHprofDumpHandler h : iterList) {
-        h.onSuccess(arg0, arg1);
-      }
-    }
-
-    @Override
-    public void onSuccess(byte[] arg0, Client arg1) {
-      List<IHprofDumpHandler> iterList = getIterationList();
-      for (IHprofDumpHandler h : iterList) {
-        h.onSuccess(arg0, arg1);
-      }
-    }
-  }
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java
deleted file mode 100644
index 84ec8b7..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.classdataretrieval.hprof;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-import com.android.ddmlib.ClientData.IHprofDumpHandler;
-import com.android.preload.classdataretrieval.ClassDataRetriever;
-import com.android.preload.ui.NullProgressMonitor;
-import com.android.tools.perflib.captures.MemoryMappedFileBuffer;
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Queries;
-import com.android.tools.perflib.heap.Snapshot;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-public class Hprof implements ClassDataRetriever {
-
-    private static GeneralHprofDumpHandler hprofHandler;
-
-    public static void init() {
-        synchronized(Hprof.class) {
-            if (hprofHandler == null) {
-                ClientData.setHprofDumpHandler(hprofHandler = new GeneralHprofDumpHandler());
-            }
-        }
-    }
-
-    public static File doHprof(Client client, int timeout) {
-        GetHprof gh = new GetHprof(client, timeout);
-        return gh.get();
-    }
-
-    /**
-     * Return a map of class names to class-loader names derived from the hprof dump.
-     *
-     * @param hprofLocalFile
-     */
-    public static Map<String, String> analyzeHprof(File hprofLocalFile) throws Exception {
-        Snapshot snapshot = Snapshot.createSnapshot(new MemoryMappedFileBuffer(hprofLocalFile));
-
-        Map<String, Set<ClassObj>> classes = Queries.classes(snapshot, null);
-        Map<String, String> retValue = new HashMap<String, String>();
-        for (Map.Entry<String, Set<ClassObj>> e : classes.entrySet()) {
-            for (ClassObj c : e.getValue()) {
-                String cl = c.getClassLoader() == null ? null : c.getClassLoader().toString();
-                String cName = c.getClassName();
-                int aDepth = 0;
-                while (cName.endsWith("[]")) {
-                    cName = cName.substring(0, cName.length()-2);
-                    aDepth++;
-                }
-                String newName = transformPrimitiveClass(cName);
-                if (aDepth > 0) {
-                    // Need to use kind-a descriptor syntax. If it was transformed, it is primitive.
-                    if (newName.equals(cName)) {
-                        newName = "L" + newName + ";";
-                    }
-                    for (int i = 0; i < aDepth; i++) {
-                        newName = "[" + newName;
-                    }
-                }
-                retValue.put(newName, cl);
-            }
-        }
-
-        // Free up memory.
-        snapshot.dispose();
-
-        return retValue;
-    }
-
-    private static Map<String, String> primitiveMapping;
-
-    static {
-        primitiveMapping = new HashMap<>();
-        primitiveMapping.put("boolean", "Z");
-        primitiveMapping.put("byte", "B");
-        primitiveMapping.put("char", "C");
-        primitiveMapping.put("double", "D");
-        primitiveMapping.put("float", "F");
-        primitiveMapping.put("int", "I");
-        primitiveMapping.put("long", "J");
-        primitiveMapping.put("short", "S");
-        primitiveMapping.put("void", "V");
-    }
-
-    private static String transformPrimitiveClass(String name) {
-        String rep = primitiveMapping.get(name);
-        if (rep != null) {
-            return rep;
-        }
-        return name;
-    }
-
-    private static class GetHprof implements IHprofDumpHandler {
-
-        private File target;
-        private long timeout;
-        private Client client;
-
-        public GetHprof(Client client, long timeout) {
-            this.client = client;
-            this.timeout = timeout;
-        }
-
-        public File get() {
-            synchronized (this) {
-                hprofHandler.addHandler(this);
-                client.dumpHprof();
-                if (target == null) {
-                    try {
-                        wait(timeout);
-                    } catch (Exception e) {
-                        System.out.println(e);
-                    }
-                }
-            }
-
-            hprofHandler.removeHandler(this);
-            return target;
-        }
-
-        private void wakeUp() {
-            synchronized (this) {
-                notifyAll();
-            }
-        }
-
-        @Override
-        public void onEndFailure(Client arg0, String arg1) {
-            System.out.println("GetHprof.onEndFailure");
-            if (client == arg0) {
-                wakeUp();
-            }
-        }
-
-        private static File createTargetFile() {
-            try {
-                return File.createTempFile("ddms", ".hprof");
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        @Override
-        public void onSuccess(String arg0, Client arg1) {
-            System.out.println("GetHprof.onSuccess");
-            if (client == arg1) {
-                try {
-                    target = createTargetFile();
-                    arg1.getDevice().getSyncService().pullFile(arg0,
-                            target.getAbsoluteFile().toString(), new NullProgressMonitor());
-                } catch (Exception e) {
-                    if (target != null) {
-                        target.delete();
-                    }
-                    e.printStackTrace();
-                    target = null;
-                }
-                wakeUp();
-            }
-        }
-
-        @Override
-        public void onSuccess(byte[] arg0, Client arg1) {
-            System.out.println("GetHprof.onSuccess");
-            if (client == arg1) {
-                try {
-                    target = createTargetFile();
-                    BufferedOutputStream out =
-                            new BufferedOutputStream(new FileOutputStream(target));
-                    out.write(arg0);
-                    out.close();
-                } catch (Exception e) {
-                    if (target != null) {
-                        target.delete();
-                    }
-                    e.printStackTrace();
-                    target = null;
-                }
-                wakeUp();
-            }
-        }
-    }
-
-    private int timeout;
-
-    public Hprof(int timeout) {
-        this.timeout = timeout;
-    }
-
-    @Override
-    public Map<String, String> getClassData(Client client) {
-        File hprofLocalFile = Hprof.doHprof(client, timeout);
-        if (hprofLocalFile == null) {
-            throw new RuntimeException("Failed getting dump...");
-        }
-        System.out.println("Dump file is " + hprofLocalFile);
-
-        try {
-            return analyzeHprof(hprofLocalFile);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        } finally {
-            hprofLocalFile.delete();
-        }
-    }
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java
deleted file mode 100644
index dbd4c89..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.classdataretrieval.jdwp;
-
-import com.android.ddmlib.Client;
-import com.android.preload.classdataretrieval.ClassDataRetriever;
-
-import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
-import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
-import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
-import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
-import org.apache.harmony.jpda.tests.jdwp.share.JDWPTestCase;
-import org.apache.harmony.jpda.tests.jdwp.share.JDWPUnitDebuggeeWrapper;
-import org.apache.harmony.jpda.tests.share.JPDALogWriter;
-import org.apache.harmony.jpda.tests.share.JPDATestOptions;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class JDWPClassDataRetriever extends JDWPTestCase implements ClassDataRetriever {
-
-    private final Client client;
-
-    public JDWPClassDataRetriever() {
-        this(null);
-    }
-
-    public JDWPClassDataRetriever(Client client) {
-        this.client = client;
-    }
-
-
-    @Override
-    protected String getDebuggeeClassName() {
-        return "<unset>";
-    }
-
-    @Override
-    public Map<String, String> getClassData(Client client) {
-        return new JDWPClassDataRetriever(client).retrieve();
-    }
-
-    private Map<String, String> retrieve() {
-        if (client == null) {
-            throw new IllegalStateException();
-        }
-
-        settings = createTestOptions("localhost:" + String.valueOf(client.getDebuggerListenPort()));
-        settings.setDebuggeeSuspend("n");
-
-        logWriter = new JPDALogWriter(System.out, "", false);
-
-        try {
-            internalSetUp();
-
-            return retrieveImpl();
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        } finally {
-            internalTearDown();
-        }
-    }
-
-    private Map<String, String> retrieveImpl() {
-        try {
-            // Suspend the app.
-            {
-                CommandPacket packet = new CommandPacket(
-                        JDWPCommands.VirtualMachineCommandSet.CommandSetID,
-                        JDWPCommands.VirtualMachineCommandSet.SuspendCommand);
-                ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
-                if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
-                    return null;
-                }
-            }
-
-            // List all classes.
-            CommandPacket packet = new CommandPacket(
-                    JDWPCommands.VirtualMachineCommandSet.CommandSetID,
-                    JDWPCommands.VirtualMachineCommandSet.AllClassesCommand);
-            ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
-
-            if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
-                return null;
-            }
-
-            int classCount = reply.getNextValueAsInt();
-            System.out.println("Runtime reported " + classCount + " classes.");
-
-            Map<Long, String> classes = new HashMap<Long, String>();
-            Map<Long, String> arrayClasses = new HashMap<Long, String>();
-
-            for (int i = 0; i < classCount; i++) {
-                byte refTypeTag = reply.getNextValueAsByte();
-                long typeID = reply.getNextValueAsReferenceTypeID();
-                String signature = reply.getNextValueAsString();
-                /* int status = */ reply.getNextValueAsInt();
-
-                switch (refTypeTag) {
-                    case JDWPConstants.TypeTag.CLASS:
-                    case JDWPConstants.TypeTag.INTERFACE:
-                        classes.put(typeID, signature);
-                        break;
-
-                    case JDWPConstants.TypeTag.ARRAY:
-                        arrayClasses.put(typeID, signature);
-                        break;
-                }
-            }
-
-            Map<String, String> result = new HashMap<String, String>();
-
-            // Parse all classes.
-            for (Map.Entry<Long, String> entry : classes.entrySet()) {
-                long typeID = entry.getKey();
-                String signature = entry.getValue();
-
-                if (!checkClass(typeID, signature, result)) {
-                    System.err.println("Issue investigating " + signature);
-                }
-            }
-
-            // For arrays, look at the leaf component type.
-            for (Map.Entry<Long, String> entry : arrayClasses.entrySet()) {
-                long typeID = entry.getKey();
-                String signature = entry.getValue();
-
-                if (!checkArrayClass(typeID, signature, result)) {
-                    System.err.println("Issue investigating " + signature);
-                }
-            }
-
-            return result;
-        } finally {
-            // Resume the app.
-            {
-                CommandPacket packet = new CommandPacket(
-                        JDWPCommands.VirtualMachineCommandSet.CommandSetID,
-                        JDWPCommands.VirtualMachineCommandSet.ResumeCommand);
-                /* ReplyPacket reply = */ debuggeeWrapper.vmMirror.performCommand(packet);
-            }
-        }
-    }
-
-    private boolean checkClass(long typeID, String signature, Map<String, String> result) {
-        CommandPacket packet = new CommandPacket(
-                JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
-                JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand);
-        packet.setNextValueAsReferenceTypeID(typeID);
-        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
-        if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
-            return false;
-        }
-
-        long classLoaderID = reply.getNextValueAsObjectID();
-
-        // TODO: Investigate the classloader to have a better string?
-        String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID);
-
-        result.put(getClassName(signature), classLoaderString);
-
-        return true;
-    }
-
-    private boolean checkArrayClass(long typeID, String signature, Map<String, String> result) {
-        // Classloaders of array classes are the same as the component class'.
-        CommandPacket packet = new CommandPacket(
-                JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
-                JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand);
-        packet.setNextValueAsReferenceTypeID(typeID);
-        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
-        if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
-            return false;
-        }
-
-        long classLoaderID = reply.getNextValueAsObjectID();
-
-        // TODO: Investigate the classloader to have a better string?
-        String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID);
-
-        // For array classes, we *need* the signature directly.
-        result.put(signature, classLoaderString);
-
-        return true;
-    }
-
-    private static String getClassName(String signature) {
-        String withoutLAndSemicolon = signature.substring(1, signature.length() - 1);
-        return withoutLAndSemicolon.replace('/', '.');
-    }
-
-
-    private static JPDATestOptions createTestOptions(String address) {
-        JPDATestOptions options = new JPDATestOptions();
-        options.setAttachConnectorKind();
-        options.setTimeout(1000);
-        options.setWaitingTime(1000);
-        options.setTransportAddress(address);
-        return options;
-    }
-
-    @Override
-    protected JDWPUnitDebuggeeWrapper createDebuggeeWrapper() {
-        return new PreloadDebugeeWrapper(settings, logWriter);
-    }
-}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java
deleted file mode 100644
index b9df6d0..0000000
--- a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.classdataretrieval.jdwp;
-
-import org.apache.harmony.jpda.tests.framework.LogWriter;
-import org.apache.harmony.jpda.tests.jdwp.share.JDWPManualDebuggeeWrapper;
-import org.apache.harmony.jpda.tests.share.JPDATestOptions;
-
-import java.io.IOException;
-
-public class PreloadDebugeeWrapper extends JDWPManualDebuggeeWrapper {
-
-    public PreloadDebugeeWrapper(JPDATestOptions options, LogWriter writer) {
-        super(options, writer);
-    }
-
-    @Override
-    protected Process launchProcess(String cmdLine) throws IOException {
-        return null;
-    }
-
-    @Override
-    protected void WaitForProcessExit(Process process) {
-    }
-
-}
diff --git a/tools/preload2/src/com/android/preload/ui/IUI.java b/tools/preload2/src/com/android/preload/ui/IUI.java
deleted file mode 100644
index 9371463..0000000
--- a/tools/preload2/src/com/android/preload/ui/IUI.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.android.preload.ui;
-
-import com.android.ddmlib.Client;
-import java.io.File;
-import java.util.List;
-import javax.swing.Action;
-import javax.swing.ListModel;
-import javax.swing.table.TableModel;
-
-/**
- * UI abstraction for the tool. This allows a graphical mode, command line mode,
- * or silent mode.
- */
-public interface IUI {
-
-    void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
-            List<Action> actions);
-
-    void ready();
-
-    boolean isSingleThreaded();
-
-    Client getSelectedClient();
-
-    int getSelectedDataTableRow();
-
-    void showWaitDialog();
-
-    void updateWaitDialog(String s);
-
-    void hideWaitDialog();
-
-    void showMessageDialog(String s);
-
-    boolean showConfirmDialog(String title, String message);
-
-    String showInputDialog(String message);
-
-    <T> T showChoiceDialog(String title, String message, T[] choices);
-
-    File showSaveDialog();
-
-    File[] showOpenDialog(boolean multi);
-
-}
diff --git a/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java b/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java
deleted file mode 100644
index f45aad0..0000000
--- a/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.ui;
-
-import com.android.ddmlib.SyncService.ISyncProgressMonitor;
-
-public class NullProgressMonitor implements ISyncProgressMonitor {
-
-    @Override
-    public void advance(int arg0) {}
-
-    @Override
-    public boolean isCanceled() {
-        return false;
-    }
-
-    @Override
-    public void start(int arg0) {}
-
-    @Override
-    public void startSubTask(String arg0) {}
-
-    @Override
-    public void stop() {}
-}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/ui/SequenceUI.java b/tools/preload2/src/com/android/preload/ui/SequenceUI.java
deleted file mode 100644
index dc6a4f3..0000000
--- a/tools/preload2/src/com/android/preload/ui/SequenceUI.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package com.android.preload.ui;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-import java.io.File;
-import java.util.LinkedList;
-import java.util.List;
-import javax.swing.Action;
-import javax.swing.ListModel;
-import javax.swing.table.TableModel;
-
-public class SequenceUI implements IUI {
-
-    private ListModel<Client> clientListModel;
-    @SuppressWarnings("unused")
-    private TableModel dataTableModel;
-    private List<Action> actions;
-
-    private List<Object> sequence = new LinkedList<>();
-
-    public SequenceUI() {
-    }
-
-    @Override
-    public boolean isSingleThreaded() {
-        return true;
-    }
-
-    @Override
-    public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
-            List<Action> actions) {
-        this.clientListModel = clientListModel;
-        this.dataTableModel = dataTableModel;
-        this.actions = actions;
-    }
-
-    public SequenceUI action(Action a) {
-        sequence.add(a);
-        return this;
-    }
-
-    public SequenceUI action(Class<? extends Action> actionClass) {
-        for (Action a : actions) {
-            if (actionClass.equals(a.getClass())) {
-                sequence.add(a);
-                return this;
-            }
-        }
-        throw new IllegalArgumentException("No action of class " + actionClass + " found.");
-    }
-
-    public SequenceUI confirmYes() {
-        sequence.add(Boolean.TRUE);
-        return this;
-    }
-
-    public SequenceUI confirmNo() {
-        sequence.add(Boolean.FALSE);
-        return this;
-    }
-
-    public SequenceUI input(String input) {
-        sequence.add(input);
-        return this;
-    }
-
-    public SequenceUI input(File... f) {
-        sequence.add(f);
-        return this;
-    }
-
-    public SequenceUI output(File f) {
-        sequence.add(f);
-        return this;
-    }
-
-    public SequenceUI tableRow(int i) {
-        sequence.add(i);
-        return this;
-    }
-
-    private class ClientSelector {
-        private String pkg;
-
-        public ClientSelector(String pkg) {
-            this.pkg = pkg;
-        }
-
-        public Client getClient() {
-            for (int i = 0; i < clientListModel.getSize(); i++) {
-                ClientData cd = clientListModel.getElementAt(i).getClientData();
-                if (cd != null) {
-                    String s = cd.getClientDescription();
-                    if (pkg.equals(s)) {
-                        return clientListModel.getElementAt(i);
-                    }
-                }
-            }
-            throw new RuntimeException("Didn't find client " + pkg);
-        }
-    }
-
-    public SequenceUI client(String pkg) {
-        sequence.add(new ClientSelector(pkg));
-        return this;
-    }
-
-    public SequenceUI choice(String pattern) {
-        sequence.add(pattern);
-        return this;
-    }
-
-    @Override
-    public void ready() {
-        // Run the actions.
-        // No iterator or foreach loop as the sequence will be emptied while running.
-        try {
-            while (!sequence.isEmpty()) {
-                Object next = sequence.remove(0);
-                if (next instanceof Action) {
-                    ((Action)next).actionPerformed(null);
-                } else {
-                    throw new IllegalStateException("Didn't expect a non-action: " + next);
-                }
-            }
-        } catch (Exception e) {
-            e.printStackTrace(System.out);
-        }
-
-        // Now shut down.
-        System.exit(0);
-    }
-
-    @Override
-    public Client getSelectedClient() {
-        Object next = sequence.remove(0);
-        if (next instanceof ClientSelector) {
-            return ((ClientSelector)next).getClient();
-        }
-        throw new IllegalStateException("Unexpected: " + next);
-    }
-
-    @Override
-    public int getSelectedDataTableRow() {
-        Object next = sequence.remove(0);
-        if (next instanceof Integer) {
-            return ((Integer)next).intValue();
-        }
-        throw new IllegalStateException("Unexpected: " + next);
-    }
-
-    @Override
-    public void showWaitDialog() {
-    }
-
-    @Override
-    public void updateWaitDialog(String s) {
-        System.out.println(s);
-    }
-
-    @Override
-    public void hideWaitDialog() {
-    }
-
-    @Override
-    public void showMessageDialog(String s) {
-        System.out.println(s);
-    }
-
-    @Override
-    public boolean showConfirmDialog(String title, String message) {
-        Object next = sequence.remove(0);
-        if (next instanceof Boolean) {
-            return ((Boolean)next).booleanValue();
-        }
-        throw new IllegalStateException("Unexpected: " + next);
-    }
-
-    @Override
-    public String showInputDialog(String message) {
-        Object next = sequence.remove(0);
-        if (next instanceof String) {
-            return (String)next;
-        }
-        throw new IllegalStateException("Unexpected: " + next);
-    }
-
-    @Override
-    public <T> T showChoiceDialog(String title, String message, T[] choices) {
-        Object next = sequence.remove(0);
-        if (next instanceof String) {
-            String s = (String)next;
-            for (T t : choices) {
-                if (t.toString().contains(s)) {
-                    return t;
-                }
-            }
-            return null;
-        }
-        throw new IllegalStateException("Unexpected: " + next);
-    }
-
-    @Override
-    public File showSaveDialog() {
-        Object next = sequence.remove(0);
-        if (next instanceof File) {
-            System.out.println(next);
-            return (File)next;
-        }
-        throw new IllegalStateException("Unexpected: " + next);
-    }
-
-    @Override
-    public File[] showOpenDialog(boolean multi) {
-        Object next = sequence.remove(0);
-        if (next instanceof File[]) {
-            return (File[])next;
-        }
-        throw new IllegalStateException("Unexpected: " + next);
-    }
-
-}
diff --git a/tools/preload2/src/com/android/preload/ui/SwingUI.java b/tools/preload2/src/com/android/preload/ui/SwingUI.java
deleted file mode 100644
index cab3744..0000000
--- a/tools/preload2/src/com/android/preload/ui/SwingUI.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.preload.ui;
-
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.io.File;
-import java.util.List;
-
-import javax.swing.Action;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JDialog;
-import javax.swing.JFileChooser;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JProgressBar;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.JToolBar;
-import javax.swing.ListModel;
-import javax.swing.SwingUtilities;
-import javax.swing.table.TableModel;
-
-public class SwingUI extends JFrame implements IUI {
-
-    private JList<Client> clientList;
-    private JTable dataTable;
-
-    // Shared file chooser, means the directory is retained.
-    private JFileChooser jfc;
-
-    public SwingUI() {
-        super("Preloaded-classes computation");
-    }
-
-    @Override
-    public boolean isSingleThreaded() {
-        return false;
-    }
-
-    @Override
-    public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
-            List<Action> actions) {
-        getContentPane().add(new JScrollPane(clientList = new JList<Client>(clientListModel)),
-                BorderLayout.WEST);
-        clientList.setCellRenderer(new ClientListCellRenderer());
-        // clientList.addListSelectionListener(listener);
-
-        dataTable = new JTable(dataTableModel);
-        getContentPane().add(new JScrollPane(dataTable), BorderLayout.CENTER);
-
-        JToolBar toolbar = new JToolBar(JToolBar.HORIZONTAL);
-        for (Action a : actions) {
-            if (a == null) {
-                toolbar.addSeparator();
-            } else {
-                toolbar.add(a);
-            }
-        }
-        getContentPane().add(toolbar, BorderLayout.PAGE_START);
-
-        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-        setBounds(100, 100, 800, 600);
-
-        setVisible(true);
-    }
-
-    @Override
-    public void ready() {
-    }
-
-    @Override
-    public Client getSelectedClient() {
-        return clientList.getSelectedValue();
-    }
-
-    @Override
-    public int getSelectedDataTableRow() {
-        return dataTable.getSelectedRow();
-    }
-
-    private JDialog currentWaitDialog = null;
-
-    @Override
-    public void showWaitDialog() {
-        if (currentWaitDialog == null) {
-            currentWaitDialog = new JDialog(this, "Please wait...", true);
-            currentWaitDialog.getContentPane().add(new JLabel("Please be patient."),
-                    BorderLayout.CENTER);
-            JProgressBar progress = new JProgressBar(JProgressBar.HORIZONTAL);
-            progress.setIndeterminate(true);
-            currentWaitDialog.getContentPane().add(progress, BorderLayout.SOUTH);
-            currentWaitDialog.setSize(200, 100);
-            currentWaitDialog.setLocationRelativeTo(null);
-            showWaitDialogLater();
-        }
-    }
-
-    private void showWaitDialogLater() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                if (currentWaitDialog != null) {
-                    currentWaitDialog.setVisible(true); // This is blocking.
-                }
-            }
-        });
-    }
-
-    @Override
-    public void updateWaitDialog(String s) {
-        if (currentWaitDialog != null) {
-            ((JLabel) currentWaitDialog.getContentPane().getComponent(0)).setText(s);
-            Dimension prefSize = currentWaitDialog.getPreferredSize();
-            Dimension curSize = currentWaitDialog.getSize();
-            if (prefSize.width > curSize.width || prefSize.height > curSize.height) {
-                currentWaitDialog.setSize(Math.max(prefSize.width, curSize.width),
-                        Math.max(prefSize.height, curSize.height));
-                currentWaitDialog.invalidate();
-            }
-        }
-    }
-
-    @Override
-    public void hideWaitDialog() {
-        if (currentWaitDialog != null) {
-            currentWaitDialog.setVisible(false);
-            currentWaitDialog = null;
-        }
-    }
-
-    @Override
-    public void showMessageDialog(String s) {
-        // Hide the wait dialog...
-        if (currentWaitDialog != null) {
-            currentWaitDialog.setVisible(false);
-        }
-
-        try {
-            JOptionPane.showMessageDialog(this, s);
-        } finally {
-            // And reshow it afterwards...
-            if (currentWaitDialog != null) {
-                showWaitDialogLater();
-            }
-        }
-    }
-
-    @Override
-    public boolean showConfirmDialog(String title, String message) {
-        // Hide the wait dialog...
-        if (currentWaitDialog != null) {
-            currentWaitDialog.setVisible(false);
-        }
-
-        try {
-            return JOptionPane.showConfirmDialog(this, title, message, JOptionPane.YES_NO_OPTION)
-                    == JOptionPane.YES_OPTION;
-        } finally {
-            // And reshow it afterwards...
-            if (currentWaitDialog != null) {
-                showWaitDialogLater();
-            }
-        }
-    }
-
-    @Override
-    public String showInputDialog(String message) {
-        // Hide the wait dialog...
-        if (currentWaitDialog != null) {
-            currentWaitDialog.setVisible(false);
-        }
-
-        try {
-            return JOptionPane.showInputDialog(message);
-        } finally {
-            // And reshow it afterwards...
-            if (currentWaitDialog != null) {
-                showWaitDialogLater();
-            }
-        }
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <T> T showChoiceDialog(String title, String message, T[] choices) {
-        // Hide the wait dialog...
-        if (currentWaitDialog != null) {
-            currentWaitDialog.setVisible(false);
-        }
-
-        try{
-            return (T)JOptionPane.showInputDialog(this,
-                    title,
-                    message,
-                    JOptionPane.QUESTION_MESSAGE,
-                    null,
-                    choices,
-                    choices[0]);
-        } finally {
-            // And reshow it afterwards...
-            if (currentWaitDialog != null) {
-                showWaitDialogLater();
-            }
-        }
-    }
-
-    @Override
-    public File showSaveDialog() {
-        // Hide the wait dialog...
-        if (currentWaitDialog != null) {
-            currentWaitDialog.setVisible(false);
-        }
-
-        try{
-            if (jfc == null) {
-                jfc = new JFileChooser();
-            }
-
-            int ret = jfc.showSaveDialog(this);
-            if (ret == JFileChooser.APPROVE_OPTION) {
-                return jfc.getSelectedFile();
-            } else {
-                return null;
-            }
-        } finally {
-            // And reshow it afterwards...
-            if (currentWaitDialog != null) {
-                showWaitDialogLater();
-            }
-        }
-    }
-
-    @Override
-    public File[] showOpenDialog(boolean multi) {
-        // Hide the wait dialog...
-        if (currentWaitDialog != null) {
-            currentWaitDialog.setVisible(false);
-        }
-
-        try{
-            if (jfc == null) {
-                jfc = new JFileChooser();
-            }
-
-            jfc.setMultiSelectionEnabled(multi);
-            int ret = jfc.showOpenDialog(this);
-            if (ret == JFileChooser.APPROVE_OPTION) {
-                return jfc.getSelectedFiles();
-            } else {
-                return null;
-            }
-        } finally {
-            // And reshow it afterwards...
-            if (currentWaitDialog != null) {
-                showWaitDialogLater();
-            }
-        }
-    }
-
-    private class ClientListCellRenderer extends DefaultListCellRenderer {
-
-        @Override
-        public Component getListCellRendererComponent(JList<?> list, Object value, int index,
-                boolean isSelected, boolean cellHasFocus) {
-            ClientData cd = ((Client) value).getClientData();
-            String s = cd.getClientDescription() + " (pid " + cd.getPid() + ")";
-            return super.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
-        }
-    }
-}
diff --git a/tools/processors/staledataclass/Android.bp b/tools/processors/staledataclass/Android.bp
new file mode 100644
index 0000000..c81d410
--- /dev/null
+++ b/tools/processors/staledataclass/Android.bp
@@ -0,0 +1,27 @@
+
+java_plugin {
+    name: "staledataclass-annotation-processor",
+    processor_class: "android.processor.staledataclass.StaleDataclassProcessor",
+
+    java_resources: [
+        "META-INF/**/*",
+    ],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "codegen-version-info",
+    ],
+    openjdk9: {
+        javacflags: [
+            "--add-modules=jdk.compiler",
+            "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+            "--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
+            "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+            "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+        ],
+    },
+
+    use_tools_jar: true,
+}
diff --git a/tools/processors/staledataclass/META-INF/services/javax.annotation.processing.Processor b/tools/processors/staledataclass/META-INF/services/javax.annotation.processing.Processor
new file mode 100644
index 0000000..15ee623
--- /dev/null
+++ b/tools/processors/staledataclass/META-INF/services/javax.annotation.processing.Processor
@@ -0,0 +1 @@
+android.processor.staledataclass.StaleDataclassProcessorOld
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
new file mode 100644
index 0000000..9e51180
--- /dev/null
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -0,0 +1,178 @@
+/*
+ * 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.processor.staledataclass
+
+import com.android.codegen.CODEGEN_NAME
+import com.android.codegen.CODEGEN_VERSION
+import com.sun.tools.javac.code.Symbol
+import com.sun.tools.javac.code.Type
+import java.io.File
+import java.io.FileNotFoundException
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.RoundEnvironment
+import javax.annotation.processing.SupportedAnnotationTypes
+import javax.lang.model.SourceVersion
+import javax.lang.model.element.AnnotationMirror
+import javax.lang.model.element.Element
+import javax.lang.model.element.TypeElement
+import javax.tools.Diagnostic
+
+private const val STALE_FILE_THRESHOLD_MS = 1000
+private val WORKING_DIR = File(".").absoluteFile
+
+private const val DATACLASS_ANNOTATION_NAME = "com.android.internal.util.DataClass"
+private const val GENERATED_ANNOTATION_NAME = "com.android.internal.util.DataClass.Generated"
+private const val GENERATED_MEMBER_ANNOTATION_NAME
+        = "com.android.internal.util.DataClass.Generated.Member"
+
+
+@SupportedAnnotationTypes(DATACLASS_ANNOTATION_NAME, GENERATED_ANNOTATION_NAME)
+class StaleDataclassProcessor: AbstractProcessor() {
+
+    private var dataClassAnnotation: TypeElement? = null
+    private var generatedAnnotation: TypeElement? = null
+    private var repoRoot: File? = null
+
+    private val stale = mutableListOf<Stale>()
+
+    /**
+     * This is the main entry point in the processor, called by the compiler.
+     */
+    override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
+
+        if (generatedAnnotation == null) {
+            generatedAnnotation = annotations.find {
+                it.qualifiedName.toString() == GENERATED_ANNOTATION_NAME
+            }
+        }
+        if (dataClassAnnotation == null) {
+            dataClassAnnotation = annotations.find {
+                it.qualifiedName.toString() == DATACLASS_ANNOTATION_NAME
+            }
+        }
+
+        val generatedAnnotatedElements = roundEnv.getElementsAnnotatedWith(generatedAnnotation)
+        generatedAnnotatedElements.forEach {
+            processSingleFile(it)
+        }
+
+
+        val dataClassesWithoutGeneratedPart =
+                roundEnv.getElementsAnnotatedWith(dataClassAnnotation) -
+                        generatedAnnotatedElements.map { it.enclosingElement }
+
+        dataClassesWithoutGeneratedPart.forEach { dataClass ->
+            stale += Stale(dataClass.toString(), file = null, lastGenerated = 0L)
+        }
+
+
+        if (!stale.isEmpty()) {
+            error("Stale generated dataclass(es) detected. " +
+                    "Run the following command(s) to update them:" +
+                    stale.joinToString("") { "\n" + it.refreshCmd })
+        }
+        return true
+    }
+
+    private fun elemToString(elem: Element): String {
+        return buildString {
+            append(elem.modifiers.joinToString(" ") { it.name.toLowerCase() }).append(" ")
+            append(elem.annotationMirrors.joinToString(" ")).append(" ")
+            if (elem is Symbol) {
+                if (elem.type is Type.MethodType) {
+                    append((elem.type as Type.MethodType).returnType)
+                } else {
+                    append(elem.type)
+                }
+                append(" ")
+            }
+            append(elem)
+        }
+    }
+
+    private fun processSingleFile(elementAnnotatedWithGenerated: Element) {
+
+        val inputSignatures = elementAnnotatedWithGenerated
+                .enclosingElement
+                .enclosedElements
+                .filterNot {
+                    it.annotationMirrors.any { "Generated" in it.annotationType.toString() }
+                }.map {
+                    elemToString(it)
+                }.toSet()
+
+        val annotationParams = elementAnnotatedWithGenerated
+                .annotationMirrors
+                .find { ann -> isGeneratedAnnotation(ann) }!!
+                .elementValues
+                .map { (k, v) -> k.getSimpleName().toString() to v.getValue() }
+                .toMap()
+
+        val lastGenerated = annotationParams["time"] as Long
+        val codegenVersion = annotationParams["codegenVersion"] as String
+        val sourceRelative = File(annotationParams["sourceFile"] as String)
+
+        val lastGenInputSignatures = (annotationParams["inputSignatures"] as String).lines().toSet()
+
+        if (repoRoot == null) {
+            repoRoot = generateSequence(WORKING_DIR) { it.parentFile }
+                    .find { it.resolve(sourceRelative).isFile }
+                    ?.canonicalFile
+                    ?: throw FileNotFoundException(
+                            "Failed to detect repository root: " +
+                                    "no parent of $WORKING_DIR contains $sourceRelative")
+        }
+
+        val source = repoRoot!!.resolve(sourceRelative)
+        val clazz = elementAnnotatedWithGenerated.enclosingElement.toString()
+
+        if (inputSignatures != lastGenInputSignatures) {
+            error(buildString {
+                append(sourceRelative).append(":\n")
+                append("  Added:\n").append((inputSignatures-lastGenInputSignatures).joinToString("\n"))
+                append("\n")
+                append("  Removed:\n").append((lastGenInputSignatures-inputSignatures).joinToString("\n"))
+            })
+            stale += Stale(clazz, source, lastGenerated)
+        }
+
+        if (codegenVersion != CODEGEN_VERSION) {
+            stale += Stale(clazz, source, lastGenerated)
+        }
+    }
+
+    private fun error(msg: String) {
+        processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, msg)
+    }
+
+    private fun isGeneratedAnnotation(ann: AnnotationMirror): Boolean {
+        return generatedAnnotation!!.qualifiedName.toString() == ann.annotationType.toString()
+    }
+
+    data class Stale(val clazz: String, val file: File?, val lastGenerated: Long) {
+        val refreshCmd = if (file != null) {
+            "$CODEGEN_NAME $file"
+        } else {
+            "find \$ANDROID_BUILD_TOP -path */${clazz.replace('.', '/')}.java -exec $CODEGEN_NAME {} \\;"
+        }
+    }
+
+    override fun getSupportedSourceVersion(): SourceVersion {
+        return SourceVersion.latest()
+    }
+}
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 9010f3c9..1829baa 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -29,7 +29,6 @@
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ITrafficStateCallback;
 import android.net.wifi.IOnWifiUsabilityStatsListener;
-import android.net.wifi.PasspointManagementObjectDefinition;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.wifi.WifiConfiguration;
diff --git a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl
deleted file mode 100644
index eb7cc39..0000000
--- a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2008, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-parcelable PasspointManagementObjectDefinition;
diff --git a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java
deleted file mode 100644
index 70577b9..0000000
--- a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java
+++ /dev/null
@@ -1,81 +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.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * This object describes a partial tree structure in the Hotspot 2.0 release 2 management object.
- * The object is used during subscription remediation to modify parts of an existing PPS MO
- * tree (Hotspot 2.0 specification section 9.1).
- * @hide
- */
-public class PasspointManagementObjectDefinition implements Parcelable {
-    private final String mBaseUri;
-    private final String mUrn;
-    private final String mMoTree;
-
-    public PasspointManagementObjectDefinition(String baseUri, String urn, String moTree) {
-        mBaseUri = baseUri;
-        mUrn = urn;
-        mMoTree = moTree;
-    }
-
-    public String getBaseUri() {
-        return mBaseUri;
-    }
-
-    public String getUrn() {
-        return mUrn;
-    }
-
-    public String getMoTree() {
-        return mMoTree;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mBaseUri);
-        dest.writeString(mUrn);
-        dest.writeString(mMoTree);
-    }
-
-    /**
-     * Implement the Parcelable interface {@hide}
-     */
-    public static final @android.annotation.NonNull Creator<PasspointManagementObjectDefinition> CREATOR =
-            new Creator<PasspointManagementObjectDefinition>() {
-                public PasspointManagementObjectDefinition createFromParcel(Parcel in) {
-                    return new PasspointManagementObjectDefinition(
-                            in.readString(),    /* base URI */
-                            in.readString(),    /* URN */
-                            in.readString()     /* Tree XML */
-                    );
-                }
-
-                public PasspointManagementObjectDefinition[] newArray(int size) {
-                    return new PasspointManagementObjectDefinition[size];
-                }
-            };
-}
-
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1a16aaa..89ed080 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1691,6 +1691,8 @@
 
     /**
      * Remove some or all of the network suggestions that were previously provided by the app.
+     * If the current network is a suggestion being removed and if it was only provided by this app
+     * and is not a saved network then the framework will immediately disconnect.
      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
      *
diff --git a/wifi/java/android/net/wifi/WpsResult.aidl b/wifi/java/android/net/wifi/WpsResult.aidl
deleted file mode 100644
index eb4c4f5..0000000
--- a/wifi/java/android/net/wifi/WpsResult.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-parcelable WpsResult;
diff --git a/wifi/java/android/net/wifi/WpsResult.java b/wifi/java/android/net/wifi/WpsResult.java
deleted file mode 100644
index f2ffb6f..0000000
--- a/wifi/java/android/net/wifi/WpsResult.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A class representing the result of a WPS request
- * @hide
- */
-public class WpsResult implements Parcelable {
-
-    public enum Status {
-        SUCCESS,
-        FAILURE,
-        IN_PROGRESS,
-    }
-
-    public Status status;
-
-    public String pin;
-
-    public WpsResult() {
-        status = Status.FAILURE;
-        pin = null;
-    }
-
-    public WpsResult(Status s) {
-        status = s;
-        pin = null;
-    }
-
-    public String toString() {
-        StringBuffer sbuf = new StringBuffer();
-        sbuf.append(" status: ").append(status.toString());
-        sbuf.append('\n');
-        sbuf.append(" pin: ").append(pin);
-        sbuf.append("\n");
-        return sbuf.toString();
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** copy constructor {@hide} */
-    public WpsResult(WpsResult source) {
-        if (source != null) {
-            status = source.status;
-            pin = source.pin;
-        }
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(status.name());
-        dest.writeString(pin);
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public static final @android.annotation.NonNull Creator<WpsResult> CREATOR =
-        new Creator<WpsResult>() {
-            public WpsResult createFromParcel(Parcel in) {
-                WpsResult result = new WpsResult();
-                result.status = Status.valueOf(in.readString());
-                result.pin = in.readString();
-                return result;
-            }
-
-            public WpsResult[] newArray(int size) {
-                return new WpsResult[size];
-            }
-        };
-}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl b/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl
deleted file mode 100644
index e923f1f..0000000
--- a/wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.hotspot2.pps;
-
-parcelable Policy;
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
deleted file mode 100644
index 701db47..0000000
--- a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.hotspot2.pps;
-
-parcelable UpdateParameter;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl
deleted file mode 100644
index 3d8a476..0000000
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.aidl
+++ /dev/null
@@ -1,19 +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.
- */
-
-package android.net.wifi.p2p;
-
-parcelable WifiP2pGroupList;
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index cd659e2..d37c4a2 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -190,7 +190,7 @@
      * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in
      * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides
      * the network info in the form of a {@link android.net.NetworkInfo}. A third extra provides
-     * the details of the group.
+     * the details of the group and may contain a {@code null}.
      *
      * All of these permissions are required to receive this broadcast:
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and