Merge "Move SignalDrawable to SettingsLib so every can enjoy it"
diff --git a/Android.bp b/Android.bp
index d5e04f9..05fb3c0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -373,7 +373,6 @@
         "core/java/com/android/internal/appwidget/IAppWidgetHost.aidl",
         "core/java/com/android/internal/backup/IBackupTransport.aidl",
         "core/java/com/android/internal/backup/IObbBackupService.aidl",
-        "core/java/com/android/internal/car/ICarServiceHelper.aidl",
         "core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl",
         "core/java/com/android/internal/net/INetworkWatchlistManager.aidl",
         "core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl",
@@ -579,7 +578,6 @@
         "wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl",
         "wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl",
         "wifi/java/android/net/wifi/IWifiScanner.aidl",
-        "wifi/java/android/net/wifi/IRttManager.aidl",
         "packages/services/PacProcessor/com/android/net/IProxyService.aidl",
         "packages/services/Proxy/com/android/net/IProxyCallback.aidl",
         "packages/services/Proxy/com/android/net/IProxyPortListener.aidl",
@@ -672,8 +670,9 @@
         "android.hardware.tv.input-V1.0-java-constants",
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
-        "android.hardware.vibrator-V1.0-java-constants",
-        "android.hardware.vibrator-V1.1-java-constants",
+        "android.hardware.vibrator-V1.0-java",
+        "android.hardware.vibrator-V1.1-java",
+        "android.hardware.vibrator-V1.2-java",
         "android.hardware.wifi-V1.0-java-constants",
         "android.hardware.radio-V1.0-java",
         "android.hardware.usb.gadget-V1.0-java",
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 711c12d..2a67b75 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,6 +1,7 @@
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
                   -fw core/java/android/
+                      graphics/java/android
                       core/tests/coretests/src/android/
                       packages/PrintRecommendationService/
                       packages/PrintSpooler/
diff --git a/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java
new file mode 100644
index 0000000..f8fd51d
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.perftests.utils.StubActivity;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+// Due to b/71353150, you might get "java.lang.AssertionError: Binder ProxyMap has too many
+// entries", but it's flaky. Adding "Runtime.getRuntime().gc()" between each iteration solves
+// the problem, but it doesn't seem like it's currently needed.
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class PendingIntentPerfTest {
+
+    private Context mContext;
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    private Intent mIntent;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mIntent = StubActivity.createLaunchIntent(mContext);
+    }
+
+    /**
+     * Benchmark time to create a PendingIntent.
+     */
+    @Test
+    public void create() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            state.resumeTiming();
+
+            final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent,
+                    0);
+
+            state.pauseTiming();
+            pendingIntent.cancel();
+            state.resumeTiming();
+        }
+    }
+
+    /**
+     * Benchmark time to create a PendingIntent with FLAG_CANCEL_CURRENT, already having an active
+     * PendingIntent.
+     */
+    @Test
+    public void createWithCancelFlag() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final PendingIntent previousPendingIntent = PendingIntent.getActivity(mContext, 0,
+                    mIntent, 0);
+            state.resumeTiming();
+
+            final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent,
+                    PendingIntent.FLAG_CANCEL_CURRENT);
+
+            state.pauseTiming();
+            pendingIntent.cancel();
+            state.resumeTiming();
+        }
+    }
+
+    /**
+     * Benchmark time to create a PendingIntent with FLAG_UPDATE_CURRENT, already having an active
+     * PendingIntent.
+     */
+    @Test
+    public void createWithUpdateFlag() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final PendingIntent previousPendingIntent = PendingIntent.getActivity(mContext, 0,
+                    mIntent, 0);
+            state.resumeTiming();
+
+            final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent,
+                    PendingIntent.FLAG_UPDATE_CURRENT);
+
+            state.pauseTiming();
+            previousPendingIntent.cancel();
+            pendingIntent.cancel();
+            state.resumeTiming();
+        }
+    }
+
+    /**
+     * Benchmark time to cancel a PendingIntent.
+     */
+    @Test
+    public void cancel() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
+                    mIntent, 0);
+            state.resumeTiming();
+
+            pendingIntent.cancel();
+        }
+    }
+}
+
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java
new file mode 100644
index 0000000..60c6d89
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.text;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class StaticLayoutMultithreadPerfTest {
+    private static final int WORD_LENGTH = 9;  // Random word has 9 characters.
+    private static final int WORDS_IN_LINE = 8;  // Roughly, 8 words in a line.
+    private static final boolean NO_STYLE_TEXT = false;
+
+    private static TextPaint PAINT = new TextPaint();
+    private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
+
+    public StaticLayoutMultithreadPerfTest() {}
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    private CountDownLatch mStartLatch;
+    private AtomicBoolean mThreadState;  // True for running, False for stopped.
+
+    private static final long TIMEOUT_MS = 5000;
+
+    private Thread[] startBackgroundThread(int numOfThreads) {
+        mStartLatch = new CountDownLatch(numOfThreads);
+        mThreadState = new AtomicBoolean(true);
+
+        Thread[] threads = new Thread[numOfThreads];
+        for (int i = 0; i < numOfThreads; ++i) {
+            final int seed = i + 1;
+            threads[i] = new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    final TextPerfUtils util = new TextPerfUtils();
+                    util.resetRandom(seed);
+
+                    mStartLatch.countDown();
+                    while (mThreadState.get()) {
+                        final CharSequence text = util.nextRandomParagraph(
+                                WORD_LENGTH, NO_STYLE_TEXT);
+                        StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+                                .build();
+                    }
+                }
+            });
+        }
+
+        for (int i = 0; i < numOfThreads; ++i) {
+            threads[i].start();
+        }
+
+        try {
+            mStartLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+        return threads;
+    }
+
+    private void finishThreads(Thread[] threads) {
+        mThreadState.set(false);
+        for (Thread thread : threads) {
+            try {
+                thread.join();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        mStartLatch = null;
+        mThreadState = null;
+    }
+
+    private void runRandomTest(int numOfTotalThreads) {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final TextPerfUtils util = new TextPerfUtils();
+        Thread[] threads = startBackgroundThread(numOfTotalThreads - 1);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final CharSequence text = util.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+            state.resumeTiming();
+
+            StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+                    .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
+                    .build();
+        }
+        finishThreads(threads);
+    }
+
+    @Test
+    public void testCreate_RandomText_Thread_1() {
+        runRandomTest(1);
+    }
+
+    @Test
+    public void testCreate_RandomText_Thread_2() {
+        runRandomTest(2);
+    }
+
+    @Test
+    public void testCreate_RandomText_Thread_4() {
+        runRandomTest(4);
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/StubActivity.java b/apct-tests/perftests/utils/src/android/perftests/utils/StubActivity.java
index 6012f4b1..8f03f7e 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/StubActivity.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/StubActivity.java
@@ -17,6 +17,14 @@
 package android.perftests.utils;
 
 import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
 
 public class StubActivity extends Activity {
-}
\ No newline at end of file
+    public static Intent createLaunchIntent(Context context) {
+        final Intent intent = new Intent();
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClass(context, StubActivity.class);
+        return intent;
+    }
+}
diff --git a/api/current.txt b/api/current.txt
index d93bc41..3a82ed2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5711,7 +5711,8 @@
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
     field public static final java.lang.String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
-    field public static final java.lang.String EXTRA_BLOCK_STATE_CHANGED_ID = "android.app.extra.BLOCK_STATE_CHANGED_ID";
+    field public static final java.lang.String EXTRA_NOTIFICATION_CHANNEL_GROUP_ID = "android.app.extra.NOTIFICATION_CHANNEL_GROUP_ID";
+    field public static final java.lang.String EXTRA_NOTIFICATION_CHANNEL_ID = "android.app.extra.NOTIFICATION_CHANNEL_ID";
     field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
     field public static final int IMPORTANCE_HIGH = 4; // 0x4
     field public static final int IMPORTANCE_LOW = 2; // 0x2
@@ -6492,7 +6493,6 @@
     method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
     method public boolean isOverrideApnEnabled(android.content.ComponentName);
     method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public boolean isPrintingEnabled();
     method public boolean isProfileOwnerApp(java.lang.String);
     method public boolean isProvisioningAllowed(java.lang.String);
     method public boolean isResetPasswordTokenActive(android.content.ComponentName);
@@ -6565,7 +6565,6 @@
     method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedCrossProfileNotificationListeners(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
-    method public void setPrintingEnabled(android.content.ComponentName, boolean);
     method public void setProfileEnabled(android.content.ComponentName);
     method public void setProfileName(android.content.ComponentName, java.lang.String);
     method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
@@ -6740,6 +6739,7 @@
     field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
     field public static final int TAG_CERT_AUTHORITY_INSTALLED = 210029; // 0x3346d
     field public static final int TAG_CERT_AUTHORITY_REMOVED = 210030; // 0x3346e
+    field public static final int TAG_CRYPTO_SELF_TEST_COMPLETED = 210031; // 0x3346f
     field public static final int TAG_KEYGUARD_DISABLED_FEATURES_SET = 210021; // 0x33465
     field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
     field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
@@ -6873,6 +6873,7 @@
     method public java.lang.String getIdEntry();
     method public java.lang.String getIdPackage();
     method public java.lang.String getIdType();
+    method public int getImportantForAutofill();
     method public int getInputType();
     method public int getLeft();
     method public android.os.LocaleList getLocaleList();
@@ -14604,7 +14605,7 @@
     method public final android.graphics.Rect copyBounds();
     method public static android.graphics.drawable.Drawable createFromPath(java.lang.String);
     method public static android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, java.lang.String);
-    method public static android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, java.lang.String, android.graphics.BitmapFactory.Options);
+    method public static deprecated android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, java.lang.String, android.graphics.BitmapFactory.Options);
     method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, java.lang.String);
     method public static android.graphics.drawable.Drawable createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.graphics.drawable.Drawable createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -16295,7 +16296,7 @@
 
   public final class TotalCaptureResult extends android.hardware.camera2.CaptureResult {
     method public java.util.List<android.hardware.camera2.CaptureResult> getPartialResults();
-    method public <T> T getPhysicalCameraKey(android.hardware.camera2.CaptureResult.Key<T>, java.lang.String);
+    method public java.util.Map<java.lang.String, android.hardware.camera2.CaptureResult> getPhysicalCameraResults();
   }
 
 }
@@ -23370,6 +23371,7 @@
     method public android.media.MediaDrm.CryptoSession getCryptoSession(byte[], java.lang.String, java.lang.String);
     method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>) throws android.media.NotProvisionedException;
     method public int getMaxHdcpLevel();
+    method public static int getMaxSecurityLevel();
     method public int getMaxSessionCount();
     method public android.os.PersistableBundle getMetrics();
     method public int getOpenSessionCount();
@@ -23383,6 +23385,7 @@
     method public static boolean isCryptoSchemeSupported(java.util.UUID);
     method public static boolean isCryptoSchemeSupported(java.util.UUID, java.lang.String);
     method public byte[] openSession() throws android.media.NotProvisionedException, android.media.ResourceBusyException;
+    method public byte[] openSession(int) throws android.media.NotProvisionedException, android.media.ResourceBusyException;
     method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.NotProvisionedException;
     method public void provideProvisionResponse(byte[]) throws android.media.DeniedByServerException;
     method public java.util.HashMap<java.lang.String, java.lang.String> queryKeyStatus(byte[]);
@@ -23398,7 +23401,6 @@
     method public void setOnKeyStatusChangeListener(android.media.MediaDrm.OnKeyStatusChangeListener, android.os.Handler);
     method public void setPropertyByteArray(java.lang.String, byte[]);
     method public void setPropertyString(java.lang.String, java.lang.String);
-    method public void setSecurityLevel(byte[], int);
     field public static final deprecated int EVENT_KEY_EXPIRED = 3; // 0x3
     field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
     field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
@@ -33139,6 +33141,7 @@
     field public static final java.lang.String DISALLOW_NETWORK_RESET = "no_network_reset";
     field public static final java.lang.String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
     field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
+    field public static final java.lang.String DISALLOW_PRINTING = "no_printing";
     field public static final java.lang.String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
@@ -36772,6 +36775,13 @@
     field public static final java.lang.String ADDRESS = "address";
   }
 
+  public static final class Telephony.CarrierIdentification implements android.provider.BaseColumns {
+    method public static android.net.Uri getUriForSubscriptionId(int);
+    field public static final java.lang.String CID = "carrier_id";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String NAME = "carrier_name";
+  }
+
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final java.lang.String APN = "apn";
     field public static final java.lang.String AUTH_TYPE = "authtype";
@@ -40504,6 +40514,7 @@
   public final class Call {
     method public void answer(int);
     method public void conference(android.telecom.Call);
+    method public void deflect(android.net.Uri);
     method public void disconnect();
     method public java.util.List<java.lang.String> getCannedTextResponses();
     method public java.util.List<android.telecom.Call> getChildren();
@@ -40614,6 +40625,7 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 3072; // 0xc00
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 1024; // 0x400
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
+    field public static final int CAPABILITY_SUPPORT_DEFLECT = 16777216; // 0x1000000
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
     field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200
@@ -40761,6 +40773,7 @@
     method public void onAnswer();
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallEvent(java.lang.String, android.os.Bundle);
+    method public void onDeflect(android.net.Uri);
     method public void onDisconnect();
     method public void onExtrasChanged(android.os.Bundle);
     method public void onHandoverComplete();
@@ -40829,6 +40842,7 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 3072; // 0xc00
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 1024; // 0x400
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
+    field public static final int CAPABILITY_SUPPORT_DEFLECT = 33554432; // 0x2000000
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
     field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
@@ -44897,6 +44911,7 @@
     method public abstract int getAttributeListValue(int, java.lang.String[], int);
     method public abstract java.lang.String getAttributeName(int);
     method public abstract int getAttributeNameResource(int);
+    method public default java.lang.String getAttributeNamespace(int);
     method public abstract int getAttributeResourceValue(java.lang.String, java.lang.String, int);
     method public abstract int getAttributeResourceValue(int, int);
     method public abstract int getAttributeUnsignedIntValue(java.lang.String, java.lang.String, int);
@@ -48146,8 +48161,6 @@
     method public void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
     method public final void offsetDescendantRectToMyCoords(android.view.View, android.graphics.Rect);
     method public final void offsetRectIntoDescendantCoords(android.view.View, android.graphics.Rect);
-    method protected void onDebugDraw(android.graphics.Canvas);
-    method protected void onDebugDrawMargins(android.graphics.Canvas, android.graphics.Paint);
     method public boolean onInterceptHoverEvent(android.view.MotionEvent);
     method public boolean onInterceptTouchEvent(android.view.MotionEvent);
     method protected abstract void onLayout(boolean, int, int, int, int);
@@ -48221,7 +48234,6 @@
     ctor public ViewGroup.LayoutParams(android.content.Context, android.util.AttributeSet);
     ctor public ViewGroup.LayoutParams(int, int);
     ctor public ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams);
-    method public void onDebugDraw(android.view.View, android.graphics.Canvas, android.graphics.Paint);
     method public void resolveLayoutDirection(int);
     method protected void setBaseAttributes(android.content.res.TypedArray, int, int);
     field public static final deprecated int FILL_PARENT = -1; // 0xffffffff
@@ -48409,6 +48421,7 @@
     method public abstract void setHint(java.lang.CharSequence);
     method public abstract void setHtmlInfo(android.view.ViewStructure.HtmlInfo);
     method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String);
+    method public void setImportantForAutofill(int);
     method public abstract void setInputType(int);
     method public abstract void setLocaleList(android.os.LocaleList);
     method public abstract void setLongClickable(boolean);
@@ -50361,7 +50374,7 @@
     method public final void logSelectionModifiedEvent(int, int);
     method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
     method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
-    method public final void logSelectionStartedEvent(int);
+    method public final void logSelectionStartedEvent(int, int);
     method public abstract void writeEvent(android.view.textclassifier.logging.SelectionEvent);
     field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
     field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
@@ -50391,6 +50404,7 @@
     method public int getEventIndex();
     method public long getEventTime();
     method public int getEventType();
+    method public int getInvocationMethod();
     method public java.lang.String getPackageName();
     method public java.lang.String getSessionId();
     method public java.lang.String getSignature();
@@ -50415,6 +50429,8 @@
     field public static final int EVENT_SELECTION_STARTED = 1; // 0x1
     field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4
     field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
+    field public static final int INVOCATION_LINK = 2; // 0x2
+    field public static final int INVOCATION_MANUAL = 1; // 0x1
   }
 
 }
diff --git a/api/system-current.txt b/api/system-current.txt
index 70148d9..71df272 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30,8 +30,8 @@
     field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
     field public static final java.lang.String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
     field public static final java.lang.String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
-    field public static final java.lang.String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
     field public static final java.lang.String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
+    field public static final java.lang.String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
     field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
     field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
     field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
@@ -362,10 +362,12 @@
 
   public final class StatsManager {
     method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String);
+    method public boolean addConfiguration(long, byte[]);
     method public byte[] getData(long);
     method public byte[] getMetadata();
     method public boolean removeConfiguration(long);
     method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
+    method public boolean setDataFetchOperation(long, android.app.PendingIntent);
     field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
     field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
     field public static final java.lang.String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
@@ -687,6 +689,12 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService";
   }
 
+  public static final class UsageEvents.Event {
+    method public int getStandbyBucket();
+    field public static final int NOTIFICATION_SEEN = 10; // 0xa
+    field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
+  }
+
   public final class UsageStatsManager {
     method public int getAppStandbyBucket(java.lang.String);
     method public java.util.Map<java.lang.String, java.lang.Integer> getAppStandbyBuckets();
@@ -791,7 +799,7 @@
     field public static final java.lang.String STATS_MANAGER = "stats";
     field public static final java.lang.String SYSTEM_UPDATE_SERVICE = "system_update";
     field public static final java.lang.String VR_SERVICE = "vrmanager";
-    field public static final java.lang.String WIFI_RTT_SERVICE = "rttmanager";
+    field public static final deprecated java.lang.String WIFI_RTT_SERVICE = "rttmanager";
     field public static final java.lang.String WIFI_SCANNING_SERVICE = "wifiscanner";
   }
 
@@ -821,6 +829,7 @@
     field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
     field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
     field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
+    field public static final java.lang.String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
     field public static final java.lang.String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
     field public static final java.lang.String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
     field public static final java.lang.String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
@@ -2516,6 +2525,7 @@
     method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
     method public deprecated int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
     method public int requestAudioFocus(android.media.AudioFocusRequest, android.media.audiopolicy.AudioPolicy);
+    method public void setFocusRequestResult(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy);
     method public void unregisterAudioPolicyAsync(android.media.audiopolicy.AudioPolicy);
     field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
     field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
@@ -3090,7 +3100,7 @@
 
 package android.net.wifi {
 
-  public class RttManager {
+  public deprecated class RttManager {
     method public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
     method public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
     method public deprecated android.net.wifi.RttManager.Capabilities getCapabilities();
@@ -3166,22 +3176,22 @@
     field public int supportedType;
   }
 
-  public static class RttManager.ParcelableRttParams implements android.os.Parcelable {
+  public static deprecated class RttManager.ParcelableRttParams implements android.os.Parcelable {
     field public android.net.wifi.RttManager.RttParams[] mParams;
   }
 
-  public static class RttManager.ParcelableRttResults implements android.os.Parcelable {
+  public static deprecated class RttManager.ParcelableRttResults implements android.os.Parcelable {
     ctor public RttManager.ParcelableRttResults(android.net.wifi.RttManager.RttResult[]);
     field public android.net.wifi.RttManager.RttResult[] mResults;
   }
 
-  public static abstract class RttManager.ResponderCallback {
+  public static abstract deprecated class RttManager.ResponderCallback {
     ctor public RttManager.ResponderCallback();
     method public abstract void onResponderEnableFailure(int);
     method public abstract void onResponderEnabled(android.net.wifi.RttManager.ResponderConfig);
   }
 
-  public static class RttManager.ResponderConfig implements android.os.Parcelable {
+  public static deprecated class RttManager.ResponderConfig implements android.os.Parcelable {
     ctor public RttManager.ResponderConfig();
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -3194,7 +3204,7 @@
     field public int preamble;
   }
 
-  public static class RttManager.RttCapabilities implements android.os.Parcelable {
+  public static deprecated class RttManager.RttCapabilities implements android.os.Parcelable {
     ctor public RttManager.RttCapabilities();
     field public int bwSupported;
     field public boolean lciSupported;
@@ -3209,13 +3219,13 @@
     field public boolean twoSided11McRttSupported;
   }
 
-  public static abstract interface RttManager.RttListener {
+  public static abstract deprecated interface RttManager.RttListener {
     method public abstract void onAborted();
     method public abstract void onFailure(int, java.lang.String);
     method public abstract void onSuccess(android.net.wifi.RttManager.RttResult[]);
   }
 
-  public static class RttManager.RttParams {
+  public static deprecated class RttManager.RttParams {
     ctor public RttManager.RttParams();
     field public boolean LCIRequest;
     field public boolean LCRRequest;
@@ -3239,7 +3249,7 @@
     field public boolean secure;
   }
 
-  public static class RttManager.RttResult {
+  public static deprecated class RttManager.RttResult {
     ctor public RttManager.RttResult();
     field public android.net.wifi.RttManager.WifiInformationElement LCI;
     field public android.net.wifi.RttManager.WifiInformationElement LCR;
@@ -3276,7 +3286,7 @@
     field public deprecated int tx_rate;
   }
 
-  public static class RttManager.WifiInformationElement {
+  public static deprecated class RttManager.WifiInformationElement {
     ctor public RttManager.WifiInformationElement();
     field public byte[] data;
     field public byte id;
@@ -3796,6 +3806,7 @@
     method public void resume();
     method public void suspend();
     method public boolean unbind();
+    method public boolean verifyPayloadMetadata(java.lang.String);
   }
 
   public static final class UpdateEngine.ErrorCodeConstants {
@@ -5034,22 +5045,19 @@
   }
 
   public class UiccSlotInfo implements android.os.Parcelable {
-    ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int);
+    ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int);
     method public int describeContents();
     method public java.lang.String getCardId();
     method public int getCardStateInfo();
     method public boolean getIsActive();
     method public boolean getIsEuicc();
+    method public int getLogicalSlotIdx();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1
     field public static final int CARD_STATE_INFO_ERROR = 3; // 0x3
     field public static final int CARD_STATE_INFO_PRESENT = 2; // 0x2
     field public static final int CARD_STATE_INFO_RESTRICTED = 4; // 0x4
     field public static final android.os.Parcelable.Creator<android.telephony.UiccSlotInfo> CREATOR;
-    field public final java.lang.String cardId;
-    field public final int cardStateInfo;
-    field public final boolean isActive;
-    field public final boolean isEuicc;
   }
 
   public abstract class VisualVoicemailService extends android.app.Service {
@@ -5710,6 +5718,7 @@
     ctor public ImsCallSessionImplBase();
     method public void accept(int, android.telephony.ims.ImsStreamMediaProfile);
     method public void close();
+    method public void deflect(java.lang.String);
     method public void extendToConference(java.lang.String[]);
     method public java.lang.String getCallId();
     method public android.telephony.ims.ImsCallProfile getCallProfile();
diff --git a/api/test-current.txt b/api/test-current.txt
index ac4ce3b..b02da04 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -211,6 +211,7 @@
     method public abstract boolean isPermissionReviewModeEnabled();
     field public static final java.lang.String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
     field public static final java.lang.String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
+    field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
   }
 
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -1037,6 +1038,7 @@
 
   public class AccessibilityNodeInfo implements android.os.Parcelable {
     method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
+    method public void writeToParcelNoRecycle(android.os.Parcel, int);
   }
 
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
@@ -1077,6 +1079,12 @@
     field public static final int MODE_SPINNER = 1; // 0x1
   }
 
+  public final class Magnifier {
+    method public android.graphics.Bitmap getContent();
+    method public static android.graphics.PointF getMagnifierDefaultSize();
+    method public android.graphics.Rect getWindowPositionOnScreen();
+  }
+
   public class NumberPicker extends android.widget.LinearLayout {
     method public java.lang.CharSequence getDisplayedValueForCurrentSelection();
   }
diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
index 47581e1..7c1a555 100644
--- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java
+++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
@@ -46,6 +46,7 @@
     private static final String COMMAND_SET_PROFILE_OWNER = "set-profile-owner";
     private static final String COMMAND_REMOVE_ACTIVE_ADMIN = "remove-active-admin";
     private static final String COMMAND_CLEAR_FREEZE_PERIOD_RECORD = "clear-freeze-period-record";
+    private static final String COMMAND_FORCE_SECURITY_LOGS = "force-security-logs";
 
     private IDevicePolicyManager mDevicePolicyManager;
     private int mUserId = UserHandle.USER_SYSTEM;
@@ -76,11 +77,15 @@
                 "\n" +
                 "dpm remove-active-admin: Disables an active admin, the admin must have declared" +
                 " android:testOnly in the application in its manifest. This will also remove" +
-                " device and profile owners\n" +
+                " device and profile owners.\n" +
                 "\n" +
                 "dpm " + COMMAND_CLEAR_FREEZE_PERIOD_RECORD + ": clears framework-maintained " +
                 "record of past freeze periods that the device went through. For use during " +
-                "feature development to prevent triggering restriction on setting freeze periods");
+                "feature development to prevent triggering restriction on setting freeze " +
+                "periods.\n" +
+                "\n" +
+                "dpm " + COMMAND_FORCE_SECURITY_LOGS + ": makes all security logs available to " +
+                "the DPC and triggers DeviceAdminReceiver.onSecurityLogsAvailable() if needed.");
     }
 
     @Override
@@ -109,11 +114,26 @@
             case COMMAND_CLEAR_FREEZE_PERIOD_RECORD:
                 runClearFreezePeriodRecord();
                 break;
+            case COMMAND_FORCE_SECURITY_LOGS:
+                runForceSecurityLogs();
+                break;
             default:
                 throw new IllegalArgumentException ("unknown command '" + command + "'");
         }
     }
 
+    private void runForceSecurityLogs() throws RemoteException, InterruptedException {
+        while (true) {
+            final long toWait = mDevicePolicyManager.forceSecurityLogs();
+            if (toWait == 0) {
+                break;
+            }
+            System.out.println("We have to wait for " + toWait + " milliseconds...");
+            Thread.sleep(toWait);
+        }
+        System.out.println("Success");
+    }
+
     private void parseArgs(boolean canHaveName) {
         String opt;
         while ((opt = nextOption()) != null) {
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 1d5ab59..654036e 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -46,6 +46,7 @@
 checkIncidentPermissions(const IncidentReportArgs& args)
 {
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    pid_t callingPid = IPCThreadState::self()->getCallingPid();
     if (callingUid == AID_ROOT || callingUid == AID_SHELL) {
         // root doesn't have permission.DUMP if don't do this!
         return Status::ok();
@@ -54,13 +55,13 @@
     // checking calling permission.
     if (!checkCallingPermission(DUMP_PERMISSION)) {
         ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
-                IPCThreadState::self()->getCallingPid(), callingUid);
+                callingPid, callingUid);
         return Status::fromExceptionCode(Status::EX_SECURITY,
                 "Calling process does not have permission: android.permission.DUMP");
     }
     if (!checkCallingPermission(USAGE_STATS_PERMISSION)) {
         ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS",
-                IPCThreadState::self()->getCallingPid(), callingUid);
+                callingPid, callingUid);
         return Status::fromExceptionCode(Status::EX_SECURITY,
                 "Calling process does not have permission: android.permission.USAGE_STATS");
     }
@@ -68,13 +69,17 @@
     // checking calling request uid permission.
     switch (args.dest()) {
         case DEST_LOCAL:
-            if (callingUid != AID_SHELL || callingUid != AID_ROOT) {
+            if (callingUid != AID_SHELL && callingUid != AID_ROOT) {
+                ALOGW("Calling pid %d and uid %d does not have permission to get local data.",
+                        callingPid, callingUid);
                 return Status::fromExceptionCode(Status::EX_SECURITY,
                     "Calling process does not have permission to get local data.");
             }
         case DEST_EXPLICIT:
-            if (callingUid != AID_SHELL || callingUid != AID_ROOT ||
-                callingUid != AID_STATSD || callingUid != AID_SYSTEM) {
+            if (callingUid != AID_SHELL && callingUid != AID_ROOT &&
+                callingUid != AID_STATSD && callingUid != AID_SYSTEM) {
+                ALOGW("Calling pid %d and uid %d does not have permission to get explicit data.",
+                        callingPid, callingUid);
                 return Status::fromExceptionCode(Status::EX_SECURITY,
                     "Calling process does not have permission to get explicit data.");
             }
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index 03faa92..f53befe 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -142,7 +142,7 @@
 PrivacyBuffer::clear()
 {
     mSize = 0;
-    mProto = ProtoOutputStream();
+    mProto.clear();
 }
 
 size_t
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index b0019ac..8eea944 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -44,6 +44,7 @@
     src/external/KernelUidCpuActiveTimeReader.cpp \
     src/external/KernelUidCpuClusterTimeReader.cpp \
     src/external/StatsPullerManagerImpl.cpp \
+    src/external/puller_util.cpp \
     src/logd/LogEvent.cpp \
     src/logd/LogListener.cpp \
     src/logd/LogReader.cpp \
@@ -65,6 +66,7 @@
     src/storage/StorageManager.cpp \
     src/StatsLogProcessor.cpp \
     src/StatsService.cpp \
+    src/subscriber/IncidentdReporter.cpp \
     src/subscriber/SubscriberReporter.cpp \
     src/HashableDimensionKey.cpp \
     src/guardrail/MemoryLeakTrackUtil.cpp \
@@ -174,6 +176,7 @@
     tests/AnomalyMonitor_test.cpp \
     tests/anomaly/AnomalyTracker_test.cpp \
     tests/ConfigManager_test.cpp \
+    tests/external/puller_util_test.cpp \
     tests/indexed_priority_queue_test.cpp \
     tests/LogEntryMatcher_test.cpp \
     tests/LogReader_test.cpp \
@@ -239,7 +242,8 @@
 LOCAL_SRC_FILES := $(statsd_common_src) \
                    benchmark/main.cpp \
                    benchmark/hello_world_benchmark.cpp \
-                   benchmark/log_event_benchmark.cpp
+                   benchmark/log_event_benchmark.cpp \
+                   benchmark/stats_write_benchmark.cpp
 
 LOCAL_C_INCLUDES := $(statsd_common_c_includes)
 
@@ -258,7 +262,8 @@
     $(statsd_common_static_libraries)
 
 LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries) \
-    libgtest_prod
+    libgtest_prod \
+    libstatslog
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := lite
 
diff --git a/cmds/statsd/AndroidTest.xml b/cmds/statsd/AndroidTest.xml
new file mode 100644
index 0000000..afe30a2
--- /dev/null
+++ b/cmds/statsd/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for statsd_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="statsd_test->/data/nativetest/statsd_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/nativetest" />
+        <option name="module-name" value="statsd_test" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/cmds/statsd/benchmark/stats_write_benchmark.cpp b/cmds/statsd/benchmark/stats_write_benchmark.cpp
new file mode 100644
index 0000000..f5a0cd5
--- /dev/null
+++ b/cmds/statsd/benchmark/stats_write_benchmark.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "benchmark/benchmark.h"
+#include <statslog.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static void BM_StatsWrite(benchmark::State& state) {
+    const char* reason = "test";
+    int64_t boot_end_time = 1234567;
+    int64_t total_duration = 100;
+    int64_t bootloader_duration = 10;
+    int64_t time_since_last_boot = 99999999;
+    while (state.KeepRunning()) {
+        android::util::stats_write(
+                android::util::BOOT_SEQUENCE_REPORTED, reason, reason,
+                boot_end_time, total_duration, bootloader_duration, time_since_last_boot);
+        total_duration++;
+    }
+}
+BENCHMARK(BM_StatsWrite);
+
+}  //  namespace statsd
+}  //  namespace os
+}  //  namespace android
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index f0eaeff..8483b02 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -181,7 +181,9 @@
     return toString().compare(that.toString()) < 0;
 };
 
-
+bool compareDimensionsValue(const DimensionsValue& s1, const DimensionsValue& s2) {
+    return EqualsTo(s1, s2);
+}
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index a4066aa..7662c40 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 #include "statslog.h"
 
@@ -32,6 +32,7 @@
 
 #include <log/log_event_list.h>
 #include <utils/Errors.h>
+#include <utils/SystemClock.h>
 
 using namespace android;
 using android::base::StringPrintf;
@@ -60,6 +61,8 @@
 // for ConfigMetricsReport
 const int FIELD_ID_METRICS = 1;
 const int FIELD_ID_UID_MAP = 2;
+const int FIELD_ID_LAST_REPORT_NANOS = 3;
+const int FIELD_ID_CURRENT_REPORT_NANOS = 4;
 
 #define STATS_DATA_DIR "/data/misc/stats-data"
 
@@ -146,6 +149,12 @@
         return;
     }
 
+    long curTime = time(nullptr);
+    if (curTime - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
+        mStatsPullerManager.ClearPullerCacheIfNecessary(curTime);
+        mLastPullerCacheClearTimeSec = curTime;
+    }
+
     if (event->GetTagId() != android::util::ISOLATED_UID_CHANGED) {
         // Map the isolated uid to host uid if necessary.
         mapIsolatedUidToHostUidIfNecessaryLocked(event);
@@ -160,7 +169,7 @@
 
 void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
-    ALOGD("Updated configuration for key %s", key.ToString().c_str());
+    VLOG("Updated configuration for key %s", key.ToString().c_str());
     sp<MetricsManager> newMetricsManager = new MetricsManager(key, config, mTimeBaseSec, mUidMap);
     auto it = mMetricsManagers.find(key);
     if (it == mMetricsManagers.end() && mMetricsManagers.size() > StatsdStats::kMaxConfigCount) {
@@ -258,6 +267,12 @@
     uidMap.SerializeToArray(&uidMapBuffer[0], uidMapSize);
     proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize);
 
+    // Fill in the timestamps.
+    proto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_NANOS,
+                (long long)it->second->getLastReportTimeNs());
+    proto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_NANOS,
+                (long long)::android::elapsedRealtimeNano());
+
     // End of ConfigMetricsReport (reports).
     proto.end(reportsToken);
 
@@ -290,6 +305,10 @@
     StatsdStats::getInstance().noteConfigRemoved(key);
 
     mLastBroadcastTimes.erase(key);
+
+    if (mMetricsManagers.empty()) {
+        mStatsPullerManager.ForceClearPullerCache();
+    }
 }
 
 void StatsLogProcessor::flushIfNecessaryLocked(
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 7642aafa..8bbcd75 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -21,6 +21,7 @@
 #include "logd/LogReader.h"
 #include "metrics/MetricsManager.h"
 #include "packages/UidMap.h"
+#include "external/StatsPullerManager.h"
 
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
@@ -75,6 +76,8 @@
 
     sp<UidMap> mUidMap;  // Reference to the UidMap to lookup app name and version for each uid.
 
+    StatsPullerManager mStatsPullerManager;
+
     sp<AnomalyMonitor> mAnomalyMonitor;
 
     void onDumpReportLocked(const ConfigKey& key, vector<uint8_t>* outData);
@@ -96,11 +99,14 @@
 
     const long mTimeBaseSec;
 
+    long mLastPullerCacheClearTimeSec = 0;
+
     FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
     FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
     FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
     FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
-    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
+    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration);
+    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration);
     FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
     FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
     FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 32da94f..c24efec 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "StatsService.h"
@@ -77,18 +77,18 @@
     : mAnomalyMonitor(new AnomalyMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS))
 {
     mUidMap = new UidMap();
+    StatsPuller::SetUidMap(mUidMap);
     mConfigManager = new ConfigManager();
     mProcessor = new StatsLogProcessor(mUidMap, mAnomalyMonitor, time(nullptr), [this](const ConfigKey& key) {
         sp<IStatsCompanionService> sc = getStatsCompanionService();
         auto receiver = mConfigManager->GetConfigReceiver(key);
         if (sc == nullptr) {
             VLOG("Could not find StatsCompanionService");
-        } else if (receiver.first.size() == 0) {
+        } else if (receiver == nullptr) {
             VLOG("Statscompanion could not find a broadcast receiver for %s",
                  key.ToString().c_str());
         } else {
-            sc->sendBroadcast(String16(receiver.first.c_str()),
-                              String16(receiver.second.c_str()));
+            sc->sendDataBroadcast(receiver);
         }
     });
 
@@ -240,6 +240,10 @@
         if (!args[0].compare(String8("log-app-hook"))) {
             return cmd_log_app_hook(out, args);
         }
+
+        if (!args[0].compare(String8("clear-puller-cache"))) {
+            return cmd_clear_puller_cache(out);
+        }
     }
 
     print_cmd_help(out);
@@ -320,6 +324,10 @@
     fprintf(out, "\n");
     fprintf(out, "usage: adb shell cmd stats print-stats\n");
     fprintf(out, "  Prints some basic stats.\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "usage: adb shell cmd stats clear-puller-cache\n");
+    fprintf(out, "  Clear cached puller data.\n");
 }
 
 status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
@@ -358,12 +366,14 @@
     }
     auto receiver = mConfigManager->GetConfigReceiver(ConfigKey(uid, StrToInt64(name)));
     sp<IStatsCompanionService> sc = getStatsCompanionService();
-    if (sc != nullptr) {
-        sc->sendBroadcast(String16(receiver.first.c_str()), String16(receiver.second.c_str()));
+    if (sc == nullptr) {
+        VLOG("Could not access statsCompanion");
+    } else if (receiver == nullptr) {
+        VLOG("Could not find receiver for %s, %s", args[1].c_str(), args[2].c_str())
+    } else {
+        sc->sendDataBroadcast(receiver);
         VLOG("StatsService::trigger broadcast succeeded to %s, %s", args[1].c_str(),
              args[2].c_str());
-    } else {
-        VLOG("Could not access statsCompanion");
     }
 
     return NO_ERROR;
@@ -602,9 +612,15 @@
 }
 
 status_t StatsService::cmd_clear_puller_cache(FILE* out) {
-    mStatsPullerManager.ClearPullerCache();
-    fprintf(out, "Puller cached data removed!\n");
-    return NO_ERROR;
+    IPCThreadState* ipc = IPCThreadState::self();
+    VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
+    if (checkCallingPermission(String16(kPermissionDump))) {
+        int cleared = mStatsPullerManager.ForceClearPullerCache();
+        fprintf(out, "Puller removed %d cached data!\n", cleared);
+        return NO_ERROR;
+    } else {
+        return PERMISSION_DENIED;
+    }
 }
 
 Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version,
@@ -785,7 +801,6 @@
 
 Status StatsService::addConfiguration(int64_t key,
                                       const vector <uint8_t>& config,
-                                      const String16& package, const String16& cls,
                                       bool* success) {
     IPCThreadState* ipc = IPCThreadState::self();
     if (checkCallingPermission(String16(kPermissionDump))) {
@@ -796,8 +811,33 @@
             return Status::ok();
         }
         mConfigManager->UpdateConfig(configKey, cfg);
-        mConfigManager->SetConfigReceiver(configKey, string(String8(package).string()),
-                                          string(String8(cls).string()));
+        *success = true;
+        return Status::ok();
+    } else {
+        *success = false;
+        return Status::fromExceptionCode(binder::Status::EX_SECURITY);
+    }
+}
+
+Status StatsService::removeDataFetchOperation(int64_t key, bool* success) {
+    IPCThreadState* ipc = IPCThreadState::self();
+    if (checkCallingPermission(String16(kPermissionDump))) {
+        ConfigKey configKey(ipc->getCallingUid(), key);
+        mConfigManager->RemoveConfigReceiver(configKey);
+        *success = true;
+        return Status::ok();
+    } else {
+        *success = false;
+        return Status::fromExceptionCode(binder::Status::EX_SECURITY);
+    }
+}
+
+Status StatsService::setDataFetchOperation(int64_t key, const sp<android::IBinder>& intentSender,
+                                           bool* success) {
+    IPCThreadState* ipc = IPCThreadState::self();
+    if (checkCallingPermission(String16(kPermissionDump))) {
+        ConfigKey configKey(ipc->getCallingUid(), key);
+        mConfigManager->SetConfigReceiver(configKey, intentSender);
         *success = true;
         return Status::ok();
     } else {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 109752b..3dc19fe 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -90,9 +90,19 @@
      * Binder call to let clients send a configuration and indicate they're interested when they
      * should requestData for this configuration.
      */
-    virtual Status addConfiguration(int64_t key, const vector <uint8_t>& config,
-                                    const String16& package, const String16& cls, bool* success)
-    override;
+    virtual Status addConfiguration(int64_t key, const vector<uint8_t>& config,
+                                    bool* success) override;
+
+    /**
+     * Binder call to let clients register the data fetch operation for a configuration.
+     */
+    virtual Status setDataFetchOperation(int64_t key, const sp<android::IBinder>& intentSender,
+                                         bool* success) override;
+
+    /**
+     * Binder call to remove the data fetch operation for the specified config key.
+     */
+    virtual Status removeDataFetchOperation(int64_t key, bool* success) override;
 
     /**
      * Binder call to allow clients to remove the specified configuration.
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
index 4912648..72d29d0 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true
+#define DEBUG false
 #include "Log.h"
 
 #include "anomaly/AnomalyMonitor.h"
@@ -36,10 +36,10 @@
     sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
     mStatsCompanionService = statsCompanionService;
     if (statsCompanionService == nullptr) {
-        if (DEBUG) ALOGD("Erasing link to statsCompanionService");
+        VLOG("Erasing link to statsCompanionService");
         return;
     }
-    if (DEBUG) ALOGD("Creating link to statsCompanionService");
+    VLOG("Creating link to statsCompanionService");
     const sp<const AnomalyAlarm> top = mPq.top();
     if (top != nullptr) {
         updateRegisteredAlarmTime_l(top->timestampSec);
@@ -58,7 +58,7 @@
         return;
     }
     // TODO: Ensure that refractory period is respected.
-    if (DEBUG) ALOGD("Adding alarm with time %u", alarm->timestampSec);
+    VLOG("Adding alarm with time %u", alarm->timestampSec);
     mPq.push(alarm);
     if (mRegisteredAlarmTimeSec < 1 ||
         alarm->timestampSec + mMinUpdateTimeSec < mRegisteredAlarmTimeSec) {
@@ -72,16 +72,16 @@
         ALOGW("Asked to remove a null alarm.");
         return;
     }
-    if (DEBUG) ALOGD("Removing alarm with time %u", alarm->timestampSec);
+    VLOG("Removing alarm with time %u", alarm->timestampSec);
     bool wasPresent = mPq.remove(alarm);
     if (!wasPresent) return;
     if (mPq.empty()) {
-        if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
+        VLOG("Queue is empty. Cancel any alarm.");
         cancelRegisteredAlarmTime_l();
         return;
     }
     uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
-    if (DEBUG) ALOGD("Soonest alarm is %u", soonestAlarmTimeSec);
+    VLOG("Soonest alarm is %u", soonestAlarmTimeSec);
     if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) {
         updateRegisteredAlarmTime_l(soonestAlarmTimeSec);
     }
@@ -91,7 +91,7 @@
 // updates to the registered alarm.
 unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::popSoonerThan(
         uint32_t timestampSec) {
-    if (DEBUG) ALOGD("Removing alarms with time <= %u", timestampSec);
+    VLOG("Removing alarms with time <= %u", timestampSec);
     unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> oldAlarms;
     std::lock_guard<std::mutex> lock(mLock);
 
@@ -103,7 +103,7 @@
     // Always update registered alarm time (if anything has changed).
     if (!oldAlarms.empty()) {
         if (mPq.empty()) {
-            if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
+            VLOG("Queue is empty. Cancel any alarm.");
             cancelRegisteredAlarmTime_l();
         } else {
             // Always update the registered alarm in this case (unlike remove()).
@@ -114,7 +114,7 @@
 }
 
 void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
-    if (DEBUG) ALOGD("Updating reg alarm time to %u", timestampSec);
+    VLOG("Updating reg alarm time to %u", timestampSec);
     mRegisteredAlarmTimeSec = timestampSec;
     if (mStatsCompanionService != nullptr) {
         mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
@@ -123,7 +123,7 @@
 }
 
 void AnomalyMonitor::cancelRegisteredAlarmTime_l() {
-    if (DEBUG) ALOGD("Cancelling reg alarm.");
+    VLOG("Cancelling reg alarm.");
     mRegisteredAlarmTimeSec = 0;
     if (mStatsCompanionService != nullptr) {
         mStatsCompanionService->cancelAnomalyAlarm();
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index c84a5b4..ba16ec83 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "AnomalyTracker.h"
 #include "external/Perfetto.h"
 #include "guardrail/StatsdStats.h"
-#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
+#include "subscriber/IncidentdReporter.h"
 #include "subscriber/SubscriberReporter.h"
 
-#include <android/os/IIncidentManager.h>
-#include <android/os/IncidentReportArgs.h>
-#include <binder/IServiceManager.h>
 #include <statslog.h>
 #include <time.h>
 
@@ -35,20 +32,17 @@
 
 // TODO: Get rid of bucketNumbers, and return to the original circular array method.
 AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
-    : mAlert(alert),
-      mConfigKey(configKey),
-      mNumOfPastBuckets(mAlert.num_buckets() - 1) {
+    : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) {
     VLOG("AnomalyTracker() called");
     if (mAlert.num_buckets() <= 0) {
-        ALOGE("Cannot create AnomalyTracker with %lld buckets",
-              (long long)mAlert.num_buckets());
+        ALOGE("Cannot create AnomalyTracker with %lld buckets", (long long)mAlert.num_buckets());
         return;
     }
     if (!mAlert.has_trigger_if_sum_gt()) {
         ALOGE("Cannot create AnomalyTracker without threshold");
         return;
     }
-    resetStorage(); // initialization
+    resetStorage();  // initialization
 }
 
 AnomalyTracker::~AnomalyTracker() {
@@ -171,8 +165,8 @@
         // TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this.
         addPastBucket(key, 0, currentBucketNum - 1);
     }
-    return mAlert.has_trigger_if_sum_gt()
-            && getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
+    return mAlert.has_trigger_if_sum_gt() &&
+           getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
 }
 
 void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const MetricDimensionKey& key) {
@@ -188,7 +182,7 @@
 
     if (!mSubscriptions.empty()) {
         if (mAlert.has_id()) {
-            ALOGI("An anomaly (%llu) has occurred! Informing subscribers.",mAlert.id());
+            ALOGI("An anomaly (%llu) has occurred! Informing subscribers.", mAlert.id());
             informSubscribers(key);
         } else {
             ALOGI("An anomaly (with no id) has occurred! Not informing any subscribers.");
@@ -233,44 +227,26 @@
         return;
     }
 
-    std::set<int> incidentdSections;
-
     for (const Subscription& subscription : mSubscriptions) {
         switch (subscription.subscriber_information_case()) {
             case Subscription::SubscriberInformationCase::kIncidentdDetails:
-                for (int i = 0; i < subscription.incidentd_details().section_size(); i++) {
-                    incidentdSections.insert(subscription.incidentd_details().section(i));
+                if (!GenerateIncidentReport(subscription.incidentd_details(), mAlert, mConfigKey)) {
+                    ALOGW("Failed to generate incident report.");
                 }
                 break;
             case Subscription::SubscriberInformationCase::kPerfettoDetails:
-                CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details());
+                if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) {
+                    ALOGW("Failed to generate prefetto traces.");
+                }
                 break;
             case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
-                SubscriberReporter::getInstance()
-                        .alertBroadcastSubscriber(mConfigKey, subscription, key);
+                SubscriberReporter::getInstance().alertBroadcastSubscriber(mConfigKey, subscription,
+                                                                           key);
                 break;
             default:
                 break;
         }
     }
-    if (!incidentdSections.empty()) {
-        sp<IIncidentManager> service = interface_cast<IIncidentManager>(
-                defaultServiceManager()->getService(android::String16("incident")));
-        if (service != NULL) {
-            IncidentReportArgs incidentReport;
-            for (const auto section : incidentdSections) {
-                incidentReport.addSection(section);
-            }
-            android::os::IncidentHeaderProto header;
-            header.set_alert_id(mAlert.id());
-            header.mutable_config_key()->set_uid(mConfigKey.GetUid());
-            header.mutable_config_key()->set_id(mConfigKey.GetId());
-            incidentReport.addHeader(header);
-            service->reportIncident(incidentReport);
-        } else {
-            ALOGW("Couldn't get the incident service.");
-        }
-    }
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index f01a97f..3be959d 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -16,22 +16,24 @@
 
 #pragma once
 
+#include <memory>  // unique_ptr
+
+#include <stdlib.h>
+
 #include <gtest/gtest_prod.h>
+#include <utils/RefBase.h>
+
 #include "AnomalyMonitor.h"
 #include "config/ConfigKey.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // Alert
 #include "stats_util.h"  // HashableDimensionKey and DimToValMap
 
-#include <memory> // unique_ptr
-#include <stdlib.h>
-#include <utils/RefBase.h>
-
 namespace android {
 namespace os {
 namespace statsd {
 
-using std::unordered_map;
 using std::shared_ptr;
+using std::unordered_map;
 
 // Does NOT allow negative values.
 class AnomalyTracker : public virtual RefBase {
@@ -60,12 +62,11 @@
 
     // Detects the alert and informs the incidentd when applicable.
     void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
-                                 const MetricDimensionKey& key,
-                                 const int64_t& currentBucketValue);
+                                 const MetricDimensionKey& key, const int64_t& currentBucketValue);
 
     // Init the AnomalyMonitor which is shared across anomaly trackers.
     virtual void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) {
-        return; // Base AnomalyTracker class has no need for the AnomalyMonitor.
+        return;  // Base AnomalyTracker class has no need for the AnomalyMonitor.
     }
 
     // Helper function to return the sum value of past buckets at given dimension.
@@ -92,9 +93,10 @@
 
     // Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
     // and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
-    virtual void informAlarmsFired(const uint64_t& timestampNs,
+    virtual void informAlarmsFired(
+            const uint64_t& timestampNs,
             unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
-        return; // The base AnomalyTracker class doesn't have alarms.
+        return;  // The base AnomalyTracker class doesn't have alarms.
     }
 
 protected:
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index bbee9fa..fa0bc0c 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "DurationAnomalyTracker.h"
@@ -52,8 +52,7 @@
 }
 
 void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey,
-                                const uint64_t& timestampNs) {
-
+                                        const uint64_t& timestampNs) {
     uint32_t timestampSec = static_cast<uint32_t>(timestampNs / NS_PER_SEC);
     if (isInRefractoryPeriod(timestampNs, dimensionKey)) {
         VLOG("Skipping setting anomaly alarm since it'd fall in the refractory period");
@@ -86,15 +85,15 @@
     }
 }
 
-void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
+void DurationAnomalyTracker::informAlarmsFired(
+        const uint64_t& timestampNs,
         unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
-
     if (firedAlarms.empty() || mAlarms.empty()) return;
     // Find the intersection of firedAlarms and mAlarms.
     // The for loop is inefficient, since it loops over all keys, but that's okay since it is very
     // seldomly called. The alternative would be having AnomalyAlarms store information about the
-    // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that is
-    // rarely ever called.
+    // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that
+    // is rarely ever called.
     unordered_map<MetricDimensionKey, sp<const AnomalyAlarm>> matchedAlarms;
     for (const auto& kv : mAlarms) {
         if (firedAlarms.count(kv.second) > 0) {
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
index 052fdf57..ba687da 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -53,7 +53,8 @@
     // and removes it from firedAlarms.
     // Note that this will generally be called from a different thread from the other functions;
     // the caller is responsible for thread safety.
-    void informAlarmsFired(const uint64_t& timestampNs,
+    void informAlarmsFired(
+            const uint64_t& timestampNs,
             unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) override;
 
 protected:
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index ed570e7..4c6a36b 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -24,6 +24,7 @@
 import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
+import "frameworks/base/core/proto/android/telecomm/enums.proto";
 import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/core/proto/android/view/enums.proto";
 
@@ -97,6 +98,8 @@
         BootSequenceReported boot_sequence_reported = 57;
         DaveyOccurred davey_occurred = 58;
         OverlayStateChanged overlay_state_changed = 59;
+        ForegroundServiceStateChanged foreground_service_state_changed = 60;
+        CallStateChanged call_state_changed = 61;
         // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
     }
 
@@ -724,6 +727,33 @@
     optional int64 time_since_last_boot = 6;
 }
 
+
+/**
+ * Logs call state and disconnect cause (if applicable).
+ *
+ * Logged from:
+ *   packages/services/Telecomm/src/com/android/server/telecom/Call.java
+ */
+message CallStateChanged {
+    // The state of the call. Eg. DIALING, ACTIVE, ON_HOLD, DISCONNECTED.
+    // From frameworks/base/core/proto/android/telecomm/enums.proto.
+    optional android.telecom.CallStateEnum call_state = 1;
+
+    // The reason the call disconnected. Eg. ERROR, MISSED, REJECTED, BUSY.
+    // This value is only applicable when the call_state is DISCONNECTED, and
+    // should always be UNKNOWN if the call_state is not DISCONNECTED.
+    // From frameworks/base/core/proto/android/telecomm/enums.proto.
+    optional android.telecom.DisconnectCauseEnum disconnect_cause = 2;
+
+    // True if the call is self-managed, which are apps that use the
+    // telecom infrastructure to make their own calls.
+    optional bool self_managed = 3;
+
+    // True if call is external. External calls are calls on connected Wear
+    // devices but show up in Telecom so the user can pull them onto the device.
+    optional bool external_call = 4;
+}
+
 /**
  * Logs the duration of a davey (jank of >=700ms) when it occurs
  *
@@ -998,6 +1028,157 @@
     optional State state = 4;
 }
 
+/*
+ * Logs foreground service starts and stops.
+ * Note that this is not when a service starts or stops, but when it is
+ * considered foreground.
+ * Logged from
+ *     //frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
+ */
+message ForegroundServiceStateChanged {
+    optional int32 uid = 1;
+    // package_name + "/" + class_name
+    optional string short_name = 2;
+
+    enum State {
+        ENTER = 1;
+        EXIT = 2;
+    }
+    optional State state = 3;
+}
+
+/**
+ * Logs creation or removal of an isolated uid. Isolated uid's are temporary uid's to sandbox risky
+ * behavior in its own uid. However, the metrics of these isolated uid's almost always should be
+ * attributed back to the parent (host) uid. One example is Chrome.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message IsolatedUidChanged {
+    // The host UID. Generally, we should attribute metrics from the isolated uid to the host uid.
+    optional int32 parent_uid = 1;
+
+    optional int32 isolated_uid = 2;
+
+    // We expect an isolated uid to be removed before if it's used for another parent uid.
+    enum Event {
+        REMOVED = 0;
+        CREATED = 1;
+    }
+    optional Event event = 3;
+}
+
+/*
+ * Logs the reception of an incoming network packet causing the main system to wake up for
+ * processing that packet. These events are notified by the kernel via Netlink NFLOG to Netd
+ * and processed by WakeupController.cpp.
+ */
+message PacketWakeupOccurred {
+    // The uid owning the socket into which the packet was delivered, or -1 if the packet was
+    // delivered nowhere.
+    optional int32 uid = 1;
+    // The interface name on which the packet was received.
+    optional string iface = 2;
+    // The ethertype value of the packet.
+    optional int32 ethertype = 3;
+    // String representation of the destination MAC address of the packet.
+    optional string destination_hardware_address = 4;
+    // String representation of the source address of the packet if this was an IP packet.
+    optional string source_ip = 5;
+    // String representation of the destination address of the packet if this was an IP packet.
+    optional string destination_ip = 6;
+    // The value of the protocol field if this was an IPv4 packet or the value of the Next Header
+    // field if this was an IPv6 packet. The range of possible values is the same for both IP
+    // families.
+    optional int32 ip_next_header = 7;
+    // The source port if this was a TCP or UDP packet.
+    optional int32 source_port = 8;
+    // The destination port if this was a TCP or UDP packet.
+    optional int32 destination_port = 9;
+}
+
+/*
+ * Logs the memory stats for an app on startup.
+ * Logged from:
+ *     frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ */
+message AppStartMemoryStateCaptured {
+    // The uid if available. -1 means not available.
+    optional int32 uid = 1;
+
+    // The process name.
+    optional string process_name = 2;
+
+    // The activity name.
+    optional string activity_name = 3;
+
+    // # of page-faults
+    optional int64 pgfault = 4;
+
+    // # of major page-faults
+    optional int64 pgmajfault = 5;
+
+    // RSS
+    optional int64 rss_in_bytes = 6;
+
+    // CACHE
+    optional int64 cache_in_bytes = 7;
+
+    // SWAP
+    optional int64 swap_in_bytes = 8;
+}
+
+/*
+ * Logs the change in Low Memory Killer Daemon (LMKD) state which is used as start/stop boundaries
+ * for LMK event.
+ * Logged from:
+ *      system/core/lmkd/lmkd.c
+ */
+message LmkStateChanged {
+    enum State {
+        UNKNOWN = 0;
+        START = 1;
+        STOP = 2;
+    }
+    optional State state = 1;
+}
+
+/*
+ * Logs the event when Low Memory Killer Daemon (LMKD) kills a process to reduce memory pressure.
+ * Logged from:
+ *      system/core/lmkd/lmkd.c
+ */
+message LmkKillOccurred {
+    // The uid if available. -1 means not available.
+    optional int32 uid = 1;
+
+    // The process name.
+    optional string process_name = 2;
+
+    // oom adj score.
+    optional int32 oom_score = 3;
+
+    // # of page-faults
+    optional int64 pgfault = 4;
+
+    // # of major page-faults
+    optional int64 pgmajfault = 5;
+
+    // RSS
+    optional int64 rss_in_bytes = 6;
+
+    // CACHE
+    optional int64 cache_in_bytes = 7;
+
+    // SWAP
+    optional int64 swap_in_bytes = 8;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Pulled atoms below this line //
+//////////////////////////////////////////////////////////////////////
+
 /**
  * Pulls bytes transferred via wifi (Sum of foreground and background usage).
  *
@@ -1114,37 +1295,15 @@
  *   hardware/interfaces/power/1.1/types.hal
  */
 message SubsystemSleepState {
-    // Name should be in the format of XXX.YYY where XXX is subsystem name,
-    // YYY is corresponding voter name.
-    // If there are no voters, the format should just be XXX (with no dot).
-    // XXX and YYY should not contain a "." in it.
-    optional string name = 1;
+    // Subsystem name
+    optional string subsystem_name = 1;
+    // For PlatformLowPowerStats (hal 1.0), this is the voter name, which could be empty.
+    // For SubsystemLowPowerStats (hal 1.1), this is the sleep state name.
+    optional string subname = 2;
     // The number of times it entered, or voted for entering the sleep state
-    optional uint64 count = 2;
+    optional uint64 count = 3;
     // The length of time spent in, or spent voting for, the sleep state
-    optional uint64 timeMs = 3;
-}
-
-/**
- * Logs creation or removal of an isolated uid. Isolated uid's are temporary uid's to sandbox risky
- * behavior in its own uid. However, the metrics of these isolated uid's almost always should be
- * attributed back to the parent (host) uid. One example is Chrome.
- *
- * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
- */
-message IsolatedUidChanged {
-    // The host UID. Generally, we should attribute metrics from the isolated uid to the host uid.
-    optional int32 parent_uid = 1;
-
-    optional int32 isolated_uid = 2;
-
-    // We expect an isolated uid to be removed before if it's used for another parent uid.
-    enum Event {
-        REMOVED = 0;
-        CREATED = 1;
-    }
-    optional Event event = 3;
+    optional uint64 timeMs = 4;
 }
 
 /**
@@ -1181,35 +1340,6 @@
     optional uint64 time_ms = 3;
 }
 
-/*
- * Logs the reception of an incoming network packet causing the main system to wake up for
- * processing that packet. These events are notified by the kernel via Netlink NFLOG to Netd
- * and processed by WakeupController.cpp.
- */
-message PacketWakeupOccurred {
-    // The uid owning the socket into which the packet was delivered, or -1 if the packet was
-    // delivered nowhere.
-    optional int32 uid = 1;
-    // The interface name on which the packet was received.
-    optional string iface = 2;
-    // The ethertype value of the packet.
-    optional int32 ethertype = 3;
-    // String representation of the destination MAC address of the packet.
-    optional string destination_hardware_address = 4;
-    // String representation of the source address of the packet if this was an IP packet.
-    optional string source_ip = 5;
-    // String representation of the destination address of the packet if this was an IP packet.
-    optional string destination_ip = 6;
-    // The value of the protocol field if this was an IPv4 packet or the value of the Next Header
-    // field if this was an IPv6 packet. The range of possible values is the same for both IP
-    // families.
-    optional int32 ip_next_header = 7;
-    // The source port if this was a TCP or UDP packet.
-    optional int32 source_port = 8;
-    // The destination port if this was a TCP or UDP packet.
-    optional int32 destination_port = 9;
-}
-
 /**
  * Pulls Wifi Controller Activity Energy Info
  */
@@ -1283,37 +1413,6 @@
 }
 
 /*
- * Logs the memory stats for an app on startup.
- * Logged from:
- *     frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message AppStartMemoryStateCaptured {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1;
-
-    // The process name.
-    optional string process_name = 2;
-
-    // The activity name.
-    optional string activity_name = 3;
-
-    // # of page-faults
-    optional int64 pgfault = 4;
-
-    // # of major page-faults
-    optional int64 pgmajfault = 5;
-
-    // RSS
-    optional int64 rss_in_bytes = 6;
-
-    // CACHE
-    optional int64 cache_in_bytes = 7;
-
-    // SWAP
-    optional int64 swap_in_bytes = 8;
-}
-
-/*
  * Logs the memory stats for a process.
  */
 message ProcessMemoryState {
@@ -1343,52 +1442,6 @@
 }
 
 /*
- * Logs the change in Low Memory Killer Daemon (LMKD) state which is used as start/stop boundaries
- * for LMK event.
- * Logged from:
- *      system/core/lmkd/lmkd.c
- */
-message LmkStateChanged {
-    enum State {
-        UNKNOWN = 0;
-        START = 1;
-        STOP = 2;
-    }
-    optional State state = 1;
-}
-
-/*
- * Logs the event when Low Memory Killer Daemon (LMKD) kills a process to reduce memory pressure.
- * Logged from:
- *      system/core/lmkd/lmkd.c
- */
-message LmkKillOccurred {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1;
-
-    // The process name.
-    optional string process_name = 2;
-
-    // oom adj score.
-    optional int32 oom_score = 3;
-
-    // # of page-faults
-    optional int64 pgfault = 4;
-
-    // # of major page-faults
-    optional int64 pgmajfault = 5;
-
-    // RSS
-    optional int64 rss_in_bytes = 6;
-
-    // CACHE
-    optional int64 cache_in_bytes = 7;
-
-    // SWAP
-    optional int64 swap_in_bytes = 8;
-}
-
-/*
  * Elapsed real time from SystemClock.
  */
 message SystemElapsedRealtime {
@@ -1463,3 +1516,4 @@
 message FullBatteryCapacity {
     optional int32 capacity_uAh = 1;
 }
+
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 61eeee3..06ff603 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -75,8 +75,8 @@
     }
 }
 
-void ConfigManager::SetConfigReceiver(const ConfigKey& key, const string& pkg, const string& cls) {
-    mConfigReceivers[key] = pair<string, string>(pkg, cls);
+void ConfigManager::SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender) {
+    mConfigReceivers[key] = intentSender;
 }
 
 void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
@@ -159,10 +159,10 @@
     return ret;
 }
 
-const pair<string, string> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
+const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
     auto it = mConfigReceivers.find(key);
     if (it == mConfigReceivers.end()) {
-        return pair<string,string>();
+        return nullptr;
     } else {
         return it->second;
     }
@@ -175,8 +175,7 @@
         fprintf(out, "  %6d %lld\n", key.GetUid(), (long long)key.GetId());
         auto receiverIt = mConfigReceivers.find(key);
         if (receiverIt != mConfigReceivers.end()) {
-            fprintf(out, "    -> received by %s, %s\n", receiverIt->second.first.c_str(),
-                    receiverIt->second.second.c_str());
+            fprintf(out, "    -> received by PendingIntent as binder\n");
         }
     }
 }
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index ad666bc..a2b2a0c 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "binder/IBinder.h"
 #include "config/ConfigKey.h"
 #include "config/ConfigListener.h"
 
@@ -68,12 +69,12 @@
     /**
      * Sets the broadcast receiver for a configuration key.
      */
-    void SetConfigReceiver(const ConfigKey& key, const std::string& pkg, const std::string& cls);
+    void SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender);
 
     /**
      * Returns the package name and class name representing the broadcast receiver for this config.
      */
-    const std::pair<std::string, std::string> GetConfigReceiver(const ConfigKey& key) const;
+    const sp<android::IBinder> GetConfigReceiver(const ConfigKey& key) const;
 
     /**
      * Returns all config keys registered.
@@ -124,10 +125,10 @@
     std::set<ConfigKey> mConfigs;
 
     /**
-     * Each config key can be subscribed by up to one receiver, specified as the package name and
-     * class name.
+     * Each config key can be subscribed by up to one receiver, specified as IBinder from
+     * PendingIntent.
      */
-    std::map<ConfigKey, std::pair<std::string, std::string>> mConfigReceivers;
+    std::map<ConfigKey, sp<android::IBinder>> mConfigReceivers;
 
     /**
      * The ConfigListeners that will be told about changes.
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
index a751273..d0d2f93 100644
--- a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <fstream>
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
index e7ea4b9..d9aeb46 100644
--- a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <fstream>
diff --git a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
index 7a2d199..0e126e7 100644
--- a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
+++ b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <fstream>
diff --git a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
index 7426e74..7684ed4 100644
--- a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
+++ b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <fstream>
diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp
index 1d8a968..b09d373 100644
--- a/cmds/statsd/src/external/Perfetto.cpp
+++ b/cmds/statsd/src/external/Perfetto.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // Alert
@@ -36,7 +37,7 @@
 namespace statsd {
 
 bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config) {
-    ALOGD("Starting trace collection through perfetto");
+    VLOG("Starting trace collection through perfetto");
 
     if (!config.has_trace_config()) {
         ALOGE("The perfetto trace config is empty, aborting");
@@ -118,7 +119,7 @@
         return false;
     }
 
-    ALOGD("CollectPerfettoTraceAndUploadToDropbox() succeeded");
+    VLOG("CollectPerfettoTraceAndUploadToDropbox() succeeded");
     return true;
 }
 
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index b955f1c..8210c8d 100644
--- a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true
+#define DEBUG false
 #include "Log.h"
 
 #include <android/os/IStatsCompanionService.h>
@@ -64,7 +64,7 @@
             std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize);
             data->push_back(make_shared<LogEvent>(tmp));
         }
-        ALOGD("StatsCompanionServicePuller::pull succeeded for %d", mTagId);
+        VLOG("StatsCompanionServicePuller::pull succeeded for %d", mTagId);
         return true;
     } else {
         ALOGW("statsCompanion not found!");
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index da14434..fc0ad7c 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -19,6 +19,7 @@
 
 #include "StatsPuller.h"
 #include "guardrail/StatsdStats.h"
+#include "puller_util.h"
 
 namespace android {
 namespace os {
@@ -26,6 +27,9 @@
 
 using std::lock_guard;
 
+sp<UidMap> StatsPuller::mUidMap = nullptr;
+void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; }
+
 // ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
 StatsPuller::StatsPuller(const int tagId)
     : mTagId(tagId) {
@@ -54,14 +58,30 @@
     mLastPullTimeSec = curTime;
     bool ret = PullInternal(&mCachedData);
     if (ret) {
-        (*data) = mCachedData;
+      mergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId);
+      (*data) = mCachedData;
     }
     return ret;
 }
 
-void StatsPuller::ClearCache() {
+int StatsPuller::ForceClearCache() {
+    return clearCache();
+}
+
+int StatsPuller::clearCache() {
     lock_guard<std::mutex> lock(mLock);
+    int ret = mCachedData.size();
     mCachedData.clear();
+    mLastPullTimeSec = 0;
+    return ret;
+}
+
+int StatsPuller::ClearCacheIfNecessary(long timestampSec) {
+    if (timestampSec - mLastPullTimeSec > mCoolDownSec) {
+        return clearCache();
+    } else {
+        return 0;
+    }
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index bc7c45f..82a8611 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -18,11 +18,14 @@
 
 #include <android/os/StatsLogEventWrapper.h>
 #include <utils/String16.h>
+#include <utils/RefBase.h>
 #include <mutex>
 #include <vector>
+#include "packages/UidMap.h"
 
-#include "logd/LogEvent.h"
 #include "guardrail/StatsdStats.h"
+#include "logd/LogEvent.h"
+#include "puller_util.h"
 
 using android::os::StatsLogEventWrapper;
 
@@ -30,7 +33,7 @@
 namespace os {
 namespace statsd {
 
-class StatsPuller {
+class StatsPuller : public virtual RefBase {
 public:
     StatsPuller(const int tagId);
 
@@ -38,9 +41,15 @@
 
     bool Pull(std::vector<std::shared_ptr<LogEvent>>* data);
 
-    void ClearCache();
+    // Clear cache immediately
+    int ForceClearCache();
 
-protected:
+    // Clear cache if elapsed time is more than cooldown time
+    int ClearCacheIfNecessary(long timestampSec);
+
+    static void SetUidMap(const sp<UidMap>& uidMap);
+
+   protected:
     // The atom tag id this puller pulls
     const int mTagId;
 
@@ -61,6 +70,10 @@
     std::vector<std::shared_ptr<LogEvent>> mCachedData;
 
     long mLastPullTimeSec;
+
+    int clearCache();
+
+    static sp<UidMap> mUidMap;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index 4826d96..0dee342 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -54,8 +54,12 @@
         mPullerManager.SetTimeBaseSec(timeBaseSec);
     }
 
-    void ClearPullerCache() {
-        mPullerManager.ClearPullerCache();
+    int ForceClearPullerCache() {
+        return mPullerManager.ForceClearPullerCache();
+    }
+
+    int ClearPullerCacheIfNecessary(long timestampSec) {
+        return mPullerManager.ClearPullerCacheIfNecessary(timestampSec);
     }
 
  private:
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 71b0abe..4c676a7 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true
+#define DEBUG false
 #include "Log.h"
 
 #include <android/os/IStatsCompanionService.h>
@@ -24,6 +24,9 @@
 #include "CpuTimePerUidFreqPuller.h"
 #include "CpuTimePerUidPuller.h"
 #include "ResourceHealthManagerPuller.h"
+#include "KernelUidCpuActiveTimeReader.h"
+#include "KernelUidCpuClusterTimeReader.h"
+#include "SubsystemSleepStatePuller.h"
 #include "StatsCompanionServicePuller.h"
 #include "StatsPullerManagerImpl.h"
 #include "StatsService.h"
@@ -44,62 +47,89 @@
 namespace os {
 namespace statsd {
 
+const std::map<int, PullAtomInfo> StatsPullerManagerImpl::kAllPullAtomInfo = {
+        // wifi_bytes_transfer
+        {android::util::WIFI_BYTES_TRANSFER,
+         {{2, 3, 4, 5},
+          {},
+          1,
+          new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}},
+        // wifi_bytes_transfer_by_fg_bg
+        {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG,
+         {{3, 4, 5, 6},
+          {2},
+          1,
+          new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
+        // mobile_bytes_transfer
+        {android::util::MOBILE_BYTES_TRANSFER,
+         {{2, 3, 4, 5},
+          {},
+          1,
+          new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}},
+        // mobile_bytes_transfer_by_fg_bg
+        {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
+         {{3, 4, 5, 6},
+          {2},
+          1,
+          new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}},
+        // bluetooth_bytes_transfer
+        {android::util::BLUETOOTH_BYTES_TRANSFER,
+         {{2, 3}, {}, 1, new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}},
+        // kernel_wakelock
+        {android::util::KERNEL_WAKELOCK,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
+        // subsystem_sleep_state
+        {android::util::SUBSYSTEM_SLEEP_STATE, {{}, {}, 1, new SubsystemSleepStatePuller()}},
+        // cpu_time_per_freq
+        {android::util::CPU_TIME_PER_FREQ,
+         {{3}, {2}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
+        // cpu_time_per_uid
+        {android::util::CPU_TIME_PER_UID, {{2, 3}, {}, 1, new CpuTimePerUidPuller()}},
+        // cpu_time_per_uid_freq
+        {android::util::CPU_TIME_PER_UID_FREQ, {{3}, {2}, 1, new CpuTimePerUidFreqPuller()}},
+        // wifi_activity_energy_info
+        {android::util::WIFI_ACTIVITY_ENERGY_INFO,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}},
+        // modem_activity_info
+        {android::util::MODEM_ACTIVITY_INFO,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
+        // bluetooth_activity_info
+        {android::util::BLUETOOTH_ACTIVITY_INFO,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
+        // system_elapsed_realtime
+        {android::util::SYSTEM_ELAPSED_REALTIME,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}},
+        // system_uptime
+        {android::util::SYSTEM_UPTIME,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
+        // cpu_active_time
+        {android::util::CPU_ACTIVE_TIME, {{3}, {2}, 1, new KernelUidCpuActiveTimeReader()}},
+        // cpu_cluster_time
+        {android::util::CPU_CLUSTER_TIME, {{3}, {2}, 1, new KernelUidCpuClusterTimeReader()}},
+        // disk_space
+        {android::util::DISK_SPACE,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::DISK_SPACE)}},
+        // remaining_battery_capacity
+        {android::util::REMAINING_BATTERY_CAPACITY,
+         {{}, {}, 1, new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}},
+        // full_battery_capacity
+        {android::util::FULL_BATTERY_CAPACITY,
+         {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}};
+
 StatsPullerManagerImpl::StatsPullerManagerImpl()
     : mCurrentPullingInterval(LONG_MAX) {
-    mPullers.insert({android::util::KERNEL_WAKELOCK,
-                     make_shared<StatsCompanionServicePuller>(android::util::KERNEL_WAKELOCK)});
-    mPullers.insert({android::util::WIFI_BYTES_TRANSFER,
-                     make_shared<StatsCompanionServicePuller>(android::util::WIFI_BYTES_TRANSFER)});
-    mPullers.insert(
-            {android::util::MOBILE_BYTES_TRANSFER,
-             make_shared<StatsCompanionServicePuller>(android::util::MOBILE_BYTES_TRANSFER)});
-    mPullers.insert({android::util::WIFI_BYTES_TRANSFER_BY_FG_BG,
-                     make_shared<StatsCompanionServicePuller>(
-                             android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)});
-    mPullers.insert({android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
-                     make_shared<StatsCompanionServicePuller>(
-                             android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)});
-    mPullers.insert(
-            {android::util::SUBSYSTEM_SLEEP_STATE,
-             make_shared<SubsystemSleepStatePuller>()});
-    mPullers.insert({android::util::CPU_TIME_PER_FREQ, make_shared<StatsCompanionServicePuller>(android::util::CPU_TIME_PER_FREQ)});
-    mPullers.insert({android::util::CPU_TIME_PER_UID, make_shared<CpuTimePerUidPuller>()});
-    mPullers.insert({android::util::CPU_TIME_PER_UID_FREQ, make_shared<CpuTimePerUidFreqPuller>()});
-    mPullers.insert(
-            {android::util::SYSTEM_ELAPSED_REALTIME,
-             make_shared<StatsCompanionServicePuller>(android::util::SYSTEM_ELAPSED_REALTIME)});
-    mPullers.insert({android::util::SYSTEM_UPTIME,
-                     make_shared<StatsCompanionServicePuller>(android::util::SYSTEM_UPTIME)});
-    mPullers.insert({android::util::DISK_SPACE,
-                     make_shared<StatsCompanionServicePuller>(android::util::DISK_SPACE)});
-    mPullers.insert(
-            {android::util::BLUETOOTH_ACTIVITY_INFO,
-             make_shared<StatsCompanionServicePuller>(android::util::BLUETOOTH_ACTIVITY_INFO)});
-
-    mPullers.insert(
-            {android::util::BLUETOOTH_BYTES_TRANSFER,
-             make_shared<StatsCompanionServicePuller>(android::util::BLUETOOTH_BYTES_TRANSFER)});
-    mPullers.insert(
-            {android::util::WIFI_ACTIVITY_ENERGY_INFO,
-             make_shared<StatsCompanionServicePuller>(android::util::WIFI_ACTIVITY_ENERGY_INFO)});
-    mPullers.insert({android::util::MODEM_ACTIVITY_INFO,
-                     make_shared<StatsCompanionServicePuller>(android::util::MODEM_ACTIVITY_INFO)});
-    mPullers.insert({android::util::REMAINING_BATTERY_CAPACITY,
-                     make_shared<ResourceHealthManagerPuller>(android::util::REMAINING_BATTERY_CAPACITY)});
-    mPullers.insert({android::util::FULL_BATTERY_CAPACITY,
-                     make_shared<ResourceHealthManagerPuller>(android::util::FULL_BATTERY_CAPACITY)});
     mStatsCompanionService = StatsService::getStatsCompanionService();
 }
 
 bool StatsPullerManagerImpl::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) {
-    if (DEBUG) ALOGD("Initiating pulling %d", tagId);
+    VLOG("Initiating pulling %d", tagId);
 
-    if (mPullers.find(tagId) != mPullers.end()) {
-        bool ret = mPullers.find(tagId)->second->Pull(data);
-        ALOGD("pulled %d items", (int)data->size());
+    if (kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end()) {
+        bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data);
+        VLOG("pulled %d items", (int)data->size());
         return ret;
     } else {
-        ALOGD("Unknown tagId %d", tagId);
+        VLOG("Unknown tagId %d", tagId);
         return false;  // Return early since we don't know what to pull.
     }
 }
@@ -110,7 +140,7 @@
 }
 
 bool StatsPullerManagerImpl::PullerForMatcherExists(int tagId) const {
-    return mPullers.find(tagId) != mPullers.end();
+    return kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end();
 }
 
 void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp<PullDataReceiver> receiver,
@@ -199,10 +229,20 @@
     }
 }
 
-void StatsPullerManagerImpl::ClearPullerCache() {
-    for (auto puller : mPullers) {
-        puller.second->ClearCache();
+int StatsPullerManagerImpl::ForceClearPullerCache() {
+    int totalCleared = 0;
+    for (const auto& pulledAtom : kAllPullAtomInfo) {
+        totalCleared += pulledAtom.second.puller->ForceClearCache();
     }
+    return totalCleared;
+}
+
+int StatsPullerManagerImpl::ClearPullerCacheIfNecessary(long timestampSec) {
+    int totalCleared = 0;
+    for (const auto& pulledAtom : kAllPullAtomInfo) {
+        totalCleared += pulledAtom.second.puller->ClearCacheIfNecessary(timestampSec);
+    }
+    return totalCleared;
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.h b/cmds/statsd/src/external/StatsPullerManagerImpl.h
index fba3ade..76a4c14 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.h
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.h
@@ -32,6 +32,20 @@
 namespace os {
 namespace statsd {
 
+typedef struct {
+  // The field numbers of the fields that need to be summed when merging
+  // isolated uid with host uid.
+  std::vector<int> additiveFields;
+  // The field numbers of the fields that can't be merged when merging
+  // data belong to isolated uid and host uid.
+  std::vector<int> nonAdditiveFields;
+  // How long should the puller wait before doing an actual pull again. Default
+  // 1 sec. Set this to 0 if this is handled elsewhere.
+  long coolDownSec = 1;
+  // The actual puller
+  sp<StatsPuller> puller;
+} PullAtomInfo;
+
 class StatsPullerManagerImpl : public virtual RefBase {
 public:
     static StatsPullerManagerImpl& GetInstance();
@@ -49,9 +63,13 @@
 
     void SetTimeBaseSec(long timeBaseSec) {mTimeBaseSec = timeBaseSec;};
 
-    void ClearPullerCache();
+    int ForceClearPullerCache();
 
-private:
+    int ClearPullerCacheIfNecessary(long timestampSec);
+
+    const static std::map<int, PullAtomInfo> kAllPullAtomInfo;
+
+   private:
     StatsPullerManagerImpl();
 
     // use this to update alarm
@@ -59,9 +77,6 @@
 
     sp<IStatsCompanionService> get_stats_companion_service();
 
-    // mapping from simple matcher tagId to puller
-    std::map<int, std::shared_ptr<StatsPuller>> mPullers;
-
     typedef struct {
         // pull_interval_sec : last_pull_time_sec
         std::pair<uint64_t, uint64_t> timeInfo;
@@ -79,8 +94,6 @@
     // bucket size. All pulled metrics start pulling based on this time, so that they can be
     // correctly attributed to the correct buckets.
     long mTimeBaseSec;
-
-    LogEvent parse_pulled_data(String16 data);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
index 6d12e25..65a1df0e 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <android/hardware/power/1.0/IPower.h>
@@ -99,6 +99,7 @@
                         auto statePtr = make_shared<LogEvent>(android::util::SUBSYSTEM_SLEEP_STATE,
                                                               timestamp);
                         statePtr->write(state.name);
+                        statePtr->write("");
                         statePtr->write(state.totalTransitions);
                         statePtr->write(state.residencyInMsecSinceBoot);
                         statePtr->init();
@@ -110,7 +111,8 @@
                         for (auto voter : state.voters) {
                             auto voterPtr = make_shared<LogEvent>(android::util::SUBSYSTEM_SLEEP_STATE,
                                                                   timestamp);
-                            voterPtr->write((std::string)state.name + "." + (std::string)voter.name);
+                            voterPtr->write(state.name);
+                            voterPtr->write(voter.name);
                             voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
                             voterPtr->write(voter.totalTimeInMsecVotedForSinceBoot);
                             voterPtr->init();
@@ -144,7 +146,8 @@
                                             subsystem.states[j];
                                     auto subsystemStatePtr = make_shared<LogEvent>(
                                         android::util::SUBSYSTEM_SLEEP_STATE, timestamp);
-                                    subsystemStatePtr->write((std::string)subsystem.name + "." + (std::string)state.name);
+                                    subsystemStatePtr->write(subsystem.name);
+                                    subsystemStatePtr->write(state.name);
                                     subsystemStatePtr->write(state.totalTransitions);
                                     subsystemStatePtr->write(state.residencyInMsecSinceBoot);
                                     subsystemStatePtr->init();
diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp
new file mode 100644
index 0000000..7cfc1d48
--- /dev/null
+++ b/cmds/statsd/src/external/puller_util.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+#define DEBUG false  // STOPSHIP if true
+#include "Log.h"
+
+#include "StatsPullerManagerImpl.h"
+#include "field_util.h"
+#include "puller_util.h"
+#include "statslog.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::map;
+using std::shared_ptr;
+using std::vector;
+
+DimensionsValue* getFieldValue(shared_ptr<LogEvent> event, int tagId, int fieldNum) {
+  Field field;
+  buildSimpleAtomField(tagId, fieldNum, &field);
+  return event->findFieldValueOrNull(field);
+}
+
+bool shouldMerge(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
+                 const vector<int>& nonAdditiveFields, int tagId) {
+  for (int f : nonAdditiveFields) {
+    DimensionsValue* lValue = getFieldValue(lhs, tagId, f);
+    DimensionsValue* rValue = getFieldValue(rhs, tagId, f);
+    if (!compareDimensionsValue(*lValue, *rValue)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// merge rhs to lhs
+void mergeEvent(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
+                const vector<int>& additiveFields, int tagId) {
+  for (int f : additiveFields) {
+    DimensionsValue* lValue = getFieldValue(lhs, tagId, f);
+    DimensionsValue* rValue = getFieldValue(rhs, tagId, f);
+    if (lValue->has_value_int()) {
+      lValue->set_value_int(lValue->value_int() + rValue->value_int());
+    } else if (lValue->has_value_long()) {
+      lValue->set_value_long(lValue->value_long() + rValue->value_long());
+    }
+  }
+}
+
+// process all data and merge isolated with host if necessary
+void mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data,
+                                const sp<UidMap>& uidMap, int tagId) {
+  if (StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId) ==
+      StatsPullerManagerImpl::kAllPullAtomInfo.end()) {
+    VLOG("Unknown pull atom id %d", tagId);
+    return;
+  }
+  if (android::util::kAtomsWithUidField.find(tagId) ==
+      android::util::kAtomsWithUidField.end()) {
+    VLOG("No uid to merge for atom %d", tagId);
+    return;
+  }
+  const vector<int>& additiveFields =
+      StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)
+          ->second.additiveFields;
+  const vector<int>& nonAdditiveFields =
+      StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)
+          ->second.nonAdditiveFields;
+
+  // map of host uid to isolated uid data index in the original vector.
+  // because of non additive fields, there could be multiple of them that can't
+  // be merged into one
+  map<int, vector<int>> hostToIsolated;
+  // map of host uid to their position in the original vector
+  map<int, vector<int>> hostPosition;
+  vector<int> isolatedUidPos;
+  // all uids in the original vector
+  vector<int> allUids;
+  for (size_t i = 0; i < data.size(); i++) {
+    // uid field is always first primitive filed, if present
+    DimensionsValue* uidField = getFieldValue(data[i], tagId, 1);
+    if (!uidField) {
+      VLOG("Bad data for %d, %s", tagId, data[i]->ToString().c_str());
+      return;
+    }
+    int uid = uidField->value_int();
+    allUids.push_back(uid);
+    const int hostUid = uidMap->getHostUidOrSelf(uid);
+    if (hostUid != uid) {
+      uidField->set_value_int(hostUid);
+      hostToIsolated[hostUid].push_back(i);
+      isolatedUidPos.push_back(i);
+    }
+  }
+  vector<shared_ptr<LogEvent>> mergedData;
+  for (size_t i = 0; i < allUids.size(); i++) {
+    if (hostToIsolated.find(allUids[i]) != hostToIsolated.end()) {
+      hostPosition[allUids[i]].push_back(i);
+    } else if (std::find(isolatedUidPos.begin(), isolatedUidPos.end(), i) != isolatedUidPos.end()) {
+      continue;
+    } else {
+      mergedData.push_back(data[i]);
+    }
+  }
+  for (auto iter = hostToIsolated.begin(); iter != hostToIsolated.end();
+       iter++) {
+    int uid = iter->first;
+    vector<int>& isolated = hostToIsolated[uid];
+    vector<int> toBeMerged;
+    toBeMerged.insert(toBeMerged.begin(), isolated.begin(), isolated.end());
+    if (hostPosition.find(uid) != hostPosition.end()) {
+      vector<int>& host = hostPosition[uid];
+      toBeMerged.insert(toBeMerged.end(), host.begin(), host.end());
+    }
+    vector<bool> used(toBeMerged.size());
+    for (size_t i = 0; i < toBeMerged.size(); i++) {
+      if (used[i] == true) {
+        continue;
+      }
+      for (size_t j = i + 1; j < toBeMerged.size(); j++) {
+        shared_ptr<LogEvent>& lhs = data[toBeMerged[i]];
+        shared_ptr<LogEvent>& rhs = data[toBeMerged[j]];
+        if (shouldMerge(lhs, rhs, nonAdditiveFields, tagId)) {
+          mergeEvent(lhs, rhs, additiveFields, tagId);
+          used[j] = true;
+        }
+      }
+    }
+    for (size_t i = 0; i < toBeMerged.size(); i++) {
+      if (used[i] == false) {
+      mergedData.push_back(data[i]);
+    }
+    }
+  }
+  data.clear();
+  data = mergedData;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/external/puller_util.h b/cmds/statsd/src/external/puller_util.h
new file mode 100644
index 0000000..70d5321
--- /dev/null
+++ b/cmds/statsd/src/external/puller_util.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <vector>
+#include "HashableDimensionKey.h"
+#include "StatsPuller.h"
+#include "logd/LogEvent.h"
+#include "packages/UidMap.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+void mergeIsolatedUidsToHostUid(std::vector<std::shared_ptr<LogEvent>>& data,
+                                const sp<UidMap>& uidMap, int tagId);
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp b/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp
index e1947c4..01c7587 100644
--- a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp
+++ b/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <sstream>
@@ -63,7 +63,7 @@
     size_t count;
     if (info == nullptr || overallSize == 0 || infoSize == 0 ||
         (count = overallSize / infoSize) == 0) {
-        ALOGD("no malloc info, libc.debug.malloc.program property should be set");
+        VLOG("no malloc info, libc.debug.malloc.program property should be set");
         return std::string();
     }
 
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 77f5456..06c5b00 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "StatsdStats.h"
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 1f4bfa6..f254327 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -85,6 +85,9 @@
     // Maximum size of all files that can be written to stats directory on disk.
     static const int kMaxFileSize = 50 * 1024 * 1024;
 
+    // How long to try to clear puller cache from last time
+    static const long kPullerCacheClearIntervalSec = 1;
+
     /**
      * Report a new config has been received and report the static stats about the config.
      *
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 1dcd853..e1ab5d5 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "logd/LogEvent.h"
 
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -294,6 +294,28 @@
     }
 }
 
+int LogEvent::GetInt(size_t key, status_t* err) const {
+  DimensionsValue value;
+  if (!GetSimpleAtomDimensionsValueProto(key, &value)) {
+    *err = BAD_INDEX;
+    return 0;
+  }
+  const DimensionsValue* leafValue = getSingleLeafValue(&value);
+  switch (leafValue->value_case()) {
+    case DimensionsValue::ValueCase::kValueInt:
+      return leafValue->value_int();
+    case DimensionsValue::ValueCase::kValueLong:
+    case DimensionsValue::ValueCase::kValueBool:
+    case DimensionsValue::ValueCase::kValueFloat:
+    case DimensionsValue::ValueCase::kValueTuple:
+    case DimensionsValue::ValueCase::kValueStr:
+    case DimensionsValue::ValueCase::VALUE_NOT_SET: {
+      *err = BAD_TYPE;
+      return 0;
+    }
+  }
+}
+
 const char* LogEvent::GetString(size_t key, status_t* err) const {
     DimensionsValue value;
     if (!GetSimpleAtomDimensionsValueProto(key, &value)) {
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index eb2c008..d521e09 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -76,6 +76,7 @@
      * Returns BAD_TYPE if the index is available but the data is the wrong type.
      */
     int64_t GetLong(size_t key, status_t* err) const;
+    int GetInt(size_t key, status_t* err) const;
     const char* GetString(size_t key, status_t* err) const;
     bool GetBool(size_t key, status_t* err) const;
     float GetFloat(size_t key, status_t* err) const;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index ae4df3e..5a042b6 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -45,8 +45,6 @@
 
 // for StatsLogReport
 const int FIELD_ID_ID = 1;
-const int FIELD_ID_START_REPORT_NANOS = 2;
-const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_COUNT_METRICS = 5;
 // for CountMetricDataWrapper
 const int FIELD_ID_DATA = 1;
@@ -97,7 +95,6 @@
 void CountMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
     flushIfNeededLocked(dumpTimeNs);
     report->set_metric_id(mMetricId);
-    report->set_start_report_nanos(mStartTimeNs);
 
     auto count_metrics = report->mutable_count_metrics();
     for (const auto& counter : mPastBuckets) {
@@ -123,7 +120,6 @@
     }
 
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
 
     VLOG("metric %lld dump report now...",(long long)mMetricId);
@@ -167,10 +163,8 @@
     }
 
     protoOutput->end(protoToken);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
 
     mPastBuckets.clear();
-    mStartTimeNs = mCurrentBucketStartTimeNs;
 
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
@@ -214,13 +208,11 @@
     }
 
     auto it = mCurrentSlicedCounter->find(eventKey);
-
     if (it == mCurrentSlicedCounter->end()) {
         // ===========GuardRail==============
         if (hitGuardRailLocked(eventKey)) {
             return;
         }
-
         // create a counter for the new key
         (*mCurrentSlicedCounter)[eventKey] = 1;
     } else {
@@ -228,10 +220,14 @@
         auto& count = it->second;
         count++;
     }
-
     for (auto& tracker : mAnomalyTrackers) {
+        int64_t countWholeBucket = mCurrentSlicedCounter->find(eventKey)->second;
+        auto prev = mCurrentFullCounters->find(eventKey);
+        if (prev != mCurrentFullCounters->end()) {
+            countWholeBucket += prev->second;
+        }
         tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey,
-                                         mCurrentSlicedCounter->find(eventKey)->second);
+                                         countWholeBucket);
     }
 
     VLOG("metric %lld %s->%lld", (long long)mMetricId, eventKey.c_str(),
@@ -241,33 +237,65 @@
 // When a new matched event comes in, we check if event falls into the current
 // bucket. If not, flush the old counter to past buckets and initialize the new bucket.
 void CountMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
-    if (eventTimeNs < mCurrentBucketStartTimeNs + mBucketSizeNs) {
+    uint64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
+    if (eventTimeNs < currentBucketEndTimeNs) {
         return;
     }
 
+    flushCurrentBucketLocked(eventTimeNs);
+    // Setup the bucket start time and number.
+    uint64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
+    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    mCurrentBucketNum += numBucketsForward;
+    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
+         (long long)mCurrentBucketStartTimeNs);
+}
+
+void CountMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) {
+    uint64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
     CountBucket info;
     info.mBucketStartNs = mCurrentBucketStartTimeNs;
-    info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
+    if (eventTimeNs < fullBucketEndTimeNs) {
+        info.mBucketEndNs = eventTimeNs;
+    } else {
+        info.mBucketEndNs = fullBucketEndTimeNs;
+    }
     info.mBucketNum = mCurrentBucketNum;
     for (const auto& counter : *mCurrentSlicedCounter) {
         info.mCount = counter.second;
         auto& bucketList = mPastBuckets[counter.first];
         bucketList.push_back(info);
-        VLOG("metric %lld, dump key value: %s -> %lld",
-            (long long)mMetricId, counter.first.c_str(), (long long)counter.second);
+        VLOG("metric %lld, dump key value: %s -> %lld", (long long)mMetricId, counter.first.c_str(),
+             (long long)counter.second);
     }
 
-    for (auto& tracker : mAnomalyTrackers) {
-        tracker->addPastBucket(mCurrentSlicedCounter, mCurrentBucketNum);
+    // If we have finished a full bucket, then send this to anomaly tracker.
+    if (eventTimeNs > fullBucketEndTimeNs) {
+        // Accumulate partial buckets with current value and then send to anomaly tracker.
+        if (mCurrentFullCounters->size() > 0) {
+            for (const auto& keyValuePair : *mCurrentSlicedCounter) {
+                (*mCurrentFullCounters)[keyValuePair.first] += keyValuePair.second;
+            }
+            for (auto& tracker : mAnomalyTrackers) {
+                tracker->addPastBucket(mCurrentFullCounters, mCurrentBucketNum);
+            }
+            mCurrentFullCounters = std::make_shared<DimToValMap>();
+        } else {
+            // Skip aggregating the partial buckets since there's no previous partial bucket.
+            for (auto& tracker : mAnomalyTrackers) {
+                tracker->addPastBucket(mCurrentSlicedCounter, mCurrentBucketNum);
+            }
+        }
+    } else {
+        // Accumulate partial bucket.
+        for (const auto& keyValuePair : *mCurrentSlicedCounter) {
+            (*mCurrentFullCounters)[keyValuePair.first] += keyValuePair.second;
+        }
     }
 
-    // Reset counters (do not clear, since the old one is still referenced in mAnomalyTrackers).
+    // Only resets the counters, but doesn't setup the times nor numbers.
+    // (Do not clear since the old one is still referenced in mAnomalyTrackers).
     mCurrentSlicedCounter = std::make_shared<DimToValMap>();
-    uint64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
-    mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
-    mCurrentBucketNum += numBucketsForward;
-    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
-         (long long)mCurrentBucketStartTimeNs);
 }
 
 // Rough estimate of CountMetricProducer buffer stored. This number will be
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 8659d47..b06c77b 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -71,14 +71,20 @@
     void dumpStatesLocked(FILE* out, bool verbose) const override{};
 
     // Util function to flush the old packet.
-    void flushIfNeededLocked(const uint64_t& newEventTime);
+    void flushIfNeededLocked(const uint64_t& newEventTime) override;
+
+    void flushCurrentBucketLocked(const uint64_t& eventTimeNs) override;
 
     // TODO: Add a lock to mPastBuckets.
     std::unordered_map<MetricDimensionKey, std::vector<CountBucket>> mPastBuckets;
 
-    // The current bucket.
+    // The current bucket (may be a partial bucket).
     std::shared_ptr<DimToValMap> mCurrentSlicedCounter = std::make_shared<DimToValMap>();
 
+    // The sum of previous partial buckets in the current full bucket (excluding the current
+    // partial bucket). This is only updated while flushing the current bucket.
+    std::shared_ptr<DimToValMap> mCurrentFullCounters = std::make_shared<DimToValMap>();
+
     static const size_t kBucketSize = sizeof(CountBucket{});
 
     bool hitGuardRailLocked(const MetricDimensionKey& newKey);
@@ -87,6 +93,8 @@
     FRIEND_TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition);
     FRIEND_TEST(CountMetricProducerTest, TestEventsWithSlicedCondition);
     FRIEND_TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced);
+    FRIEND_TEST(CountMetricProducerTest, TestEventWithAppUpgrade);
+    FRIEND_TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index efbdae1..65cbc4a 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -44,8 +44,6 @@
 
 // for StatsLogReport
 const int FIELD_ID_ID = 1;
-const int FIELD_ID_START_REPORT_NANOS = 2;
-const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_DURATION_METRICS = 6;
 // for DurationMetricDataWrapper
 const int FIELD_ID_DATA = 1;
@@ -121,13 +119,13 @@
         case DurationMetric_AggregationType_SUM:
             return make_unique<OringDurationTracker>(
                     mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
-                    mDimensionsInCondition, mNested,
-                    mCurrentBucketStartTimeNs, mBucketSizeNs, mConditionSliced, mAnomalyTrackers);
+                    mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
+                    mStartTimeNs, mBucketSizeNs, mConditionSliced, mAnomalyTrackers);
         case DurationMetric_AggregationType_MAX_SPARSE:
             return make_unique<MaxDurationTracker>(
                     mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex,
-                    mDimensionsInCondition, mNested,
-                    mCurrentBucketStartTimeNs, mBucketSizeNs, mConditionSliced, mAnomalyTrackers);
+                    mDimensionsInCondition, mNested, mCurrentBucketStartTimeNs, mCurrentBucketNum,
+                    mStartTimeNs, mBucketSizeNs, mConditionSliced, mAnomalyTrackers);
     }
 }
 
@@ -179,7 +177,6 @@
 void DurationMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
     flushIfNeededLocked(dumpTimeNs);
     report->set_metric_id(mMetricId);
-    report->set_start_report_nanos(mStartTimeNs);
 
     auto duration_metrics = report->mutable_duration_metrics();
     for (const auto& pair : mPastBuckets) {
@@ -205,7 +202,6 @@
     }
 
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
 
     VLOG("metric %lld dump report now...", (long long)mMetricId);
@@ -250,19 +246,19 @@
     }
 
     protoOutput->end(protoToken);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
     mPastBuckets.clear();
-    mStartTimeNs = mCurrentBucketStartTimeNs;
 }
 
-void DurationMetricProducer::flushIfNeededLocked(const uint64_t& eventTime) {
-    if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
+void DurationMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
+    uint64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
+
+    if (currentBucketEndTimeNs > eventTimeNs) {
         return;
     }
     VLOG("flushing...........");
     for (auto it = mCurrentSlicedDurationTrackerMap.begin();
             it != mCurrentSlicedDurationTrackerMap.end();) {
-        if (it->second->flushIfNeeded(eventTime, &mPastBuckets)) {
+        if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) {
             VLOG("erase bucket for key %s", it->first.c_str());
             it = mCurrentSlicedDurationTrackerMap.erase(it);
         } else {
@@ -270,11 +266,23 @@
         }
     }
 
-    int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
-    mCurrentBucketStartTimeNs += numBucketsForward * mBucketSizeNs;
+    int numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
+    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
     mCurrentBucketNum += numBucketsForward;
 }
 
+void DurationMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) {
+    for (auto it = mCurrentSlicedDurationTrackerMap.begin();
+         it != mCurrentSlicedDurationTrackerMap.end();) {
+        if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
+            VLOG("erase bucket for key %s", it->first.c_str());
+            it = mCurrentSlicedDurationTrackerMap.erase(it);
+        } else {
+            ++it;
+        }
+    }
+}
+
 void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
     if (mCurrentSlicedDurationTrackerMap.size() == 0) {
         return;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 152e570..a496016 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -73,6 +73,8 @@
     // Util function to flush the old packet.
     void flushIfNeededLocked(const uint64_t& eventTime);
 
+    void flushCurrentBucketLocked(const uint64_t& eventTimeNs) override;
+
     const DurationMetric_AggregationType mAggregationType;
 
     // Index of the SimpleAtomMatcher which defines the start.
@@ -112,6 +114,10 @@
 
     FRIEND_TEST(DurationMetricTrackerTest, TestNoCondition);
     FRIEND_TEST(DurationMetricTrackerTest, TestNonSlicedCondition);
+    FRIEND_TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade);
+    FRIEND_TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket);
+    FRIEND_TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade);
+    FRIEND_TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket);
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicates);
 };
 
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 820d591..936a2ef1 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -42,8 +42,6 @@
 
 // for StatsLogReport
 const int FIELD_ID_ID = 1;
-const int FIELD_ID_START_REPORT_NANOS = 2;
-const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_EVENT_METRICS = 4;
 // for EventMetricDataWrapper
 const int FIELD_ID_DATA = 1;
@@ -61,9 +59,7 @@
                                metric.links().end());
         mConditionSliced = true;
     }
-
-    startNewProtoOutputStreamLocked();
-
+    mProto = std::make_unique<ProtoOutputStream>();
     VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
          (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
@@ -72,10 +68,6 @@
     VLOG("~EventMetricProducer() called");
 }
 
-void EventMetricProducer::startNewProtoOutputStreamLocked() {
-    mProto = std::make_unique<ProtoOutputStream>();
-}
-
 void EventMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
 }
 
@@ -106,8 +98,6 @@
         return;
     }
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
 
     size_t bufferSize = mProto->size();
     VLOG("metric %lld dump report now... proto size: %zu ",
@@ -117,8 +107,7 @@
     protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS,
                        reinterpret_cast<char*>(buffer.get()->data()), buffer.get()->size());
 
-    startNewProtoOutputStreamLocked();
-    mStartTimeNs = dumpTimeNs;
+    mProto->clear();
 }
 
 void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 935f206..394ed23 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -40,9 +40,6 @@
 
     virtual ~EventMetricProducer();
 
-protected:
-    void startNewProtoOutputStreamLocked();
-
 private:
     void onMatchedLogEventInternalLocked(
             const size_t matcherIndex, const MetricDimensionKey& eventKey,
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index d6cb189..62ee6ef 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -45,8 +45,6 @@
 
 // for StatsLogReport
 const int FIELD_ID_ID = 1;
-const int FIELD_ID_START_REPORT_NANOS = 2;
-const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_GAUGE_METRICS = 8;
 // for GaugeMetricDataWrapper
 const int FIELD_ID_DATA = 1;
@@ -134,7 +132,6 @@
     }
 
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
 
     for (const auto& pair : mPastBuckets) {
@@ -188,13 +185,22 @@
         protoOutput->end(wrapperToken);
     }
     protoOutput->end(protoToken);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
 
     mPastBuckets.clear();
-    mStartTimeNs = mCurrentBucketStartTimeNs;
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
+void GaugeMetricProducer::pullLocked() {
+    vector<std::shared_ptr<LogEvent>> allData;
+    if (!mStatsPullerManager->Pull(mPullTagId, &allData)) {
+        ALOGE("Stats puller failed for tag: %d", mPullTagId);
+        return;
+    }
+    for (const auto& data : allData) {
+        onMatchedLogEventLocked(0, *data);
+    }
+}
+
 void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
                                                    const uint64_t eventTime) {
     VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
@@ -326,7 +332,6 @@
 }
 
 void GaugeMetricProducer::updateCurrentSlicedBucketForAnomaly() {
-    mCurrentSlicedBucketForAnomaly->clear();
     status_t err = NO_ERROR;
     for (const auto& slice : *mCurrentSlicedBucket) {
         if (slice.second.empty() || slice.second.front().mFields->empty()) {
@@ -349,42 +354,57 @@
 // if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside
 // the GaugeMetricProducer while holding the lock.
 void GaugeMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
-    if (eventTimeNs < mCurrentBucketStartTimeNs + mBucketSizeNs) {
+    uint64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
+
+    if (eventTimeNs < currentBucketEndTimeNs) {
         VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
              (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
         return;
     }
 
+    flushCurrentBucketLocked(eventTimeNs);
+
+    // Adjusts the bucket start and end times.
+    int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
+    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    mCurrentBucketNum += numBucketsForward;
+    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
+         (long long)mCurrentBucketStartTimeNs);
+}
+
+void GaugeMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) {
+    uint64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
+
     GaugeBucket info;
     info.mBucketStartNs = mCurrentBucketStartTimeNs;
-    info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
+    if (eventTimeNs < fullBucketEndTimeNs) {
+        info.mBucketEndNs = eventTimeNs;
+    } else {
+        info.mBucketEndNs = fullBucketEndTimeNs;
+    }
     info.mBucketNum = mCurrentBucketNum;
 
     for (const auto& slice : *mCurrentSlicedBucket) {
         info.mGaugeAtoms = slice.second;
         auto& bucketList = mPastBuckets[slice.first];
         bucketList.push_back(info);
-        VLOG("gauge metric %lld, dump key value: %s",
-            (long long)mMetricId, slice.first.c_str());
+        VLOG("gauge metric %lld, dump key value: %s", (long long)mMetricId, slice.first.c_str());
     }
 
-    // Reset counters
+    // If we have anomaly trackers, we need to update the partial bucket values.
     if (mAnomalyTrackers.size() > 0) {
         updateCurrentSlicedBucketForAnomaly();
-        for (auto& tracker : mAnomalyTrackers) {
-            tracker->addPastBucket(mCurrentSlicedBucketForAnomaly, mCurrentBucketNum);
+
+        if (eventTimeNs > fullBucketEndTimeNs) {
+            // This is known to be a full bucket, so send this data to the anomaly tracker.
+            for (auto& tracker : mAnomalyTrackers) {
+                tracker->addPastBucket(mCurrentSlicedBucketForAnomaly, mCurrentBucketNum);
+            }
+            mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
         }
     }
 
-    mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
     mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
-
-    // Adjusts the bucket start time
-    int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
-    mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
-    mCurrentBucketNum += numBucketsForward;
-    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
-         (long long)mCurrentBucketStartTimeNs);
 }
 
 size_t GaugeMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 86d0ccd..d5d34be 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -62,6 +62,22 @@
     // Handles when the pulled data arrives.
     void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
 
+    // GaugeMetric needs to immediately trigger another pull when we create the partial bucket.
+    void notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid,
+                          const int64_t version) override {
+        std::lock_guard<std::mutex> lock(mMutex);
+
+        if (eventTimeNs > getCurrentBucketEndTimeNs()) {
+            // Flush full buckets on the normal path up to the latest bucket boundary.
+            flushIfNeededLocked(eventTimeNs);
+        }
+        flushCurrentBucketLocked(eventTimeNs);
+        mCurrentBucketStartTimeNs = eventTimeNs;
+        if (mPullTagId != -1) {
+            pullLocked();
+        }
+    };
+
 protected:
     void onMatchedLogEventInternalLocked(
             const size_t matcherIndex, const MetricDimensionKey& eventKey,
@@ -91,7 +107,11 @@
     void dumpStatesLocked(FILE* out, bool verbose) const override{};
 
     // Util function to flush the old packet.
-    void flushIfNeededLocked(const uint64_t& eventTime);
+    void flushIfNeededLocked(const uint64_t& eventTime) override;
+
+    void flushCurrentBucketLocked(const uint64_t& eventTimeNs) override;
+
+    void pullLocked();
 
     std::shared_ptr<StatsPullerManager> mStatsPullerManager;
     // tagId for pulled data. -1 if this is not pulled
@@ -101,13 +121,15 @@
     // TODO: Add a lock to mPastBuckets.
     std::unordered_map<MetricDimensionKey, std::vector<GaugeBucket>> mPastBuckets;
 
-    // The current bucket.
+    // The current partial bucket.
     std::shared_ptr<DimToGaugeAtomsMap> mCurrentSlicedBucket;
 
-    // The current bucket for anomaly detection.
+    // The current full bucket for anomaly detection. This is updated to the latest value seen for
+    // this slice (ie, for partial buckets, we use the last partial bucket in this full bucket).
     std::shared_ptr<DimToValMap> mCurrentSlicedBucketForAnomaly;
 
-    // Translate Atom based bucket to single numeric value bucket for anomaly
+    // Translate Atom based bucket to single numeric value bucket for anomaly and updates the map
+    // for each slice with the latest value.
     void updateCurrentSlicedBucketForAnomaly();
 
     // Whitelist of fields to report. Empty means all are reported.
@@ -125,6 +147,8 @@
 
     FRIEND_TEST(GaugeMetricProducerTest, TestWithCondition);
     FRIEND_TEST(GaugeMetricProducerTest, TestNoCondition);
+    FRIEND_TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade);
+    FRIEND_TEST(GaugeMetricProducerTest, TestPulledWithUpgrade);
     FRIEND_TEST(GaugeMetricProducerTest, TestAnomalyDetection);
 };
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 3b1498f..542dd8a 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -53,15 +53,32 @@
 
     virtual ~MetricProducer(){};
 
-    void notifyAppUpgrade(const string& apk, const int uid, const int64_t version) override{
+    /**
+     * Forces this metric to split into a partial bucket right now. If we're past a full bucket, we
+     * first call the standard flushing code to flush up to the latest full bucket. Then we call
+     * the flush again when the end timestamp is forced to be now, and then after flushing, update
+     * the start timestamp to be now.
+     */
+    void notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid,
+                          const int64_t version) override {
+        std::lock_guard<std::mutex> lock(mMutex);
+
+        if (eventTimeNs > getCurrentBucketEndTimeNs()) {
+            // Flush full buckets on the normal path up to the latest bucket boundary.
+            flushIfNeededLocked(eventTimeNs);
+        }
+        // Now flush a partial bucket.
+        flushCurrentBucketLocked(eventTimeNs);
+        mCurrentBucketStartTimeNs = eventTimeNs;
+        // Don't update the current bucket number so that the anomaly tracker knows this bucket
+        // is a partial bucket and can merge it with the previous bucket.
+    };
+
+    void notifyAppRemoved(const uint64_t& eventTimeNs, const string& apk, const int uid) override{
             // TODO: Implement me.
     };
 
-    void notifyAppRemoved(const string& apk, const int uid) override{
-            // TODO: Implement me.
-    };
-
-    void onUidMapReceived() override{
+    void onUidMapReceived(const uint64_t& eventTimeNs) override{
             // TODO: Implement me.
     };
 
@@ -87,11 +104,12 @@
     };
 
     // Output the metrics data to [protoOutput]. All metrics reports end with the same timestamp.
+    // This method clears all the past buckets.
     void onDumpReport(const uint64_t dumpTimeNs, android::util::ProtoOutputStream* protoOutput) {
         std::lock_guard<std::mutex> lock(mMutex);
         return onDumpReportLocked(dumpTimeNs, protoOutput);
     }
-
+    // This method does not clear the past buckets.
     void onDumpReport(const uint64_t dumpTimeNs, StatsLogReport* report) {
         std::lock_guard<std::mutex> lock(mMutex);
         return onDumpReportLocked(dumpTimeNs, report);
@@ -136,15 +154,43 @@
     virtual size_t byteSizeLocked() const = 0;
     virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
 
+    /**
+     * Flushes the current bucket if the eventTime is after the current bucket's end time.
+     */
+    virtual void flushIfNeededLocked(const uint64_t& eventTime){};
+
+    /**
+     * For metrics that aggregate (ie, every metric producer except for EventMetricProducer),
+     * we need to be able to flush the current buckets on demand (ie, end the current bucket and
+     * start new bucket). If this function is called when eventTimeNs is greater than the current
+     * bucket's end timestamp, than we flush up to the end of the latest full bucket; otherwise,
+     * we assume that we want to flush a partial bucket. The bucket start timestamp and bucket
+     * number are not changed by this function. This method should only be called by
+     * flushIfNeededLocked or the app upgrade handler; the caller MUST update the bucket timestamp
+     * and bucket number as needed.
+     */
+    virtual void flushCurrentBucketLocked(const uint64_t& eventTimeNs){};
+
+    // Convenience to compute the current bucket's end time, which is always aligned with the
+    // start time of the metric.
+    uint64_t getCurrentBucketEndTimeNs() {
+        return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
+    }
+
     const int64_t mMetricId;
 
     const ConfigKey mConfigKey;
 
-    // The start time for the current in memory metrics data.
+    // The time when this metric producer was first created. The end time for the current bucket
+    // can be computed from this based on mCurrentBucketNum.
     uint64_t mStartTimeNs;
 
+    // Start time may not be aligned with the start of statsd if there is an app upgrade in the
+    // middle of a bucket.
     uint64_t mCurrentBucketStartTimeNs;
 
+    // Used by anomaly detector to track which bucket we are in. This is not sent with the produced
+    // report.
     uint64_t mCurrentBucketNum;
 
     int64_t mBucketSizeNs;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 417145c..6c21b05 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 #include "MetricsManager.h"
 #include "statslog.h"
@@ -28,6 +28,8 @@
 #include "stats_util.h"
 
 #include <log/logprint.h>
+#include <private/android_filesystem_config.h>
+#include <utils/SystemClock.h>
 
 using android::util::FIELD_COUNT_REPEATED;
 using android::util::FIELD_TYPE_MESSAGE;
@@ -47,7 +49,7 @@
 
 MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
                                const long timeBaseSec, sp<UidMap> uidMap)
-    : mConfigKey(key), mUidMap(uidMap), mStatsdUid(getStatsdUid()) {
+    : mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(0) {
     mConfigValid =
             initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
                              mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap,
@@ -59,9 +61,9 @@
         // mConfigValid = false;
         // ALOGE("Log source white list is empty! This config won't get any data.");
 
-        mAllowedUid.push_back(1000);
-        mAllowedUid.push_back(0);
-        mAllowedUid.push_back(mStatsdUid);
+        mAllowedUid.push_back(AID_ROOT);
+        mAllowedUid.push_back(AID_STATSD);
+        mAllowedUid.push_back(AID_SYSTEM);
         mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
     } else {
         for (const auto& source : config.allowed_log_source()) {
@@ -120,7 +122,8 @@
     return mConfigValid;
 }
 
-void MetricsManager::notifyAppUpgrade(const string& apk, const int uid, const int64_t version) {
+void MetricsManager::notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid,
+                                      const int64_t version) {
     // check if we care this package
     if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) == mAllowedPkg.end()) {
         return;
@@ -130,7 +133,8 @@
     initLogSourceWhiteList();
 }
 
-void MetricsManager::notifyAppRemoved(const string& apk, const int uid) {
+void MetricsManager::notifyAppRemoved(const uint64_t& eventTimeNs, const string& apk,
+                                      const int uid) {
     // check if we care this package
     if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) == mAllowedPkg.end()) {
         return;
@@ -140,7 +144,7 @@
     initLogSourceWhiteList();
 }
 
-void MetricsManager::onUidMapReceived() {
+void MetricsManager::onUidMapReceived(const uint64_t& eventTimeNs) {
     if (mAllowedPkg.size() == 0) {
         return;
     }
@@ -181,6 +185,7 @@
             protoOutput->end(token);
         }
     }
+    mLastReportTimeNs = ::android::elapsedRealtimeNano();
     VLOG("=========================Metric Reports End==========================");
 }
 
@@ -198,7 +203,7 @@
         // unless that caller is statsd itself (statsd is allowed to spoof uids).
         long appHookUid = event.GetLong(event.size()-2, &err);
         int32_t loggerUid = event.GetUid();
-        if (err != NO_ERROR || (loggerUid != appHookUid && loggerUid != mStatsdUid)) {
+        if (err != NO_ERROR || (loggerUid != appHookUid && loggerUid != AID_STATSD)) {
             VLOG("AppHook has invalid uid: claimed %ld but caller is %d", appHookUid, loggerUid);
             return;
         }
@@ -333,16 +338,6 @@
     return totalSize;
 }
 
-int32_t MetricsManager::getStatsdUid() {
-    auto suit = UidMap::sAidToUidMapping.find("AID_STATSD");
-    if (suit != UidMap::sAidToUidMapping.end()) {
-        return suit->second;
-    } else {
-        ALOGE("Statsd failed to find its own uid!");
-        return -1;
-    }
-}
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index a1220f9..2b30f44 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -51,11 +51,12 @@
 
     void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor);
 
-    void notifyAppUpgrade(const string& apk, const int uid, const int64_t version) override;
+    void notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid,
+                          const int64_t version) override;
 
-    void notifyAppRemoved(const string& apk, const int uid) override;
+    void notifyAppRemoved(const uint64_t& eventTimeNs, const string& apk, const int uid) override;
 
-    void onUidMapReceived() override;
+    void onUidMapReceived(const uint64_t& eventTimeNs) override;
 
     bool shouldAddUidMapListener() const {
         return !mAllowedPkg.empty();
@@ -63,6 +64,11 @@
 
     void dumpStates(FILE* out, bool verbose);
 
+    // Returns the elapsed realtime when this metric manager last reported metrics.
+    uint64_t getLastReportTimeNs() {
+        return mLastReportTimeNs;
+    };
+
     // Config source owner can call onDumpReport() to get all the metrics collected.
     virtual void onDumpReport(android::util::ProtoOutputStream* protoOutput);
     virtual void onDumpReport(const uint64_t& dumpTimeStampNs, ConfigMetricsReport* report);
@@ -75,11 +81,10 @@
 
     sp<UidMap> mUidMap;
 
-    // The uid of statsd.
-    const int32_t mStatsdUid;
-
     bool mConfigValid = false;
 
+    uint64_t mLastReportTimeNs;
+
     // The uid log sources from StatsdConfig.
     std::vector<int32_t> mAllowedUid;
 
@@ -139,9 +144,6 @@
 
     void initLogSourceWhiteList();
 
-    // Fetches the uid of statsd from UidMap.
-    static int32_t getStatsdUid();
-
     // The metrics that don't need to be uploaded or even reported.
     std::set<int64_t> mNoReportMetricIds;
 
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index c9cc7bb..7b1944c 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -48,8 +48,6 @@
 
 // for StatsLogReport
 const int FIELD_ID_ID = 1;
-const int FIELD_ID_START_REPORT_NANOS = 2;
-const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_VALUE_METRICS = 7;
 // for ValueMetricDataWrapper
 const int FIELD_ID_DATA = 1;
@@ -122,7 +120,6 @@
 void ValueMetricProducer::onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) {
     flushIfNeededLocked(dumpTimeNs);
     report->set_metric_id(mMetricId);
-    report->set_start_report_nanos(mStartTimeNs);
     auto value_metrics = report->mutable_value_metrics();
     for (const auto& pair : mPastBuckets) {
         ValueMetricData* metricData = value_metrics->add_data();
@@ -147,7 +144,6 @@
         return;
     }
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, (long long)mStartTimeNs);
     long long protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
 
     for (const auto& pair : mPastBuckets) {
@@ -186,11 +182,9 @@
         protoOutput->end(wrapperToken);
     }
     protoOutput->end(protoToken);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, (long long)dumpTimeNs);
 
     VLOG("metric %lld dump report now...", (long long)mMetricId);
     mPastBuckets.clear();
-    mStartTimeNs = mCurrentBucketStartTimeNs;
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
@@ -320,8 +314,13 @@
         interval.sum += value;
     }
 
+    long wholeBucketVal = interval.sum;
+    auto prev = mCurrentFullBucket.find(eventKey);
+    if (prev != mCurrentFullBucket.end()) {
+        wholeBucketVal += prev->second;
+    }
     for (auto& tracker : mAnomalyTrackers) {
-        tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, interval.sum);
+        tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, wholeBucketVal);
     }
 }
 
@@ -333,16 +332,39 @@
 }
 
 void ValueMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) {
-    if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
+    uint64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
+
+    if (currentBucketEndTimeNs > eventTimeNs) {
         VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
-             (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
+             (long long)(currentBucketEndTimeNs));
         return;
     }
+
+    flushCurrentBucketLocked(eventTimeNs);
+
+    int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
+    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    mCurrentBucketNum += numBucketsForward;
+
+    if (numBucketsForward > 1) {
+        VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
+    }
+    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
+         (long long)mCurrentBucketStartTimeNs);
+}
+
+void ValueMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) {
     VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
          (int)mCurrentSlicedBucket.size());
+    uint64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
+
     ValueBucket info;
     info.mBucketStartNs = mCurrentBucketStartTimeNs;
-    info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
+    if (eventTimeNs < fullBucketEndTimeNs) {
+        info.mBucketEndNs = eventTimeNs;
+    } else {
+        info.mBucketEndNs = fullBucketEndTimeNs;
+    }
     info.mBucketNum = mCurrentBucketNum;
 
     int tainted = 0;
@@ -352,27 +374,42 @@
         // it will auto create new vector of ValuebucketInfo if the key is not found.
         auto& bucketList = mPastBuckets[slice.first];
         bucketList.push_back(info);
-
-        for (auto& tracker : mAnomalyTrackers) {
-            if (tracker != nullptr) {
-                tracker->addPastBucket(slice.first, info.mValue, info.mBucketNum);
-            }
-        }
     }
     VLOG("%d tainted pairs in the bucket", tainted);
 
+    if (eventTimeNs > fullBucketEndTimeNs) {  // If full bucket, send to anomaly tracker.
+        // Accumulate partial buckets with current value and then send to anomaly tracker.
+        if (mCurrentFullBucket.size() > 0) {
+            for (const auto& slice : mCurrentSlicedBucket) {
+                mCurrentFullBucket[slice.first] += slice.second.sum;
+            }
+            for (const auto& slice : mCurrentFullBucket) {
+                for (auto& tracker : mAnomalyTrackers) {
+                    if (tracker != nullptr) {
+                        tracker->addPastBucket(slice.first, slice.second, mCurrentBucketNum);
+                    }
+                }
+            }
+            mCurrentFullBucket.clear();
+        } else {
+            // Skip aggregating the partial buckets since there's no previous partial bucket.
+            for (const auto& slice : mCurrentSlicedBucket) {
+                for (auto& tracker : mAnomalyTrackers) {
+                    if (tracker != nullptr) {
+                        tracker->addPastBucket(slice.first, slice.second.sum, mCurrentBucketNum);
+                    }
+                }
+            }
+        }
+    } else {
+        // Accumulate partial bucket.
+        for (const auto& slice : mCurrentSlicedBucket) {
+            mCurrentFullBucket[slice.first] += slice.second.sum;
+        }
+    }
+
     // Reset counters
     mCurrentSlicedBucket.clear();
-
-    int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
-    mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
-    mCurrentBucketNum += numBucketsForward;
-
-    if (numBucketsForward > 1) {
-        VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
-    }
-    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
-         (long long)mCurrentBucketStartTimeNs);
 }
 
 size_t ValueMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 121ec7d..bf5b7df 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -47,6 +47,39 @@
 
     void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
 
+    // ValueMetric needs special logic if it's a pulled atom.
+    void notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid,
+                          const int64_t version) override {
+        std::lock_guard<std::mutex> lock(mMutex);
+
+        if (mPullTagId != -1) {
+            vector<shared_ptr<LogEvent>> allData;
+            mStatsPullerManager->Pull(mPullTagId, &allData);
+            if (allData.size() == 0) {
+                // This shouldn't happen since this valuemetric is not useful now.
+            }
+
+            // Pretend the pulled data occurs right before the app upgrade event.
+            mCondition = false;
+            for (const auto& data : allData) {
+                data->setTimestampNs(eventTimeNs - 1);
+                onMatchedLogEventLocked(0, *data);
+            }
+
+            flushCurrentBucketLocked(eventTimeNs);
+            mCurrentBucketStartTimeNs = eventTimeNs;
+
+            mCondition = true;
+            for (const auto& data : allData) {
+                data->setTimestampNs(eventTimeNs);
+                onMatchedLogEventLocked(0, *data);
+            }
+        } else {  // For pushed value metric, we simply flush and reset the current bucket start.
+            flushCurrentBucketLocked(eventTimeNs);
+            mCurrentBucketStartTimeNs = eventTimeNs;
+        }
+    };
+
 protected:
     void onMatchedLogEventInternalLocked(
             const size_t matcherIndex, const MetricDimensionKey& eventKey,
@@ -70,7 +103,9 @@
     void dumpStatesLocked(FILE* out, bool verbose) const override{};
 
     // Util function to flush the old packet.
-    void flushIfNeededLocked(const uint64_t& eventTime);
+    void flushIfNeededLocked(const uint64_t& eventTime) override;
+
+    void flushCurrentBucketLocked(const uint64_t& eventTimeNs) override;
 
     const FieldMatcher mValueField;
 
@@ -101,6 +136,8 @@
 
     std::unordered_map<MetricDimensionKey, Interval> mCurrentSlicedBucket;
 
+    std::unordered_map<MetricDimensionKey, long> mCurrentFullBucket;
+
     // Save the past buckets and we can clear when the StatsLogReport is dumped.
     // TODO: Add a lock to mPastBuckets.
     std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>> mPastBuckets;
@@ -114,6 +151,8 @@
 
     FRIEND_TEST(ValueMetricProducerTest, TestNonDimensionalEvents);
     FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
+    FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade);
+    FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
 };
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 45735a8..356a81c 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -63,7 +63,8 @@
     DurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
                     sp<ConditionWizard> wizard, int conditionIndex,
                     const FieldMatcher& dimensionInCondition, bool nesting,
-                    uint64_t currentBucketStartNs, uint64_t bucketSizeNs, bool conditionSliced,
+                    uint64_t currentBucketStartNs, uint64_t currentBucketNum, uint64_t startTimeNs,
+                    uint64_t bucketSizeNs, bool conditionSliced,
                     const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
         : mConfigKey(key),
           mTrackerId(id),
@@ -75,7 +76,9 @@
           mNested(nesting),
           mCurrentBucketStartTimeNs(currentBucketStartNs),
           mDuration(0),
-          mCurrentBucketNum(0),
+          mDurationFullBucket(0),
+          mCurrentBucketNum(currentBucketNum),
+          mStartTimeNs(startTimeNs),
           mConditionSliced(conditionSliced),
           mAnomalyTrackers(anomalyTrackers){};
 
@@ -98,6 +101,12 @@
             uint64_t timestampNs,
             std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0;
 
+    // Should only be called during an app upgrade or from this tracker's flushIfNeeded. If from
+    // an app upgrade, we assume that we're trying to form a partial bucket.
+    virtual bool flushCurrentBucket(
+            const uint64_t& eventTimeNs,
+            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0;
+
     // Predict the anomaly timestamp given the current status.
     virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker,
                                               const uint64_t currentTimestamp) const = 0;
@@ -153,6 +162,13 @@
             }
         }
     }
+
+    // Convenience to compute the current bucket's end time, which is always aligned with the
+    // start time of the metric.
+    uint64_t getCurrentBucketEndTimeNs() {
+        return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
+    }
+
     // A reference to the DurationMetricProducer's config key.
     const ConfigKey& mConfigKey;
 
@@ -172,10 +188,14 @@
 
     uint64_t mCurrentBucketStartTimeNs;
 
-    int64_t mDuration;  // current recorded duration result
+    int64_t mDuration;  // current recorded duration result (for partial bucket)
+
+    int64_t mDurationFullBucket;  // Sum of past partial buckets in current full bucket.
 
     uint64_t mCurrentBucketNum;
 
+    const uint64_t mStartTimeNs;
+
     const bool mConditionSliced;
 
     std::vector<sp<DurationAnomalyTracker>> mAnomalyTrackers;
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index db7dea4..c3bafc6 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -28,11 +28,13 @@
                                        const MetricDimensionKey& eventKey,
                                        sp<ConditionWizard> wizard, int conditionIndex,
                                        const FieldMatcher& dimensionInCondition, bool nesting,
-                                       uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
+                                       uint64_t currentBucketStartNs, uint64_t currentBucketNum,
+                                       uint64_t startTimeNs, uint64_t bucketSizeNs,
                                        bool conditionSliced,
                                        const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
     : DurationTracker(key, id, eventKey, wizard, conditionIndex, dimensionInCondition, nesting,
-                      currentBucketStartNs, bucketSizeNs, conditionSliced, anomalyTrackers) {
+                      currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs,
+                      conditionSliced, anomalyTrackers) {
 }
 
 unique_ptr<DurationTracker> MaxDurationTracker::clone(const uint64_t eventTime) {
@@ -102,7 +104,6 @@
 
 void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
                                   bool forceStop) {
-    declareAnomalyIfAlarmExpired(eventTime);
     VLOG("MaxDuration: key %s stop", key.c_str());
     if (mInfos.find(key) == mInfos.end()) {
         // we didn't see a start event before. do nothing.
@@ -122,7 +123,7 @@
                 VLOG("Max, key %s, Stop %lld %lld %lld", key.c_str(),
                      (long long)duration.lastStartTime, (long long)eventTime,
                      (long long)durationTime);
-                duration.lastDuration = duration.lastDuration + durationTime;
+                duration.lastDuration += durationTime;
                 VLOG("  record duration: %lld ", (long long)duration.lastDuration);
             }
             break;
@@ -138,7 +139,6 @@
 
     if (duration.lastDuration > mDuration) {
         mDuration = duration.lastDuration;
-        detectAndDeclareAnomaly(eventTime, mCurrentBucketNum, mDuration);
         VLOG("Max: new max duration: %lld", (long long)mDuration);
     }
     // Once an atom duration ends, we erase it. Next time, if we see another atom event with the
@@ -158,88 +158,67 @@
     }
 }
 
-bool MaxDurationTracker::flushIfNeeded(
-        uint64_t eventTime, unordered_map<MetricDimensionKey, vector<DurationBucket>>* output) {
-    if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
-        return false;
-    }
-
+bool MaxDurationTracker::flushCurrentBucket(
+        const uint64_t& eventTimeNs,
+        std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) {
     VLOG("MaxDurationTracker flushing.....");
 
     // adjust the bucket start time
-    int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+    int numBucketsForward = 0;
+    uint64_t fullBucketEnd = getCurrentBucketEndTimeNs();
+    uint64_t currentBucketEndTimeNs;
+    if (eventTimeNs >= fullBucketEnd) {
+        numBucketsForward = 1 + (eventTimeNs - fullBucketEnd) / mBucketSizeNs;
+        currentBucketEndTimeNs = fullBucketEnd;
+    } else {
+        // This must be a partial bucket.
+        currentBucketEndTimeNs = eventTimeNs;
+    }
 
-    uint64_t endTime = mCurrentBucketStartTimeNs + mBucketSizeNs;
-
-    DurationBucket info;
-    info.mBucketStartNs = mCurrentBucketStartTimeNs;
-    info.mBucketEndNs = endTime;
-    info.mBucketNum = mCurrentBucketNum;
-
-    uint64_t oldBucketStartTimeNs = mCurrentBucketStartTimeNs;
-    mCurrentBucketStartTimeNs += (numBucketsForward)*mBucketSizeNs;
-
-    bool hasOnGoingStartedEvent = false;  // a kStarted event last across bucket boundaries.
     bool hasPendingEvent =
             false;  // has either a kStarted or kPaused event across bucket boundaries
-                    // meaning we need to carry them over to the new bucket.
+    // meaning we need to carry them over to the new bucket.
     for (auto it = mInfos.begin(); it != mInfos.end(); ++it) {
         int64_t finalDuration = it->second.lastDuration;
-        if (it->second.state == kStarted) {
-            // the event is still on-going, duration needs to be updated.
-            // |..lastDurationTime_recorded...last_start -----|bucket_end. We need to record the
-            // duration between lastStartTime and bucketEnd.
-            int64_t durationTime = endTime - it->second.lastStartTime;
-
-            finalDuration += durationTime;
-            VLOG("  unrecorded %lld -> %lld", (long long)(durationTime), (long long)finalDuration);
-            // if the event is still on-going, we need to fill the buckets between prev_bucket and
-            // now_bucket. |prev_bucket|...|..|...|now_bucket|
-            hasOnGoingStartedEvent = true;
-        }
-
-        if (finalDuration > mDuration) {
-            mDuration = finalDuration;
-        }
-
         if (it->second.state == DurationState::kStopped) {
             // No need to keep buckets for events that were stopped before.
             mInfos.erase(it);
         } else {
             hasPendingEvent = true;
-            // for kPaused, and kStarted event, we will keep track of them, and reset the start time
-            // and duration.
-            it->second.lastStartTime = mCurrentBucketStartTimeNs;
-            it->second.lastDuration = 0;
         }
     }
 
+    // mDuration is updated in noteStop to the maximum duration that ended in the current bucket.
     if (mDuration != 0) {
+        DurationBucket info;
+        info.mBucketStartNs = mCurrentBucketStartTimeNs;
+        info.mBucketEndNs = currentBucketEndTimeNs;
+        info.mBucketNum = mCurrentBucketNum;
         info.mDuration = mDuration;
         (*output)[mEventKey].push_back(info);
-        addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
         VLOG("  final duration for last bucket: %lld", (long long)mDuration);
     }
 
-    mDuration = 0;
-    if (hasOnGoingStartedEvent) {
-        for (int i = 1; i < numBucketsForward; i++) {
-            DurationBucket info;
-            info.mBucketStartNs = oldBucketStartTimeNs + mBucketSizeNs * i;
-            info.mBucketEndNs = endTime + mBucketSizeNs * i;
-            info.mBucketNum = mCurrentBucketNum + i;
-            info.mDuration = mBucketSizeNs;
-            (*output)[mEventKey].push_back(info);
-            addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
-            VLOG("  filling gap bucket with duration %lld", (long long)mBucketSizeNs);
-        }
+    if (numBucketsForward > 0) {
+        mCurrentBucketStartTimeNs = fullBucketEnd + (numBucketsForward - 1) * mBucketSizeNs;
+        mCurrentBucketNum += numBucketsForward;
+    } else {  // We must be forming a partial bucket.
+        mCurrentBucketStartTimeNs = eventTimeNs;
     }
 
-    mCurrentBucketNum += numBucketsForward;
+    mDuration = 0;
     // If this tracker has no pending events, tell owner to remove.
     return !hasPendingEvent;
 }
 
+bool MaxDurationTracker::flushIfNeeded(
+        uint64_t eventTimeNs, unordered_map<MetricDimensionKey, vector<DurationBucket>>* output) {
+    if (eventTimeNs < getCurrentBucketEndTimeNs()) {
+        return false;
+    }
+    return flushCurrentBucket(eventTimeNs, output);
+}
+
 void MaxDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) {
     // Now for each of the on-going event, check if the condition has changed for them.
     for (auto& pair : mInfos) {
@@ -267,7 +246,6 @@
 
 void MaxDurationTracker::noteConditionChanged(const HashableDimensionKey& key, bool conditionMet,
                                               const uint64_t timestamp) {
-    declareAnomalyIfAlarmExpired(timestamp);
     auto it = mInfos.find(key);
     if (it == mInfos.end()) {
         return;
@@ -297,7 +275,6 @@
     }
     if (it->second.lastDuration > mDuration) {
         mDuration = it->second.lastDuration;
-        detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration);
     }
 }
 
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index 4d32a06..fba4119 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -28,10 +28,11 @@
 // they stop or bucket expires.
 class MaxDurationTracker : public DurationTracker {
 public:
-    MaxDurationTracker(const ConfigKey& key, const int64_t& id,
-                       const MetricDimensionKey& eventKey, sp<ConditionWizard> wizard,
-                       int conditionIndex, const FieldMatcher& dimensionInCondition, bool nesting,
-                       uint64_t currentBucketStartNs, uint64_t bucketSizeNs, bool conditionSliced,
+    MaxDurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
+                       sp<ConditionWizard> wizard, int conditionIndex,
+                       const FieldMatcher& dimensionInCondition, bool nesting,
+                       uint64_t currentBucketStartNs, uint64_t currentBucketNum,
+                       uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced,
                        const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
 
     MaxDurationTracker(const MaxDurationTracker& tracker) = default;
@@ -47,6 +48,9 @@
     bool flushIfNeeded(
             uint64_t timestampNs,
             std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) override;
+    bool flushCurrentBucket(
+            const uint64_t& eventTimeNs,
+            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>*) override;
 
     void onSlicedConditionMayChange(const uint64_t timestamp) override;
     void onConditionChanged(bool condition, const uint64_t timestamp) override;
@@ -68,7 +72,6 @@
     FRIEND_TEST(MaxDurationTrackerTest, TestCrossBucketBoundary);
     FRIEND_TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition);
     FRIEND_TEST(MaxDurationTrackerTest, TestStopAll);
-    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyDetection);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index 0feae36..85f7b7c 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -26,12 +26,13 @@
 
 OringDurationTracker::OringDurationTracker(
         const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
-        sp<ConditionWizard> wizard, int conditionIndex,
-        const FieldMatcher& dimensionInCondition, bool nesting, uint64_t currentBucketStartNs,
-        uint64_t bucketSizeNs, bool conditionSliced,
+        sp<ConditionWizard> wizard, int conditionIndex, const FieldMatcher& dimensionInCondition,
+        bool nesting, uint64_t currentBucketStartNs, uint64_t currentBucketNum,
+        uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced,
         const vector<sp<DurationAnomalyTracker>>& anomalyTrackers)
     : DurationTracker(key, id, eventKey, wizard, conditionIndex, dimensionInCondition, nesting,
-                      currentBucketStartNs, bucketSizeNs, conditionSliced, anomalyTrackers),
+                      currentBucketStartNs, currentBucketNum, startTimeNs, bucketSizeNs,
+                      conditionSliced, anomalyTrackers),
       mStarted(),
       mPaused() {
     mLastStartTime = 0;
@@ -100,7 +101,7 @@
         }
         if (mStarted.empty()) {
             mDuration += (timestamp - mLastStartTime);
-            detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration);
+            detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration + mDurationFullBucket);
             VLOG("record duration %lld, total %lld ", (long long)timestamp - mLastStartTime,
                  (long long)mDuration);
         }
@@ -125,7 +126,7 @@
         mDuration += (timestamp - mLastStartTime);
         VLOG("Oring Stop all: record duration %lld %lld ", (long long)timestamp - mLastStartTime,
              (long long)mDuration);
-        detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration);
+        detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration + mDurationFullBucket);
     }
 
     stopAnomalyAlarm();
@@ -134,51 +135,83 @@
     mConditionKeyMap.clear();
 }
 
-bool OringDurationTracker::flushIfNeeded(
-        uint64_t eventTime, unordered_map<MetricDimensionKey, vector<DurationBucket>>* output) {
-    if (eventTime < mCurrentBucketStartTimeNs + mBucketSizeNs) {
-        return false;
-    }
+bool OringDurationTracker::flushCurrentBucket(
+        const uint64_t& eventTimeNs,
+        std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) {
     VLOG("OringDurationTracker Flushing.............");
-    // adjust the bucket start time
-    int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
-    DurationBucket current_info;
-    current_info.mBucketStartNs = mCurrentBucketStartTimeNs;
-    current_info.mBucketEndNs = current_info.mBucketStartNs + mBucketSizeNs;
-    current_info.mBucketNum = mCurrentBucketNum;
+
+    // Note that we have to mimic the bucket time changes we do in the
+    // MetricProducer#notifyAppUpgrade.
+
+    int numBucketsForward = 0;
+    uint64_t fullBucketEnd = getCurrentBucketEndTimeNs();
+    uint64_t currentBucketEndTimeNs;
+
+    if (eventTimeNs >= fullBucketEnd) {
+        numBucketsForward = 1 + (eventTimeNs - fullBucketEnd) / mBucketSizeNs;
+        currentBucketEndTimeNs = fullBucketEnd;
+    } else {
+        // This must be a partial bucket.
+        currentBucketEndTimeNs = eventTimeNs;
+    }
+
     // Process the current bucket.
     if (mStarted.size() > 0) {
-        mDuration += (current_info.mBucketEndNs - mLastStartTime);
+        mDuration += (currentBucketEndTimeNs - mLastStartTime);
     }
     if (mDuration > 0) {
+        DurationBucket current_info;
+        current_info.mBucketStartNs = mCurrentBucketStartTimeNs;
+        current_info.mBucketEndNs = currentBucketEndTimeNs;
+        current_info.mBucketNum = mCurrentBucketNum;
         current_info.mDuration = mDuration;
         (*output)[mEventKey].push_back(current_info);
-        addPastBucketToAnomalyTrackers(current_info.mDuration, current_info.mBucketNum);
+        mDurationFullBucket += mDuration;
+        if (eventTimeNs > fullBucketEnd) {
+            // End of full bucket, can send to anomaly tracker now.
+            addPastBucketToAnomalyTrackers(mDurationFullBucket, current_info.mBucketNum);
+            mDurationFullBucket = 0;
+        }
         VLOG("  duration: %lld", (long long)current_info.mDuration);
     }
 
     if (mStarted.size() > 0) {
         for (int i = 1; i < numBucketsForward; i++) {
             DurationBucket info;
-            info.mBucketStartNs = mCurrentBucketStartTimeNs + mBucketSizeNs * i;
+            info.mBucketStartNs = fullBucketEnd + mBucketSizeNs * (i - 1);
             info.mBucketEndNs = info.mBucketStartNs + mBucketSizeNs;
             info.mBucketNum = mCurrentBucketNum + i;
             info.mDuration = mBucketSizeNs;
             (*output)[mEventKey].push_back(info);
+            // Safe to send these buckets to anomaly tracker since they must be full buckets.
+            // If it's a partial bucket, numBucketsForward would be 0.
             addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
             VLOG("  add filling bucket with duration %lld", (long long)info.mDuration);
         }
     }
-    mCurrentBucketStartTimeNs += numBucketsForward * mBucketSizeNs;
-    mCurrentBucketNum += numBucketsForward;
 
-    mLastStartTime = mCurrentBucketStartTimeNs;
     mDuration = 0;
 
+    if (numBucketsForward > 0) {
+        mCurrentBucketStartTimeNs = fullBucketEnd + (numBucketsForward - 1) * mBucketSizeNs;
+        mCurrentBucketNum += numBucketsForward;
+    } else {  // We must be forming a partial bucket.
+        mCurrentBucketStartTimeNs = eventTimeNs;
+    }
+    mLastStartTime = mCurrentBucketStartTimeNs;
+
     // if all stopped, then tell owner it's safe to remove this tracker.
     return mStarted.empty() && mPaused.empty();
 }
 
+bool OringDurationTracker::flushIfNeeded(
+        uint64_t eventTimeNs, unordered_map<MetricDimensionKey, vector<DurationBucket>>* output) {
+    if (eventTimeNs < getCurrentBucketEndTimeNs()) {
+        return false;
+    }
+    return flushCurrentBucket(eventTimeNs, output);
+}
+
 void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) {
     declareAnomalyIfAlarmExpired(timestamp);
     vector<pair<HashableDimensionKey, int>> startedToPaused;
@@ -211,7 +244,7 @@
             mDuration += (timestamp - mLastStartTime);
             VLOG("Duration add %lld , to %lld ", (long long)(timestamp - mLastStartTime),
                  (long long)mDuration);
-            detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration);
+            detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration + mDurationFullBucket);
         }
     }
 
@@ -275,7 +308,7 @@
             mDuration += (timestamp - mLastStartTime);
             mPaused.insert(mStarted.begin(), mStarted.end());
             mStarted.clear();
-            detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration);
+            detectAndDeclareAnomaly(timestamp, mCurrentBucketNum, mDuration + mDurationFullBucket);
         }
     }
     if (mStarted.empty()) {
@@ -298,7 +331,7 @@
     // As we move into the future, old buckets get overwritten (so their old data is erased).
 
     // Sum of past durations. Will change as we overwrite old buckets.
-    int64_t pastNs = mDuration;
+    int64_t pastNs = mDuration + mDurationFullBucket;
     pastNs += anomalyTracker.getSumOverPastBuckets(mEventKey);
 
     // How much of the threshold is still unaccounted after considering pastNs.
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 75b5a81..73e50e0 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -30,7 +30,8 @@
     OringDurationTracker(const ConfigKey& key, const int64_t& id,
                          const MetricDimensionKey& eventKey, sp<ConditionWizard> wizard,
                          int conditionIndex, const FieldMatcher& dimensionInCondition, bool nesting,
-                         uint64_t currentBucketStartNs, uint64_t bucketSizeNs, bool conditionSliced,
+                         uint64_t currentBucketStartNs, uint64_t currentBucketNum,
+                         uint64_t startTimeNs, uint64_t bucketSizeNs, bool conditionSliced,
                          const std::vector<sp<DurationAnomalyTracker>>& anomalyTrackers);
 
     OringDurationTracker(const OringDurationTracker& tracker) = default;
@@ -46,6 +47,9 @@
     void onSlicedConditionMayChange(const uint64_t timestamp) override;
     void onConditionChanged(bool condition, const uint64_t timestamp) override;
 
+    bool flushCurrentBucket(
+            const uint64_t& eventTimeNs,
+            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) override;
     bool flushIfNeeded(
             uint64_t timestampNs,
             std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) override;
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index a0173ee..205c8e4 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "../condition/CombinationConditionTracker.h"
@@ -541,7 +541,7 @@
         ALOGE("initLogMatchingTrackers failed");
         return false;
     }
-    ALOGD("initLogMatchingTrackers succeed...");
+    VLOG("initLogMatchingTrackers succeed...");
 
     if (!initConditions(key, config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
                         trackerToConditionMap)) {
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index df29eb0..03cb364 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -28,13 +28,15 @@
 public:
     // Uid map will notify this listener that the app with apk name and uid has been upgraded to
     // the specified version.
-    virtual void notifyAppUpgrade(const std::string& apk, const int uid, const int64_t version) = 0;
+    virtual void notifyAppUpgrade(const uint64_t& eventTimeNs, const std::string& apk,
+                                  const int uid, const int64_t version) = 0;
 
     // Notify interested listeners that the given apk and uid combination no longer exits.
-    virtual void notifyAppRemoved(const std::string& apk, const int uid) = 0;
+    virtual void notifyAppRemoved(const uint64_t& eventTimeNs, const std::string& apk,
+                                  const int uid) = 0;
 
     // Notify the listener that the UidMap snapshot is available.
-    virtual void onUidMapReceived() = 0;
+    virtual void onUidMapReceived(const uint64_t& eventTimeNs) = 0;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 91279661..0d7b722 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "guardrail/StatsdStats.h"
@@ -119,7 +119,7 @@
     for (auto weakPtr : broadcastList) {
         auto strongPtr = weakPtr.promote();
         if (strongPtr != NULL) {
-            strongPtr->onUidMapReceived();
+            strongPtr->onUidMapReceived(timestamp);
         }
     }
 }
@@ -166,7 +166,7 @@
     for (auto weakPtr : broadcastList) {
         auto strongPtr = weakPtr.promote();
         if (strongPtr != NULL) {
-            strongPtr->notifyAppUpgrade(appName, uid, versionCode);
+            strongPtr->notifyAppUpgrade(timestamp, appName, uid, versionCode);
         }
     }
 }
@@ -239,7 +239,7 @@
     for (auto weakPtr : broadcastList) {
         auto strongPtr = weakPtr.promote();
         if (strongPtr != NULL) {
-            strongPtr->notifyAppRemoved(app, uid);
+            strongPtr->notifyAppRemoved(timestamp, app, uid);
         }
     }
 }
@@ -316,13 +316,13 @@
     mLastUpdatePerConfigKey[key] = timestamp;
     int64_t newMin = getMinimumTimestampNs();
 
-    if (newMin > prevMin) {
+    if (newMin > prevMin) {  // Delete anything possible now that the minimum has moved forward.
         int64_t cutoff_nanos = newMin;
         auto snapshots = mOutput.mutable_snapshots();
         auto it_snapshots = snapshots->cbegin();
         while (it_snapshots != snapshots->cend()) {
             if (it_snapshots->timestamp_nanos() < cutoff_nanos) {
-                // it_snapshots now points to the following element.
+                // it_snapshots points to the following element after erasing.
                 it_snapshots = snapshots->erase(it_snapshots);
             } else {
                 ++it_snapshots;
@@ -332,7 +332,7 @@
         auto it_deltas = deltas->cbegin();
         while (it_deltas != deltas->cend()) {
             if (it_deltas->timestamp_nanos() < cutoff_nanos) {
-                // it_deltas now points to the following element.
+                // it_snapshots points to the following element after erasing.
                 it_deltas = deltas->erase(it_deltas);
             } else {
                 ++it_deltas;
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 3304f6c..f1da452 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -91,7 +91,7 @@
     void removeIsolatedUid(int isolatedUid, int parentUid);
 
     // Returns the host uid if it exists. Otherwise, returns the same uid that was passed-in.
-    int getHostUidOrSelf(int uid) const;
+    virtual int getHostUidOrSelf(int uid) const;
 
     // Gets the output. If every config key has received the output, then the output is cleared.
     UidMapping getOutput(const ConfigKey& key);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index af21ca4..b56cffb 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -143,9 +143,7 @@
 message StatsLogReport {
   optional int64 metric_id = 1;
 
-  optional int64 start_report_nanos = 2;
-
-  optional int64 end_report_nanos = 3;
+  // Fields 2 and 3 are reserved.
 
   message EventMetricDataWrapper {
     repeated EventMetricData data = 1;
@@ -177,6 +175,10 @@
   repeated StatsLogReport metrics = 1;
 
   optional UidMapping uid_map = 2;
+
+  optional int64 last_report_nanos = 3;
+
+  optional int64 current_report_nanos = 4;
 }
 
 message ConfigMetricsReportList {
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 3eaf7a1..5a326a4 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -275,6 +275,12 @@
 
 message IncidentdDetails {
   repeated int32 section = 1;
+
+  enum Destination {
+    AUTOMATIC = 0;
+    EXPLICIT = 1;
+  }
+  optional Destination dest = 2;
 }
 
 message PerfettoDetails {
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 00d8658..23bd5561 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "android-base/stringprintf.h"
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
new file mode 100644
index 0000000..d9a8fc8
--- /dev/null
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+#define DEBUG true
+#include "Log.h"
+
+#include "IncidentdReporter.h"
+#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
+
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
+                            const ConfigKey& configKey) {
+    if (config.section_size() == 0) {
+        VLOG("The alert %lld contains zero section in config(%d,%lld)", alert.id(),
+            configKey.GetUid(), (long long) configKey.GetId());
+        return false;
+    }
+
+    IncidentReportArgs incidentReport;
+
+    android::os::IncidentHeaderProto header;
+    header.set_alert_id(alert.id());
+    header.mutable_config_key()->set_uid(configKey.GetUid());
+    header.mutable_config_key()->set_id(configKey.GetId());
+    incidentReport.addHeader(header);
+
+    for (int i = 0; i < config.section_size(); i++) {
+        incidentReport.addSection(config.section(i));
+    }
+
+    uint8_t dest;
+    switch (config.dest()) {
+        case IncidentdDetails_Destination_AUTOMATIC:
+            dest = android::os::DEST_AUTOMATIC;
+            break;
+        case IncidentdDetails_Destination_EXPLICIT:
+            dest = android::os::DEST_EXPLICIT;
+            break;
+        default:
+            dest = android::os::DEST_AUTOMATIC;
+    }
+    incidentReport.setDest(dest);
+
+    sp<IIncidentManager> service = interface_cast<IIncidentManager>(
+            defaultServiceManager()->getService(android::String16("incident")));
+    if (service == nullptr) {
+        ALOGW("Failed to fetch incident service.");
+        return false;
+    }
+    VLOG("Calling incidentd %p", service.get());
+    binder::Status s = service->reportIncident(incidentReport);
+    VLOG("Report incident status: %s", s.toString8().string());
+    return s.isOk();
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.h b/cmds/statsd/src/subscriber/IncidentdReporter.h
new file mode 100644
index 0000000..229ed77
--- /dev/null
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.h
@@ -0,0 +1,34 @@
+/*
+ * 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 "config/ConfigKey.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // Alert, IncidentdDetails
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Calls incidentd to trigger an incident report and put in dropbox for uploading.
+ */
+bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
+                            const ConfigKey& configKey);
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 1186a16..a99dbe8 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -40,9 +40,11 @@
 
     auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
     // The predicate is dimensioning by any attribution node and both by uid and tag.
-    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
-        CreateAttributionUidAndTagDimensions(
+    FieldMatcher dimensions = CreateAttributionUidAndTagDimensions(
             android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST, Position::LAST});
+    // Also slice by the wakelock tag
+    dimensions.add_child()->set_field(3);  // The wakelock tag is set in field 3 of the wakelock.
+    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
     *config.add_predicate() = holdingWakelockPredicate;
 
     auto durationMetric = config.add_duration_metric();
@@ -58,133 +60,198 @@
     return config;
 }
 
-}  // namespace
+std::vector<AttributionNode> attributions1 = {CreateAttribution(111, "App1"),
+                                              CreateAttribution(222, "GMSCoreModule1"),
+                                              CreateAttribution(222, "GMSCoreModule2")};
 
-TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions) {
-    ConfigKey cfgKey;
-    for (auto aggregationType : { DurationMetric::SUM, DurationMetric::MAX_SPARSE }) {
-        auto config = CreateStatsdConfig(aggregationType);
-        uint64_t bucketStartTimeNs = 10000000000;
-        uint64_t bucketSizeNs =
+std::vector<AttributionNode> attributions2 = {CreateAttribution(111, "App2"),
+                                              CreateAttribution(222, "GMSCoreModule1"),
+                                              CreateAttribution(222, "GMSCoreModule2")};
+
+/*
+Events:
+Screen off is met from (200ns,1 min+500ns].
+Acquire event for wl1 from 2ns to 1min+2ns
+Acquire event for wl2 from 1min-10ns to 2min-15ns
+*/
+void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) {
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
-        auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
-        EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-        EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
-        auto screenTurnedOnEvent =
-            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-                                          bucketStartTimeNs + 1);
-        auto screenTurnedOffEvent =
-            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-                                          bucketStartTimeNs + 200);
-        auto screenTurnedOnEvent2 =
+    auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1);
+    auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200);
+    auto screenTurnedOnEvent2 =
             CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + bucketSizeNs + 500);
 
-        std::vector<AttributionNode> attributions1 =
-            {CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
-             CreateAttribution(222, "GMSCoreModule2")};
+    auto acquireEvent1 = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
+    auto releaseEvent1 =
+            CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
+    auto acquireEvent2 =
+            CreateAcquireWakelockEvent(attributions2, "wl2", bucketStartTimeNs + bucketSizeNs - 10);
+    auto releaseEvent2 = CreateReleaseWakelockEvent(attributions2, "wl2",
+                                                    bucketStartTimeNs + 2 * bucketSizeNs - 15);
 
-        std::vector<AttributionNode> attributions2 =
-            {CreateAttribution(111, "App2"), CreateAttribution(222, "GMSCoreModule1"),
-             CreateAttribution(222, "GMSCoreModule2")};
+    std::vector<std::unique_ptr<LogEvent>> events;
 
-        auto acquireEvent1 = CreateAcquireWakelockEvent(
-            attributions1, "wl1", bucketStartTimeNs + 2);
-        auto acquireEvent2 = CreateAcquireWakelockEvent(
-            attributions2, "wl2", bucketStartTimeNs + bucketSizeNs - 10);
+    events.push_back(std::move(screenTurnedOnEvent));
+    events.push_back(std::move(screenTurnedOffEvent));
+    events.push_back(std::move(screenTurnedOnEvent2));
+    events.push_back(std::move(acquireEvent1));
+    events.push_back(std::move(acquireEvent2));
+    events.push_back(std::move(releaseEvent1));
+    events.push_back(std::move(releaseEvent2));
 
-        auto releaseEvent1 = CreateReleaseWakelockEvent(
-            attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
-        auto releaseEvent2 = CreateReleaseWakelockEvent(
-            attributions2, "wl2", bucketStartTimeNs + 2 * bucketSizeNs - 15);
+    sortLogEventsByTimestamp(&events);
 
-
-        std::vector<std::unique_ptr<LogEvent>> events;
-
-        events.push_back(std::move(screenTurnedOnEvent));
-        events.push_back(std::move(screenTurnedOffEvent));
-        events.push_back(std::move(screenTurnedOnEvent2));
-        events.push_back(std::move(acquireEvent1));
-        events.push_back(std::move(acquireEvent2));
-        events.push_back(std::move(releaseEvent1));
-        events.push_back(std::move(releaseEvent2));
-
-        sortLogEventsByTimestamp(&events);
-
-        for (const auto& event : events) {
-            processor->OnLogEvent(event.get());
-        }
-
-        ConfigMetricsReportList reports;
-        processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &reports);
-        EXPECT_EQ(reports.reports_size(), 1);
-        EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-        // Only 1 dimension output. The tag dimension in the predicate has been aggregated.
-        EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-
-        auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-        // Validate dimension value.
-        ValidateAttributionUidDimension(
-            data.dimensions_in_what(),
-            android::util::WAKELOCK_STATE_CHANGED, 111);
-        // Validate bucket info.
-        EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
-        data = reports.reports(0).metrics(0).duration_metrics().data(0);
-        // The wakelock holding interval starts from the screen off event and to the end of the 1st
-        // bucket.
-        EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
-
-        reports.Clear();
-        processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
-        EXPECT_EQ(reports.reports_size(), 1);
-        EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-        EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-        // Dump the report after the end of 2nd bucket.
-        EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
-        data = reports.reports(0).metrics(0).duration_metrics().data(0);
-        // Validate dimension value.
-        ValidateAttributionUidDimension(
-            data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 111);
-        // Two output buckets.
-        // The wakelock holding interval in the 1st bucket starts from the screen off event and to
-        // the end of the 1st bucket.
-        EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(),
-            bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200));
-        // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
-        // ends at the second screen on event.
-        EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
-
-        events.clear();
-        events.push_back(CreateScreenStateChangedEvent(
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-            bucketStartTimeNs + 2 * bucketSizeNs + 90));
-        events.push_back(CreateAcquireWakelockEvent(
-            attributions1, "wl3", bucketStartTimeNs + 2 * bucketSizeNs + 100));
-        events.push_back(CreateReleaseWakelockEvent(
-            attributions1, "wl3", bucketStartTimeNs + 5 * bucketSizeNs + 100));
-        sortLogEventsByTimestamp(&events);
-        for (const auto& event : events) {
-            processor->OnLogEvent(event.get());
-        }
-        reports.Clear();
-        processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &reports);
-        EXPECT_EQ(reports.reports_size(), 1);
-        EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-        EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-        EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
-        data = reports.reports(0).metrics(0).duration_metrics().data(0);
-        ValidateAttributionUidDimension(
-            data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 111);
-        // The last wakelock holding spans 4 buckets.
-        EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
-        EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
-        EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
-        EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
     }
 }
 
+}  // namespace
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration) {
+    ConfigKey cfgKey;
+    auto config = CreateStatsdConfig(DurationMetric::SUM);
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    FeedEvents(config, processor);
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &reports);
+
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    // Only 1 dimension output. The tag dimension in the predicate has been aggregated.
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // Validate dimension value.
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // Validate bucket info.
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+    data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // The wakelock holding interval starts from the screen off event and to the end of the 1st
+    // bucket.
+    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
+
+    reports.Clear();
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+    // Dump the report after the end of 2nd bucket.
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+    data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // Validate dimension value.
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // Two output buckets.
+    // The wakelock holding interval in the 1st bucket starts from the screen off event and to
+    // the end of the 1st bucket.
+    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(),
+              bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200));
+    // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
+    // ends at the second screen on event.
+    EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                          bucketStartTimeNs + 2 * bucketSizeNs + 90));
+    events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3",
+                                                bucketStartTimeNs + 2 * bucketSizeNs + 100));
+    events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3",
+                                                bucketStartTimeNs + 5 * bucketSizeNs + 100));
+    sortLogEventsByTimestamp(&events);
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+    reports.Clear();
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
+    data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // The last wakelock holding spans 4 buckets.
+    EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
+    EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
+    EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
+    EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration) {
+    ConfigKey cfgKey;
+    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    FeedEvents(config, processor);
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, &reports);
+
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    // Nothing has ended in the first bucket.
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 0);
+
+    reports.Clear();
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, &reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+    // Dump the report after the end of 2nd bucket. One dimension with one bucket.
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // Validate dimension value.
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // The max is acquire event for wl1 to screen off start.
+    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200);
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                          bucketStartTimeNs + 2 * bucketSizeNs + 90));
+    events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3",
+                                                bucketStartTimeNs + 2 * bucketSizeNs + 100));
+    events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3",
+                                                bucketStartTimeNs + 5 * bucketSizeNs + 100));
+    sortLogEventsByTimestamp(&events);
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+    reports.Clear();
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, &reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+    data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // The last wakelock holding spans 4 buckets.
+    EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
+    EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_nanos(),
+              bucketStartTimeNs + 5 * bucketSizeNs);
+    EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_nanos(),
+              bucketStartTimeNs + 6 * bucketSizeNs);
+}
+
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp
new file mode 100644
index 0000000..7d9c8a8
--- /dev/null
+++ b/cmds/statsd/tests/external/puller_util_test.cpp
@@ -0,0 +1,269 @@
+// 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 "external/puller_util.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+#include "../metrics/metrics_test_helper.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace testing;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
+using testing::Contains;
+/*
+ * Test merge isolated and host uid
+ */
+
+int uidAtomTagId = android::util::CPU_TIME_PER_UID_FREQ;
+int nonUidAtomTagId = android::util::SYSTEM_UPTIME;
+int timestamp = 1234;
+int isolatedUid = 30;
+int isolatedAdditiveData = 31;
+int isolatedNonAdditiveData = 32;
+int hostUid = 20;
+int hostAdditiveData = 21;
+int hostNonAdditiveData = 22;
+
+void extractIntoVector(vector<shared_ptr<LogEvent>> events,
+                      vector<vector<int>>& ret) {
+  ret.clear();
+  status_t err;
+  for (const auto& event : events) {
+    vector<int> vec;
+    vec.push_back(event->GetInt(1, &err));
+    vec.push_back(event->GetInt(2, &err));
+    vec.push_back(event->GetInt(3, &err));
+    ret.push_back(vec);
+  }
+}
+
+TEST(puller_util, MergeNoDimension) {
+  vector<shared_ptr<LogEvent>> inputData;
+  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  // 30->22->31
+  event->write(isolatedUid);
+  event->write(hostNonAdditiveData);
+  event->write(isolatedAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  // 20->22->21
+  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  event->write(hostUid);
+  event->write(hostNonAdditiveData);
+  event->write(hostAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+  EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
+      .WillRepeatedly(Return(hostUid));
+  EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
+      .WillRepeatedly(ReturnArg<0>());
+  mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+  vector<vector<int>> actual;
+  extractIntoVector(inputData, actual);
+  vector<int> expectedV1 = {20, 22, 52};
+  EXPECT_EQ(1, (int)actual.size());
+  EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, MergeWithDimension) {
+  vector<shared_ptr<LogEvent>> inputData;
+  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  // 30->32->31
+  event->write(isolatedUid);
+  event->write(isolatedNonAdditiveData);
+  event->write(isolatedAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  // 20->32->21
+  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  event->write(hostUid);
+  event->write(isolatedNonAdditiveData);
+  event->write(hostAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  // 20->22->21
+  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  event->write(hostUid);
+  event->write(hostNonAdditiveData);
+  event->write(hostAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+  EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
+      .WillRepeatedly(Return(hostUid));
+  EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
+      .WillRepeatedly(ReturnArg<0>());
+  mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+  vector<vector<int>> actual;
+  extractIntoVector(inputData, actual);
+  vector<int> expectedV1 = {20, 22, 21};
+  vector<int> expectedV2 = {20, 32, 52};
+  EXPECT_EQ(2, (int)actual.size());
+  EXPECT_THAT(actual, Contains(expectedV1));
+  EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, NoMergeHostUidOnly) {
+  vector<shared_ptr<LogEvent>> inputData;
+  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  // 20->32->31
+  event->write(hostUid);
+  event->write(isolatedNonAdditiveData);
+  event->write(isolatedAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  // 20->22->21
+  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  event->write(hostUid);
+  event->write(hostNonAdditiveData);
+  event->write(hostAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+  EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
+      .WillRepeatedly(Return(hostUid));
+  EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
+      .WillRepeatedly(ReturnArg<0>());
+  mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+  // 20->32->31
+  // 20->22->21
+  vector<vector<int>> actual;
+  extractIntoVector(inputData, actual);
+  vector<int> expectedV1 = {20, 32, 31};
+  vector<int> expectedV2 = {20, 22, 21};
+  EXPECT_EQ(2, (int)actual.size());
+  EXPECT_THAT(actual, Contains(expectedV1));
+  EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, IsolatedUidOnly) {
+  vector<shared_ptr<LogEvent>> inputData;
+  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  // 30->32->31
+  event->write(hostUid);
+  event->write(isolatedNonAdditiveData);
+  event->write(isolatedAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  // 30->22->21
+  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  event->write(hostUid);
+  event->write(hostNonAdditiveData);
+  event->write(hostAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+  EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
+      .WillRepeatedly(Return(hostUid));
+  EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
+      .WillRepeatedly(ReturnArg<0>());
+  mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+  // 20->32->31
+  // 20->22->21
+  vector<vector<int>> actual;
+  extractIntoVector(inputData, actual);
+  vector<int> expectedV1 = {20, 32, 31};
+  vector<int> expectedV2 = {20, 22, 21};
+  EXPECT_EQ(2, (int)actual.size());
+  EXPECT_THAT(actual, Contains(expectedV1));
+  EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, MultipleIsolatedUidToOneHostUid) {
+  vector<shared_ptr<LogEvent>> inputData;
+  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  // 30->32->31
+  event->write(isolatedUid);
+  event->write(isolatedNonAdditiveData);
+  event->write(isolatedAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  // 31->32->21
+  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  event->write(isolatedUid + 1);
+  event->write(isolatedNonAdditiveData);
+  event->write(hostAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  // 20->32->21
+  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+  event->write(hostUid);
+  event->write(isolatedNonAdditiveData);
+  event->write(hostAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+  EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid));
+  mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+  vector<vector<int>> actual;
+  extractIntoVector(inputData, actual);
+  vector<int> expectedV1 = {20, 32, 73};
+  EXPECT_EQ(1, (int)actual.size());
+  EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, NoNeedToMerge) {
+  vector<shared_ptr<LogEvent>> inputData;
+  shared_ptr<LogEvent> event =
+      make_shared<LogEvent>(nonUidAtomTagId, timestamp);
+  // 32
+  event->write(isolatedNonAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  event = make_shared<LogEvent>(nonUidAtomTagId, timestamp);
+  // 22
+  event->write(hostNonAdditiveData);
+  event->init();
+  inputData.push_back(event);
+
+  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+  mergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId);
+
+  EXPECT_EQ(2, (int)inputData.size());
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 50b3532..87a1079 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -191,6 +191,117 @@
     EXPECT_EQ(1LL, bucketInfo.mCount);
 }
 
+TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+
+    int tagId = 1;
+    int conditionTagId = 2;
+
+    CountMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    Alert alert;
+    alert.set_num_buckets(3);
+    alert.set_trigger_if_sum_gt(2);
+    LogEvent event1(tagId, bucketStartTimeNs + 1);
+    event1.write("111");  // uid
+    event1.init();
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+                                      bucketStartTimeNs);
+    sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert);
+    EXPECT_TRUE(anomalyTracker != nullptr);
+
+    // Bucket is flushed yet.
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // App upgrade forces bucket flush.
+    // Check that there's a past bucket and the bucket end is not adjusted.
+    countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((long long)bucketStartTimeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+    EXPECT_EQ((long long)eventUpgradeTimeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
+    EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+    // Anomaly tracker only contains full buckets.
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    uint64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
+    // Next event occurs in same bucket as partial bucket created.
+    LogEvent event2(tagId, bucketStartTimeNs + 59 * NS_PER_SEC + 10);
+    event2.write("222");  // uid
+    event2.init();
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Third event in following bucket.
+    LogEvent event3(tagId, bucketStartTimeNs + 62 * NS_PER_SEC + 10);
+    event3.write("333");  // uid
+    event3.init();
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+
+    int tagId = 1;
+    int conditionTagId = 2;
+
+    CountMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    LogEvent event1(tagId, bucketStartTimeNs + 1);
+    event1.write("111");  // uid
+    event1.init();
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+                                      bucketStartTimeNs);
+
+    // Bucket is flushed yet.
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+    // App upgrade forces bucket flush.
+    // Check that there's a past bucket and the bucket end is not adjusted.
+    countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((int64_t)bucketStartTimeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+              (uint64_t)countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
+    EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+
+    // Next event occurs in same bucket as partial bucket created.
+    LogEvent event2(tagId, bucketStartTimeNs + 70 * NS_PER_SEC + 10);
+    event2.write("222");  // uid
+    event2.init();
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+
+    // Third event in following bucket.
+    LogEvent event3(tagId, bucketStartTimeNs + 121 * NS_PER_SEC + 10);
+    event3.write("333");  // uid
+    event3.init();
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((int64_t)eventUpgradeTimeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              (uint64_t)countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
+}
+
 TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
     Alert alert;
     alert.set_id(11);
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index c9fe252..23e15f7 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -116,6 +116,231 @@
     EXPECT_EQ(1ULL, buckets2[0].mDuration);
 }
 
+TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
+    /**
+     * The duration starts from the first bucket, through the two partial buckets (10-70sec),
+     * another bucket, and ends at the beginning of the next full bucket.
+     * Expected buckets:
+     *  - [10,25]: 14 secs
+     *  - [25,70]: All 45 secs
+     *  - [70,130]: All 60 secs
+     *  - [130, 210]: Only 5 secs (event ended at 135sec)
+     */
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+    uint64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
+    uint64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+    int tagId = 1;
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(
+            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
+            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    std::vector<DurationBucket> buckets =
+            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration);
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+    buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(3UL, buckets.size());
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
+    EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
+    /**
+     * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
+     *  - [10,70]: 59 secs
+     *  - [70,75]: 5 sec
+     *  - [75,130]: 55 secs
+     */
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+    uint64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
+    uint64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+    int tagId = 1;
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(
+            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
+            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    std::vector<DurationBucket> buckets =
+            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs);
+    EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+    buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(3UL, buckets.size());
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+    uint64_t startTimeNs = bucketStartTimeNs + 1;
+    uint64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
+
+    int tagId = 1;
+
+    // Setup metric with alert.
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+    Alert alert;
+    alert.set_num_buckets(3);
+    alert.set_trigger_if_sum_gt(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(
+            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
+            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+    sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert);
+    EXPECT_TRUE(anomalyTracker != nullptr);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
+              (uint64_t)anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+    uint64_t startTimeNs = bucketStartTimeNs + 1;
+    uint64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+    int tagId = 1;
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
+    LogEvent event1(tagId, startTimeNs);
+    event1.write("111");  // uid
+    event1.init();
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(
+            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
+            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+
+    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+    std::vector<DurationBucket> buckets =
+            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(1UL, buckets.size());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+    uint64_t startTimeNs = bucketStartTimeNs + 1;
+    uint64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
+
+    int tagId = 1;
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
+    LogEvent event1(tagId, startTimeNs);
+    event1.write("111");  // uid
+    event1.init();
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(
+            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
+            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, LogEvent(tagId, startTimeNs));
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    // Stop occurs in the same partial bucket as created for the app upgrade.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, LogEvent(tagId, endTimeNs));
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+    std::vector<DurationBucket> buckets =
+            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(1UL, buckets.size());
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 58be5b0..470d4d0 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -44,6 +44,7 @@
 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
 const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
+const uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
 
 TEST(GaugeMetricProducerTest, TestNoCondition) {
     GaugeMetric metric;
@@ -119,6 +120,143 @@
     EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mBucketNum);
 }
 
+TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_gauge_fields_filter()->set_include_all(true);
+
+    Alert alert;
+    alert.set_id(101);
+    alert.set_metric_id(metricId);
+    alert.set_trigger_if_sum_gt(25);
+    alert.set_num_buckets(100);
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      -1 /* -1 means no pulling */, bucketStartTimeNs,
+                                      pullerManager);
+    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert);
+    EXPECT_TRUE(anomalyTracker != nullptr);
+
+    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+    event1->write(1);
+    event1->write(10);
+    event1->init();
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
+    EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
+
+    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(0UL, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    // Partial buckets are not sent to anomaly tracker.
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Create an event in the same partial bucket.
+    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
+    event2->write(1);
+    event2->write(10);
+    event2->init();
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
+    EXPECT_EQ(0UL, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((uint64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    // Partial buckets are not sent to anomaly tracker.
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Next event should trigger creation of new bucket and send previous full bucket to anomaly
+    // tracker.
+    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
+    event3->write(1);
+    event3->write(10);
+    event3->init();
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((uint64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Next event should trigger creation of new bucket.
+    shared_ptr<LogEvent> event4 =
+            make_shared<LogEvent>(tagId, bucketStartTimeNs + 125 * NS_PER_SEC);
+    event4->write(1);
+    event4->write(10);
+    event4->init();
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
+    EXPECT_EQ(2UL, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs);
+                event->write("some value");
+                event->write(2);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      tagId, bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+    event->write("some value");
+    event->write(1);
+    event->init();
+    allData.push_back(event);
+    gaugeProducer.onDataPulled(allData);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->second.value_int());
+
+    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(0UL, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ((uint64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->second.value_int());
+
+    allData.clear();
+    event = make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 1);
+    event->write("some value");
+    event->write(3);
+    event->init();
+    allData.push_back(event);
+    gaugeProducer.onDataPulled(allData);
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->second.value_int());
+}
+
 TEST(GaugeMetricProducerTest, TestWithCondition) {
     GaugeMetric metric;
     metric.set_id(metricId);
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 203f028..2658e4e 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -41,6 +41,11 @@
 
 const int TagId = 1;
 
+const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "1");
+const std::vector<HashableDimensionKey> conditionKey = {getMockedDimensionKey(TagId, 4, "1")};
+const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
+const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
+const uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
 TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
     const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
@@ -54,11 +59,13 @@
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
     uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
 
     int64_t metricId = 1;
     MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
-                               false, bucketStartTimeNs, bucketSizeNs, false, {});
+                               false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
+                               false, {});
 
     tracker.noteStart(key1, true, bucketStartTimeNs, ConditionKey());
     // Event starts again. This would not change anything as it already starts.
@@ -87,12 +94,15 @@
 
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
-    uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
 
     int64_t metricId = 1;
     MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
-                               false, bucketStartTimeNs, bucketSizeNs, false, {});
+                               false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
+                               false, {});
 
     tracker.noteStart(key1, true, bucketStartTimeNs + 1, ConditionKey());
 
@@ -101,15 +111,14 @@
     tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 40, &buckets);
     tracker.noteStopAll(bucketStartTimeNs + bucketSizeNs + 40);
     EXPECT_TRUE(tracker.mInfos.empty());
-
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    EXPECT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+    EXPECT_TRUE(buckets.find(eventKey) == buckets.end());
 
     tracker.flushIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 40, &buckets);
-    EXPECT_EQ(2u, buckets[eventKey].size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
-    EXPECT_EQ(40ULL, buckets[eventKey][1].mDuration);
+    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+    EXPECT_EQ(1u, buckets[eventKey].size());
+    EXPECT_EQ(bucketSizeNs + 40 - 1, buckets[eventKey][0].mDuration);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[eventKey][0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[eventKey][0].mBucketEndNs);
 }
 
 TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
@@ -122,12 +131,15 @@
 
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
-    uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
 
     int64_t metricId = 1;
     MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
-                               false, bucketStartTimeNs, bucketSizeNs, false, {});
+                               false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
+                               false, {});
 
     // The event starts.
     tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 1, ConditionKey());
@@ -137,14 +149,18 @@
                       ConditionKey());
 
     // The event stops at early 4th bucket.
+    // Notestop is called from DurationMetricProducer's onMatchedLogEvent, which calls
+    // flushIfneeded.
     tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 20, &buckets);
     tracker.noteStop(DEFAULT_DIMENSION_KEY, bucketStartTimeNs + (3 * bucketSizeNs) + 20,
                      false /*stop all*/);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    EXPECT_EQ(3u, buckets[eventKey].size());
-    EXPECT_EQ((unsigned long long)(bucketSizeNs - 1), buckets[eventKey][0].mDuration);
-    EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[eventKey][1].mDuration);
-    EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[eventKey][2].mDuration);
+    EXPECT_TRUE(buckets.find(eventKey) == buckets.end());
+
+    tracker.flushIfNeeded(bucketStartTimeNs + 4 * bucketSizeNs, &buckets);
+    EXPECT_EQ(1u, buckets[eventKey].size());
+    EXPECT_EQ((3 * bucketSizeNs) + 20 - 1, buckets[eventKey][0].mDuration);
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[eventKey][0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, buckets[eventKey][0].mBucketEndNs);
 }
 
 TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
@@ -157,12 +173,15 @@
 
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
-    uint64_t bucketStartTimeNs = 10000000000;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
 
     int64_t metricId = 1;
     MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
-                               true, bucketStartTimeNs, bucketSizeNs, false, {});
+                               true, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
+                               false, {});
 
     // 2 starts
     tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 1, ConditionKey());
@@ -171,21 +190,16 @@
     tracker.noteStop(DEFAULT_DIMENSION_KEY, bucketStartTimeNs + 20, false /*stop all*/);
 
     tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1, &buckets);
-
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    EXPECT_EQ(2u, buckets[eventKey].size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
-    EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
+    // Because of nesting, still not stopped.
+    EXPECT_TRUE(buckets.find(eventKey) == buckets.end());
 
     // real stop now.
     tracker.noteStop(DEFAULT_DIMENSION_KEY,
                      bucketStartTimeNs + (2 * bucketSizeNs) + 5, false);
     tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 1, &buckets);
 
-    EXPECT_EQ(3u, buckets[eventKey].size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
-    EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
-    EXPECT_EQ(5ULL, buckets[eventKey][2].mDuration);
+    EXPECT_EQ(1u, buckets[eventKey].size());
+    EXPECT_EQ(2 * bucketSizeNs + 5 - 1, buckets[eventKey][0].mDuration);
 }
 
 TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
@@ -204,14 +218,17 @@
 
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     int64_t durationTimeNs = 2 * 1000;
 
     int64_t metricId = 1;
     MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                               false, bucketStartTimeNs, bucketSizeNs, true, {});
+                               false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
+                               true, {});
     EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
 
     tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
@@ -226,45 +243,6 @@
     EXPECT_EQ(5ULL, buckets[eventKey][0].mDuration);
 }
 
-TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
-    const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
-    const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
-    FieldMatcher dimensionInCondition;
-    int64_t metricId = 1;
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(metricId);
-    alert.set_trigger_if_sum_gt(32 * NS_PER_SEC);
-    alert.set_num_buckets(2);
-    const int32_t refPeriodSec = 1;
-    alert.set_refractory_period_secs(refPeriodSec);
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-    uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
-    uint64_t bucketSizeNs = 30 * NS_PER_SEC;
-
-    sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
-    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, dimensionInCondition,
-                               true, bucketStartTimeNs, bucketSizeNs, false, {anomalyTracker});
-
-    tracker.noteStart(key1, true, eventStartTimeNs, ConditionKey());
-    tracker.noteStop(key1, eventStartTimeNs + 10, false);
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
-    EXPECT_EQ(10LL, tracker.mDuration);
-
-    tracker.noteStart(key2, true, eventStartTimeNs + 20, ConditionKey());
-    tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, &buckets);
-    tracker.noteStop(key2, eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, false);
-    EXPECT_EQ((long long)(4 * NS_PER_SEC + 1LL), tracker.mDuration);
-
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey),
-              (eventStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC  + 3 + refPeriodSec);
-}
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 80e16a1..4b579b1 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -38,6 +38,12 @@
 const ConfigKey kConfigKey(0, 12345);
 const int TagId = 1;
 const int64_t metricId = 123;
+const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "event");
+
+const std::vector<HashableDimensionKey> kConditionKey1 = {getMockedDimensionKey(TagId, 1, "maps")};
+const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
+const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
+const uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
 
 TEST(OringDurationTrackerTest, TestDurationOverlap) {
     const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
@@ -51,13 +57,16 @@
 
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t durationTimeNs = 2 * 1000;
 
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 false, bucketStartTimeNs, bucketSizeNs, false, {});
+                                 false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, false, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
     EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
@@ -84,12 +93,15 @@
 
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
 
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 true, bucketStartTimeNs, bucketSizeNs, false, {});
+                                 true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, false, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
     tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, ConditionKey());  // overlapping wl
@@ -115,12 +127,15 @@
 
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
 
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 true, bucketStartTimeNs, bucketSizeNs, false, {});
+                                 true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, false, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
     tracker.noteStart(kEventKey2, true, eventStartTimeNs + 10, ConditionKey());  // overlapping wl
@@ -145,13 +160,16 @@
 
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t durationTimeNs = 2 * 1000;
 
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 true, bucketStartTimeNs, bucketSizeNs, false, {});
+                                 true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, false, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
     EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
@@ -190,13 +208,16 @@
 
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t durationTimeNs = 2 * 1000;
 
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 false, bucketStartTimeNs, bucketSizeNs, true, {});
+                                 false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, true, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
 
@@ -231,12 +252,15 @@
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
     uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t durationTimeNs = 2 * 1000;
 
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 false, bucketStartTimeNs, bucketSizeNs, true, {});
+                                 false, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, true, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
     // condition to false; record duration 5n
@@ -271,11 +295,14 @@
     unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
 
     uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
     uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
+    uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
 
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 true, bucketStartTimeNs, bucketSizeNs, true, {});
+                                 true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, true, {});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
     tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2, key1);
@@ -311,12 +338,14 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
     uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
-    uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
     sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 true, bucketStartTimeNs, bucketSizeNs, true, {anomalyTracker});
+                                 true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, true, {anomalyTracker});
 
     // Nothing in the past bucket.
     tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, ConditionKey());
@@ -379,12 +408,14 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
     uint64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+    uint64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
+    uint64_t bucketNum = 0;
     uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
-    uint64_t bucketSizeNs = 30 * NS_PER_SEC;
 
     sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 true /*nesting*/, bucketStartTimeNs, bucketSizeNs, false, {anomalyTracker});
+                                 true /*nesting*/, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
+                                 bucketSizeNs, false, {anomalyTracker});
 
     tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
     tracker.noteStop(kEventKey1, eventStartTimeNs + 10, false);
@@ -434,8 +465,8 @@
 
     sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey);
     OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition,
-                                 true /*nesting*/, bucketStartTimeNs, bucketSizeNs, false,
-                                 {anomalyTracker});
+                                 true /*nesting*/, bucketStartTimeNs, 0, bucketStartTimeNs,
+                                 bucketSizeNs, false, {anomalyTracker});
 
     tracker.noteStart(kEventKey1, true, 15 * NS_PER_SEC, conkey); // start key1
     EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 55c078d..325a372 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -44,6 +44,7 @@
 const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
 const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
+const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
 
 /*
  * Tests pulled atoms with no conditions
@@ -202,6 +203,101 @@
     EXPECT_EQ(false, curInterval.startUpdated);
 }
 
+TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, -1, bucketStartTimeNs,
+                                      pullerManager);
+
+    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+    event1->write(1);
+    event1->write(10);
+    event1->init();
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+
+    valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((uint64_t)eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+
+    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
+    event2->write(1);
+    event2->write(10);
+    event2->init();
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((uint64_t)eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+
+    // Next value should create a new bucket.
+    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
+    event3->write(1);
+    event3->write(10);
+    event3->init();
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((uint64_t)bucketStartTimeNs + bucketSizeNs, valueProducer.mCurrentBucketStartTimeNs);
+}
+
+TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    shared_ptr<MockStatsPullerManager> pullerManager =
+            make_shared<StrictMock<MockStatsPullerManager>>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                event->write(tagId);
+                event->write(120);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, tagId, bucketStartTimeNs,
+                                      pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+    event->write(tagId);
+    event->write(100);
+    event->init();
+    allData.push_back(event);
+
+    valueProducer.onDataPulled(allData);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+
+    valueProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((uint64_t)eventUpgradeTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mValue);
+
+    allData.clear();
+    event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event->write(tagId);
+    event->write(150);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData);
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((uint64_t)bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(30L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mValue);
+}
+
 TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
     ValueMetric metric;
     metric.set_id(metricId);
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index 0a97456..b48de54 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -15,6 +15,7 @@
 
 #include "src/condition/ConditionWizard.h"
 #include "src/external/StatsPullerManager.h"
+#include "src/packages/UidMap.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -40,6 +41,11 @@
     MOCK_METHOD2(Pull, bool(const int pullCode, vector<std::shared_ptr<LogEvent>>* data));
 };
 
+class MockUidMap : public UidMap {
+ public:
+  MOCK_CONST_METHOD1(getHostUidOrSelf, int(int uid));
+};
+
 HashableDimensionKey getMockedDimensionKey(int tagId, int key, std::string value);
 MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, std::string value);
 
diff --git a/cmds/statsd/tools/dogfood/AndroidManifest.xml b/cmds/statsd/tools/dogfood/AndroidManifest.xml
index cd76c9d..52673fb 100644
--- a/cmds/statsd/tools/dogfood/AndroidManifest.xml
+++ b/cmds/statsd/tools/dogfood/AndroidManifest.xml
@@ -37,5 +37,7 @@
                 <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/layout/activity_main.xml b/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
index 5d35c29..784ed40 100644
--- a/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
+++ b/cmds/statsd/tools/dogfood/res/layout/activity_main.xml
@@ -31,6 +31,18 @@
             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"
diff --git a/cmds/statsd/tools/dogfood/res/values/strings.xml b/cmds/statsd/tools/dogfood/res/values/strings.xml
index 0eab0f4..60948a1 100644
--- a/cmds/statsd/tools/dogfood/res/values/strings.xml
+++ b/cmds/statsd/tools/dogfood/res/values/strings.xml
@@ -24,6 +24,8 @@
     <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>
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
index 33c8abf..03e5fef 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/DisplayProtoUtils.java
@@ -32,11 +32,13 @@
 
         for (StatsLog.ConfigMetricsReport report : reports.getReportsList()) {
             sb.append("StatsLogReport size: ").append(report.getMetricsCount()).append("\n");
+            sb.append("Last report time:").append(getDateStr(report.getLastReportNanos())).
+                    append("\n");
+            sb.append("Current report time:").append(getDateStr(report.getCurrentReportNanos())).
+                    append("\n");
             for (StatsLog.StatsLogReport log : report.getMetricsList()) {
                 sb.append("\n\n");
                 sb.append("metric id: ").append(log.getMetricId()).append("\n");
-                sb.append("start time:").append(getDateStr(log.getStartReportNanos())).append("\n");
-                sb.append("end time:").append(getDateStr(log.getEndReportNanos())).append("\n");
 
                 switch (log.getDataCase()) {
                     case DURATION_METRICS:
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
index 57575ae..0e6c933 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
@@ -16,7 +16,10 @@
 package com.android.statsd.dogfood;
 
 import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.IntentService;
 import android.app.StatsManager;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.os.Bundle;
@@ -48,69 +51,69 @@
 
         findViewById(R.id.app_a_wake_lock_acquire1).setOnClickListener(
                 new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                onWakeLockAcquire(0, "wl_1");
-            }
-        });
+                    @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");
-            }
-        });
+                    @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");
-            }
-        });
+                    @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");
-            }
-        });
+                    @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");
-            }
-        });
+                    @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");
-            }
-        });
+                    @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");
-            }
-        });
+                    @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");
-            }
-        });
+                    @Override
+                    public void onClick(View view) {
+                        onWakeLockRelease(1, "wl_2");
+                    }
+                });
 
 
         findViewById(R.id.plug).setOnClickListener(new View.OnClickListener() {
@@ -191,8 +194,7 @@
                     byte[] config = new byte[inputStream.available()];
                     inputStream.read(config);
                     if (mStatsManager != null) {
-                        if (mStatsManager.addConfiguration(CONFIG_ID,
-                                config, getPackageName(), MainActivity.this.getClass().getName())) {
+                        if (mStatsManager.addConfiguration(CONFIG_ID, config)) {
                             Toast.makeText(
                                     MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show();
                         } else {
@@ -205,6 +207,55 @@
                 }
             }
         });
+
+        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) {
+                        if (mStatsManager.setDataFetchOperation(CONFIG_ID, pi)) {
+                            Toast.makeText(MainActivity.this,
+                                    "Receiver specified to pending intent", Toast.LENGTH_LONG)
+                                    .show();
+                        } else {
+                            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) {
+                        if (mStatsManager.setDataFetchOperation(CONFIG_ID, null)) {
+                            Toast.makeText(MainActivity.this, "Receiver remove", Toast.LENGTH_LONG)
+                                    .show();
+                        } else {
+                            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");
     }
 
@@ -257,8 +308,8 @@
             Log.d(TAG, "invalid pkg id");
             return;
         }
-        int[] uids = new int[] {mUids[id]};
-        String[] tags  = new String[] {"acquire"};
+        int[] uids = new int[]{mUids[id]};
+        String[] tags = new String[]{"acquire"};
         StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
                 StatsLog.WAKELOCK_STATE_CHANGED__LEVEL__PARTIAL_WAKE_LOCK, name,
                 StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
@@ -273,8 +324,8 @@
             Log.d(TAG, "invalid pkg id");
             return;
         }
-        int[] uids = new int[] {mUids[id]};
-        String[] tags  = new String[] {"release"};
+        int[] uids = new int[]{mUids[id]};
+        String[] tags = new String[]{"release"};
         StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
                 StatsLog.WAKELOCK_STATE_CHANGED__LEVEL__PARTIAL_WAKE_LOCK, name,
                 StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
@@ -283,4 +334,20 @@
                 .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/src/com/android/statsd/loadtest/DisplayProtoUtils.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
index 75489ad..87b82c2 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/DisplayProtoUtils.java
@@ -36,6 +36,10 @@
         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.getLastReportNanos())).
+                    append("\n");
+            sb.append("Current report time:").append(getDateStr(report.getCurrentReportNanos())).
+                    append("\n");
             for (StatsLog.StatsLogReport log : report.getMetricsList()) {
                 numMetrics++;
                 if (numMetrics > MAX_NUM_METRICS_TO_DISPLAY) {
@@ -45,8 +49,6 @@
                 }
                 sb.append("\n");
                 sb.append("metric id: ").append(log.getMetricId()).append("\n");
-                sb.append("start time:").append(getDateStr(log.getStartReportNanos())).append("\n");
-                sb.append("end time:").append(getDateStr(log.getEndReportNanos())).append("\n");
 
                 switch (log.getDataCase()) {
                     case DURATION_METRICS:
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
index 652f6b2..bed4d98 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
@@ -47,10 +47,12 @@
 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;
@@ -60,18 +62,18 @@
  * 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.
+ * <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).
+ * <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 {
@@ -93,7 +95,7 @@
             Intent activityIntent = new Intent(context, LoadtestActivity.class);
             activityIntent.putExtra(TYPE, PUSH_ALARM);
             context.startActivity(activityIntent);
-         }
+        }
     }
 
     public final static class StopperAlarmReceiver extends BroadcastReceiver {
@@ -102,7 +104,7 @@
             Intent activityIntent = new Intent(context, LoadtestActivity.class);
             activityIntent.putExtra(TYPE, STOP);
             context.startActivity(activityIntent);
-         }
+        }
     }
 
     private static Map<String, TimeUnit> initializeTimeUnitMap() {
@@ -119,6 +121,7 @@
         labels.put("1s", TimeUnit.CTS);
         return labels;
     }
+
     private static List<String> initializeTimeUnitLabels() {
         List<String> labels = new ArrayList();
         labels.add("1s");
@@ -136,10 +139,14 @@
 
     private AlarmManager mAlarmMgr;
 
-    /** Used to periodically log atoms to logd. */
+    /**
+     * Used to periodically log atoms to logd.
+     */
     private PendingIntent mPushPendingIntent;
 
-    /** Used to end the loadtest. */
+    /**
+     * Used to end the loadtest.
+     */
     private PendingIntent mStopPendingIntent;
 
     private Button mStartStop;
@@ -156,13 +163,19 @@
     private CheckBox mValueMetricCheckBox;
     private CheckBox mGaugeMetricCheckBox;
 
-    /** When the load test started. */
+    /**
+     * When the load test started.
+     */
     private long mStartedTimeMillis;
 
-    /** For measuring perf data. */
+    /**
+     * For measuring perf data.
+     */
     private PerfData mPerfData;
 
-    /** For communicating with statsd. */
+    /**
+     * For communicating with statsd.
+     */
     private StatsManager mStatsManager;
 
     private PowerManager mPowerManager;
@@ -199,34 +212,54 @@
      */
     private boolean mIncludeGaugeMetric;
 
-    /** The burst size. */
+    /**
+     * The burst size.
+     */
     private int mBurst;
 
-    /** The metrics replication. */
+    /**
+     * The metrics replication.
+     */
     private int mReplication;
 
-    /** The period, in seconds, at which batches of atoms are pushed. */
+    /**
+     * The period, in seconds, at which batches of atoms are pushed.
+     */
     private long mPeriodSecs;
 
-    /** The bucket size, in minutes, for aggregate metrics. */
+    /**
+     * The bucket size, in minutes, for aggregate metrics.
+     */
     private TimeUnit mBucket;
 
-    /** The duration, in minutes, of the loadtest. */
+    /**
+     * The duration, in minutes, of the loadtest.
+     */
     private long mDurationMins;
 
-    /** Whether the loadtest has started. */
+    /**
+     * Whether the loadtest has started.
+     */
     private boolean mStarted = false;
 
-    /** Orchestrates the logging of pushed events into logd. */
+    /**
+     * Orchestrates the logging of pushed events into logd.
+     */
     private SequencePusher mPusher;
 
-    /** Generates statsd configs. */
+    /**
+     * Generates statsd configs.
+     */
     private ConfigFactory mFactory;
 
-    /** For intra-minute periods. */
+    /**
+     * For intra-minute periods.
+     */
     private final Handler mHandler = new Handler();
 
-    /** Number of metrics in the current config. */
+    /**
+     * Number of metrics in the current config.
+     */
     private int mNumMetrics;
 
     @Override
@@ -250,7 +283,7 @@
             @Override
             public boolean onTouch(View v, MotionEvent event) {
                 InputMethodManager imm =
-                    (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+                        (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                 if (getCurrentFocus() != null) {
                     imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
                 }
@@ -380,10 +413,10 @@
         }
         // Piggy-back on that alarm to show the elapsed time.
         long elapsedTimeMins = (long) Math.floor(
-            (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
+                (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
         mReportText.setText("Loadtest in progress.\n"
-            + "num metrics =" + mNumMetrics
-            + "\nElapsed time = " + elapsedTimeMins + " min(s)");
+                + "num metrics =" + mNumMetrics
+                + "\nElapsed time = " + elapsedTimeMins + " min(s)");
     }
 
     private void onAlarm() {
@@ -402,12 +435,14 @@
         mWakeLock = null;
     }
 
-    /** Schedules the next cycle of pushing atoms into logd. */
+    /**
+     * 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;
+        long nextTime = SystemClock.elapsedRealtime() + mPeriodSecs * 1000;
         mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mPushPendingIntent);
     }
 
@@ -433,7 +468,7 @@
         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;
+        long nextTime = SystemClock.elapsedRealtime() + mDurationMins * 60 * 1000;
         mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mStopPendingIntent);
 
         // Log atoms.
@@ -441,8 +476,8 @@
 
         // Start tracking performance.
         mPerfData = new PerfData(this, mPlacebo, mReplication, mBucket, mPeriodSecs, mBurst,
-            mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric, mIncludeValueMetric,
-            mIncludeGaugeMetric);
+                mIncludeCountMetric, mIncludeDurationMetric, mIncludeEventMetric, mIncludeValueMetric,
+                mIncludeGaugeMetric);
         mPerfData.startRecording(this);
 
         mReportText.setText("Loadtest in progress.\nnum metrics =" + mNumMetrics);
@@ -476,7 +511,7 @@
         getData();
 
         long elapsedTimeMins = (long) Math.floor(
-            (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
+                (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
         mReportText.setText("Loadtest ended. Elapsed time = " + elapsedTimeMins + " min(s)");
         clearConfigs();
         updateStarted(false);
@@ -485,7 +520,7 @@
     private synchronized void updateStarted(boolean started) {
         mStarted = started;
         mStartStop.setBackgroundColor(started ?
-            Color.parseColor("#FFFF0000") : Color.parseColor("#FF00FF00"));
+                Color.parseColor("#FFFF0000") : Color.parseColor("#FF00FF00"));
         mStartStop.setText(started ? getString(R.string.stop) : getString(R.string.start));
         updateControlsEnabled();
     }
@@ -538,22 +573,21 @@
     }
 
     private boolean setConfig(ConfigFactory.ConfigMetadata configData) {
-      if (mStatsManager != null) {
-            if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_ID,
-                configData.bytes, getPackageName(), LoadtestActivity.this.getClass().getName())) {
+        if (mStatsManager != null) {
+            if (mStatsManager.addConfiguration(ConfigFactory.CONFIG_ID, configData.bytes)) {
                 mNumMetrics = configData.numMetrics;
                 Log.d(TAG, "Config pushed to statsd");
                 return true;
             } else {
                 Log.d(TAG, "Failed to push config to statsd");
             }
-      }
-      return false;
+        }
+        return false;
     }
 
     private synchronized void setReplication(int replication) {
         if (mStarted) {
-          return;
+            return;
         }
         mReplicationText.setText("" + replication);
     }
@@ -614,13 +648,13 @@
         mBucketSpinner = (Spinner) findViewById(R.id.bucket_spinner);
 
         ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(
-            this, R.layout.spinner_item, TIME_UNIT_LABELS);
+                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())) {
+            if (defaultValue.equals(TIME_UNIT_MAP.get(label).toString())) {
                 mBucketSpinner.setSelection(dataAdapter.getPosition(label));
             }
         }
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 58936fc..7b70f59 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -7,15 +7,18 @@
 Landroid/app/Activity;->getActivityOptions()Landroid/app/ActivityOptions;
 Landroid/app/Activity;->getActivityToken()Landroid/os/IBinder;
 Landroid/app/Activity;->mActivityInfo:Landroid/content/pm/ActivityInfo;
+Landroid/app/ActivityManager;->addOnUidImportanceListener(Landroid/app/ActivityManager$OnUidImportanceListener;I)V
 Landroid/app/ActivityManager;->clearApplicationUserData(Ljava/lang/String;Landroid/content/pm/IPackageDataObserver;)Z
 Landroid/app/ActivityManager;->forceStopPackage(Ljava/lang/String;)V
 Landroid/app/ActivityManager;->getCurrentUser()I
+Landroid/app/ActivityManager;->getPackageImportance(Ljava/lang/String;)I
 Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z
 Landroid/app/ActivityManager;->isUserRunning(I)Z
 Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
 Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
 Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
 Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J
+Landroid/app/ActivityManager;->removeOnUidImportanceListener(Landroid/app/ActivityManager$OnUidImportanceListener;)V
 Landroid/app/ActivityManager$RunningAppProcessInfo;->flags:I
 Landroid/app/ActivityManager$RunningAppProcessInfo;->processState:I
 Landroid/app/Activity;->mApplication:Landroid/app/Application;
@@ -34,16 +37,17 @@
 Landroid/app/ActivityThread;->currentApplication()Landroid/app/Application;
 Landroid/app/ActivityThread;->currentPackageName()Ljava/lang/String;
 Landroid/app/ActivityThread;->currentProcessName()Ljava/lang/String;
+Landroid/app/ActivityThread;->getActivity(Landroid/os/IBinder;)Landroid/app/Activity;
 Landroid/app/ActivityThread;->getApplication()Landroid/app/Application;
 Landroid/app/ActivityThread;->getApplicationThread()Landroid/app/ActivityThread$ApplicationThread;
 Landroid/app/ActivityThread;->getHandler()Landroid/os/Handler;
+Landroid/app/ActivityThread;->getInstrumentation()Landroid/app/Instrumentation;
 Landroid/app/ActivityThread;->getPackageManager()Landroid/content/pm/IPackageManager;
 Landroid/app/ActivityThread;->getProcessName()Ljava/lang/String;
 Landroid/app/ActivityThread$H;->BIND_SERVICE:I
 Landroid/app/ActivityThread$H;->CREATE_SERVICE:I
 Landroid/app/ActivityThread$H;->EXIT_APPLICATION:I
 Landroid/app/ActivityThread$H;->RECEIVER:I
-Landroid/app/ActivityThread$H;->RELAUNCH_ACTIVITY:I
 Landroid/app/ActivityThread$H;->REMOVE_PROVIDER:I
 Landroid/app/ActivityThread$H;->SERVICE_ARGS:I
 Landroid/app/ActivityThread$H;->STOP_SERVICE:I
@@ -58,6 +62,9 @@
 Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->performStopActivity(Landroid/os/IBinder;ZLjava/lang/String;)V
 Landroid/app/ActivityThread;->sPackageManager:Landroid/content/pm/IPackageManager;
+Landroid/app/admin/DevicePolicyManager;->getDeviceOwnerComponentOnAnyUser()Landroid/content/ComponentName;
+Landroid/app/admin/DevicePolicyManager;->getDeviceOwner()Ljava/lang/String;
+Landroid/app/admin/DevicePolicyManager;->getProfileOwner()Landroid/content/ComponentName;
 Landroid/app/admin/DevicePolicyManager;->getTrustAgentConfiguration(Landroid/content/ComponentName;Landroid/content/ComponentName;I)Ljava/util/List;
 Landroid/app/admin/DevicePolicyManager;->notifyPendingSystemUpdate(J)V
 Landroid/app/admin/DevicePolicyManager;->notifyPendingSystemUpdate(JZ)V
@@ -65,6 +72,14 @@
 Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/String;)Z
 Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
 Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V
+Landroid/app/AlarmManager;->FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED:I
+Landroid/app/AlarmManager;->FLAG_IDLE_UNTIL:I
+Landroid/app/AlarmManager;->FLAG_STANDALONE:I
+Landroid/app/AlarmManager;->FLAG_WAKE_FROM_IDLE:I
+Landroid/app/AlarmManager;->set(IJJJLandroid/app/AlarmManager$OnAlarmListener;Landroid/os/Handler;Landroid/os/WorkSource;)V
+Landroid/app/AlarmManager;->set(IJJJLandroid/app/PendingIntent;Landroid/os/WorkSource;)V
+Landroid/app/AlarmManager;->WINDOW_EXACT:J
+Landroid/app/AlarmManager;->WINDOW_HEURISTIC:J
 Landroid/app/AlertDialog$Builder;->P:Lcom/android/internal/app/AlertController$AlertParams;
 Landroid/app/AlertDialog;->mAlert:Lcom/android/internal/app/AlertController;
 Landroid/app/AppGlobals;->getInitialApplication()Landroid/app/Application;
@@ -86,9 +101,32 @@
 Landroid/app/AppOpsManager;->OP_WRITE_SMS:I
 Landroid/app/AppOpsManager;->setMode(IILjava/lang/String;I)V
 Landroid/app/AppOpsManager;->strOpToOp(Ljava/lang/String;)I
+Landroid/app/backup/BackupDataInput;-><init>(Ljava/io/FileDescriptor;)V
 Landroid/app/backup/BackupDataInputStream;->dataSize:I
 Landroid/app/backup/BackupDataInputStream;->key:Ljava/lang/String;
+Landroid/app/backup/BackupDataOutput;-><init>(Ljava/io/FileDescriptor;)V
+Landroid/app/backup/BackupManager;->backupNow()V
+Landroid/app/backup/BackupManager;->beginRestoreSession()Landroid/app/backup/RestoreSession;
+Landroid/app/backup/BackupManager;->cancelBackups()V
+Landroid/app/backup/BackupManager;->getAvailableRestoreToken(Ljava/lang/String;)J
+Landroid/app/backup/BackupManager;->getCurrentTransport()Ljava/lang/String;
+Landroid/app/backup/BackupManager;->isBackupEnabled()Z
+Landroid/app/backup/BackupManager;->listAllTransports()[Ljava/lang/String;
+Landroid/app/backup/BackupManagerMonitor;-><init>()V
+Landroid/app/backup/BackupManager;->requestBackup([Ljava/lang/String;Landroid/app/backup/BackupObserver;Landroid/app/backup/BackupManagerMonitor;I)I
+Landroid/app/backup/BackupManager;->selectBackupTransport(Landroid/content/ComponentName;Landroid/app/backup/SelectBackupTransportCallback;)V
+Landroid/app/backup/BackupManager;->selectBackupTransport(Ljava/lang/String;)Ljava/lang/String;
+Landroid/app/backup/BackupManager;->setAutoRestore(Z)V
+Landroid/app/backup/BackupManager;->setBackupEnabled(Z)V
+Landroid/app/backup/BackupObserver;-><init>()V
+Landroid/app/backup/BackupTransport;-><init>()V
 Landroid/app/backup/FullBackup;->backupToTar(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/app/backup/FullBackupDataOutput;)I
+Landroid/app/backup/RestoreDescription;-><init>(Ljava/lang/String;I)V
+Landroid/app/backup/RestoreSession;->endRestoreSession()V
+Landroid/app/backup/RestoreSession;->getAvailableRestoreSets(Landroid/app/backup/RestoreObserver;)I
+Landroid/app/backup/RestoreSession;->restoreAll(JLandroid/app/backup/RestoreObserver;)I
+Landroid/app/backup/RestoreSet;-><init>(Ljava/lang/String;Ljava/lang/String;J)V
+Landroid/app/backup/SelectBackupTransportCallback;-><init>()V
 Landroid/app/ContextImpl;->createActivityContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;ILandroid/content/res/Configuration;)Landroid/app/ContextImpl;
 Landroid/app/ContextImpl;->getActivityToken()Landroid/os/IBinder;
 Landroid/app/ContextImpl;->mMainThread:Landroid/app/ActivityThread;
@@ -107,6 +145,8 @@
 Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljava/lang/String;
 Landroid/app/IActivityManager;->resumeAppSwitches()V
 Landroid/app/IApplicationThread;->scheduleTrimMemory(I)V
+Landroid/app/InstantAppResolverService;-><init>()V
+Landroid/app/InstantAppResolverService$InstantAppResolutionCallback;->onInstantAppResolveInfo(Ljava/util/List;)V
 Landroid/app/IntentService;->mServiceHandler:Landroid/app/IntentService$ServiceHandler;
 Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor;
 Landroid/app/LoadedApk;->mApplication:Landroid/app/Application;
@@ -133,6 +173,10 @@
 Landroid/app/StatusBarManager;->expandSettingsPanel(Ljava/lang/String;)V
 Landroid/app/StatusBarManager;->expandSettingsPanel()V
 Landroid/app/TimePickerDialog;->mTimePicker:Landroid/widget/TimePicker;
+Landroid/app/usage/UsageStatsManager;->getAppStandbyBuckets()Ljava/util/Map;
+Landroid/app/usage/UsageStatsManager;->setAppStandbyBuckets(Ljava/util/Map;)V
+Landroid/app/usage/UsageStatsManager;->whitelistAppTemporarily(Ljava/lang/String;JLandroid/os/UserHandle;)V
+Landroid/app/WallpaperColors;->getColorHints()I
 Landroid/app/WallpaperManager;->getBitmap()Landroid/graphics/Bitmap;
 Landroid/app/WallpaperManager;->getBitmap(Z)Landroid/graphics/Bitmap;
 Landroid/app/WallpaperManager;->getIWallpaperManager()Landroid/app/IWallpaperManager;
@@ -143,9 +187,13 @@
 Landroid/appwidget/AppWidgetManager;->bindAppWidgetId(ILandroid/content/ComponentName;Landroid/os/Bundle;)V
 Landroid/appwidget/AppWidgetManager;->bindAppWidgetId(ILandroid/content/ComponentName;)V
 Landroid/bluetooth/BluetoothA2dp;->connect(Landroid/bluetooth/BluetoothDevice;)Z
+Landroid/bluetooth/BluetoothAdapter;->disableBLE()Z
 Landroid/bluetooth/BluetoothAdapter;->disable(Z)Z
+Landroid/bluetooth/BluetoothAdapter;->enableBLE()Z
 Landroid/bluetooth/BluetoothAdapter;->enableNoAutoConnect()Z
 Landroid/bluetooth/BluetoothAdapter;->getDiscoverableTimeout()I
+Landroid/bluetooth/BluetoothAdapter;->isBleScanAlwaysAvailable()Z
+Landroid/bluetooth/BluetoothAdapter;->isLeEnabled()Z
 Landroid/bluetooth/BluetoothAdapter;->setScanMode(II)Z
 Landroid/bluetooth/BluetoothAdapter;->setScanMode(I)Z
 Landroid/bluetooth/BluetoothDevice;->cancelBondProcess()Z
@@ -164,6 +212,8 @@
 Landroid/bluetooth/BluetoothHeadset;->setPriority(Landroid/bluetooth/BluetoothDevice;I)Z
 Landroid/bluetooth/BluetoothUuid;->RESERVED_UUIDS:[Landroid/os/ParcelUuid;
 Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
+Landroid/bluetooth/le/BluetoothLeScanner;->startScanFromSource(Ljava/util/List;Landroid/bluetooth/le/ScanSettings;Landroid/os/WorkSource;Landroid/bluetooth/le/ScanCallback;)V
+Landroid/bluetooth/le/ScanSettings$Builder;->setScanResultType(I)Landroid/bluetooth/le/ScanSettings$Builder;
 Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor;
 Landroid/content/ContentProviderOperation;->mSelection:Ljava/lang/String;
 Landroid/content/ContentProviderOperation;->mType:I
@@ -171,13 +221,17 @@
 Landroid/content/ContentResolver;->getSyncStatus(Landroid/accounts/Account;Ljava/lang/String;)Landroid/content/SyncStatusInfo;
 Landroid/content/ContentResolver;->mContext:Landroid/content/Context;
 Landroid/content/ContentValues;->mValues:Ljava/util/HashMap;
+Landroid/content/Context;->bindServiceAsUser(Landroid/content/Intent;Landroid/content/ServiceConnection;ILandroid/os/UserHandle;)Z
+Landroid/content/Context;->createCredentialProtectedStorageContext()Landroid/content/Context;
 Landroid/content/Context;->createPackageContextAsUser(Ljava/lang/String;ILandroid/os/UserHandle;)Landroid/content/Context;
 Landroid/content/Context;->getSharedPrefsFile(Ljava/lang/String;)Ljava/io/File;
 Landroid/content/Context;->getThemeResId()I
+Landroid/content/Context;->isCredentialProtectedStorage()Z
 Landroid/content/Context;->sendBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;I)V
 Landroid/content/Context;->sendBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;Landroid/os/Bundle;)V
 Landroid/content/Context;->sendOrderedBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;ILandroid/content/BroadcastReceiver;Landroid/os/Handler;ILjava/lang/String;Landroid/os/Bundle;)V
 Landroid/content/Context;->sendOrderedBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;ILandroid/os/Bundle;Landroid/content/BroadcastReceiver;Landroid/os/Handler;ILjava/lang/String;Landroid/os/Bundle;)V
+Landroid/content/ContextWrapper;->createCredentialProtectedStorageContext()Landroid/content/Context;
 Landroid/content/ContextWrapper;->mBase:Landroid/content/Context;
 Landroid/content/CursorLoader;->mCancellationSignal:Landroid/os/CancellationSignal;
 Landroid/content/CursorLoader;->mObserver:Landroid/content/Loader$ForceLoadContentObserver;
@@ -185,6 +239,7 @@
 Landroid/content/IContentService;->getMasterSyncAutomatically()Z
 Landroid/content/IContentService;->setMasterSyncAutomatically(Z)V
 Landroid/content/Intent;->ACTION_ALARM_CHANGED:Ljava/lang/String;
+Landroid/content/IntentFilter;->setOrder(I)V
 Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/IBinder;)Landroid/content/Intent;
 Landroid/content/pm/ApplicationInfo;->installLocation:I
 Landroid/content/pm/ApplicationInfo;->isForwardLocked()Z
@@ -193,12 +248,19 @@
 Landroid/content/pm/ApplicationInfo;->primaryCpuAbi:Ljava/lang/String;
 Landroid/content/pm/ApplicationInfo;->privateFlags:I
 Landroid/content/pm/ApplicationInfo;->targetSandboxVersion:I
+Landroid/content/pm/InstantAppIntentFilter;-><init>(Ljava/lang/String;Ljava/util/List;)V
+Landroid/content/pm/InstantAppResolveInfo;->getPackageName()Ljava/lang/String;
+Landroid/content/pm/InstantAppResolveInfo;-><init>(Landroid/content/pm/InstantAppResolveInfo$InstantAppDigest;Ljava/lang/String;Ljava/util/List;I)V
+Landroid/content/pm/InstantAppResolveInfo$InstantAppDigest;->getDigestPrefix()[I
+Landroid/content/pm/InstantAppResolveInfo$InstantAppDigest;-><init>(Ljava/lang/String;)V
 Landroid/content/pm/IPackageManager;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
 Landroid/content/pm/IPackageManager;->setLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;ILandroid/content/IntentFilter;ILandroid/content/ComponentName;)V
+Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V
 Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager;
 Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V
 Landroid/content/pm/PackageInstaller$SessionParams;->setGrantedRuntimePermissions([Ljava/lang/String;)V
 Landroid/content/pm/PackageInstaller$SessionParams;->setInstallAsInstantApp(Z)V
+Landroid/content/pm/PackageManager;->addOnPermissionsChangeListener(Landroid/content/pm/PackageManager$OnPermissionsChangedListener;)V
 Landroid/content/pm/PackageManager;->freeStorageAndNotify(JLandroid/content/pm/IPackageDataObserver;)V
 Landroid/content/pm/PackageManager;->freeStorageAndNotify(Ljava/lang/String;JLandroid/content/pm/IPackageDataObserver;)V
 Landroid/content/pm/PackageManager;->freeStorage(JLandroid/content/IntentSender;)V
@@ -210,6 +272,8 @@
 Landroid/content/pm/PackageManager;->getResourcesForApplicationAsUser(Ljava/lang/String;I)Landroid/content/res/Resources;
 Landroid/content/pm/PackageManager;->movePackage(Ljava/lang/String;Landroid/os/storage/VolumeInfo;)I
 Landroid/content/pm/PackageManager;->queryBroadcastReceivers(Landroid/content/Intent;II)Ljava/util/List;
+Landroid/content/pm/PackageManager;->removeOnPermissionsChangeListener(Landroid/content/pm/PackageManager$OnPermissionsChangedListener;)V
+Landroid/content/pm/PackageManager;->verifyIntentFilter(IILjava/util/List;)V
 Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Ljava/io/File;Z)V
 Landroid/content/pm/PackageParser;->collectCertificates(Landroid/content/pm/PackageParser$Package;Z)V
 Landroid/content/pm/PackageParser;->generatePackageInfo(Landroid/content/pm/PackageParser$Package;[IIJJLjava/util/Set;Landroid/content/pm/PackageUserState;I)Landroid/content/pm/PackageInfo;
@@ -301,6 +365,11 @@
 Landroid/graphics/drawable/StateListDrawable;->getStateSet(I)[I
 Landroid/graphics/drawable/StateListDrawable;->mStateListState:Landroid/graphics/drawable/StateListDrawable$StateListState;
 Landroid/graphics/drawable/StateListDrawable;->updateStateFromTypedArray(Landroid/content/res/TypedArray;)V
+Landroid/graphics/FontFamily;->abortCreation()V
+Landroid/graphics/FontFamily;->addFontFromAssetManager(Landroid/content/res/AssetManager;Ljava/lang/String;IZIII[Landroid/graphics/fonts/FontVariationAxis;)Z
+Landroid/graphics/FontFamily;->addFontFromBuffer(Ljava/nio/ByteBuffer;I[Landroid/graphics/fonts/FontVariationAxis;II)Z
+Landroid/graphics/FontFamily;->freeze()Z
+Landroid/graphics/FontFamily;-><init>()V
 Landroid/graphics/LinearGradient;->mColors:[I
 Landroid/graphics/NinePatch;->mBitmap:Landroid/graphics/Bitmap;
 Landroid/graphics/SurfaceTexture;->nativeDetachFromGLContext()I
@@ -310,18 +379,64 @@
 Landroid/graphics/Typeface;->sSystemFontMap:Ljava/util/Map;
 Landroid/hardware/Camera;->addCallbackBuffer([BI)V
 Landroid/hardware/Camera;->openLegacy(II)Landroid/hardware/Camera;
+Landroid/hardware/display/DisplayManager;->getStableDisplaySize()Landroid/graphics/Point;
 Landroid/hardware/display/WifiDisplayStatus;->mActiveDisplay:Landroid/hardware/display/WifiDisplay;
 Landroid/hardware/display/WifiDisplayStatus;->mDisplays:[Landroid/hardware/display/WifiDisplay;
 Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/input/IInputManager;
 Landroid/hardware/input/InputManager;->getInstance()Landroid/hardware/input/InputManager;
 Landroid/hardware/input/InputManager;->mIm:Landroid/hardware/input/IInputManager;
+Landroid/hardware/location/ContextHubInfo;->getId()I
+Landroid/hardware/location/ContextHubInfo;->getMaxPacketLengthBytes()I
+Landroid/hardware/location/ContextHubManager$Callback;-><init>()V
+Landroid/hardware/location/ContextHubManager;->findNanoAppOnHub(ILandroid/hardware/location/NanoAppFilter;)[I
+Landroid/hardware/location/ContextHubManager;->getContextHubHandles()[I
+Landroid/hardware/location/ContextHubManager;->getContextHubInfo(I)Landroid/hardware/location/ContextHubInfo;
+Landroid/hardware/location/ContextHubManager;->getNanoAppInstanceInfo(I)Landroid/hardware/location/NanoAppInstanceInfo;
+Landroid/hardware/location/ContextHubManager;->loadNanoApp(ILandroid/hardware/location/NanoApp;)I
+Landroid/hardware/location/ContextHubManager;->registerCallback(Landroid/hardware/location/ContextHubManager$Callback;)I
+Landroid/hardware/location/ContextHubManager;->sendMessage(IILandroid/hardware/location/ContextHubMessage;)I
+Landroid/hardware/location/ContextHubManager;->unloadNanoApp(I)I
+Landroid/hardware/location/ContextHubMessage;->getData()[B
+Landroid/hardware/location/ContextHubMessage;->getMsgType()I
+Landroid/hardware/location/ContextHubMessage;->getVersion()I
+Landroid/hardware/location/ContextHubMessage;-><init>(II[B)V
+Landroid/hardware/location/GeofenceHardware;->addGeofence(IILandroid/hardware/location/GeofenceHardwareRequest;Landroid/hardware/location/GeofenceHardwareCallback;)Z
+Landroid/hardware/location/GeofenceHardwareCallback;-><init>()V
+Landroid/hardware/location/GeofenceHardwareCallback;->onGeofenceAdd(II)V
+Landroid/hardware/location/GeofenceHardwareCallback;->onGeofenceRemove(II)V
+Landroid/hardware/location/GeofenceHardwareCallback;->onGeofenceTransition(IILandroid/location/Location;JI)V
+Landroid/hardware/location/GeofenceHardware;->getMonitoringTypes()[I
+Landroid/hardware/location/GeofenceHardware;->getStatusOfMonitoringType(I)I
+Landroid/hardware/location/GeofenceHardwareMonitorCallback;-><init>()V
+Landroid/hardware/location/GeofenceHardwareMonitorCallback;->onMonitoringSystemChange(IZLandroid/location/Location;)V
+Landroid/hardware/location/GeofenceHardware;->registerForMonitorStateChangeCallback(ILandroid/hardware/location/GeofenceHardwareMonitorCallback;)Z
+Landroid/hardware/location/GeofenceHardware;->removeGeofence(II)Z
+Landroid/hardware/location/GeofenceHardwareRequest;->createCircularGeofence(DDD)Landroid/hardware/location/GeofenceHardwareRequest;
+Landroid/hardware/location/GeofenceHardwareRequest;->setLastTransition(I)V
+Landroid/hardware/location/GeofenceHardwareRequest;->setMonitorTransitions(I)V
+Landroid/hardware/location/GeofenceHardwareRequest;->setNotificationResponsiveness(I)V
+Landroid/hardware/location/GeofenceHardwareRequest;->setUnknownTimer(I)V
+Landroid/hardware/location/NanoAppFilter;-><init>(JIIJ)V
+Landroid/hardware/location/NanoApp;-><init>(J[B)V
+Landroid/hardware/location/NanoAppInstanceInfo;->getAppId()J
+Landroid/hardware/location/NanoAppInstanceInfo;->getAppVersion()I
+Landroid/hardware/location/NanoAppInstanceInfo;->getHandle()I
+Landroid/hardware/location/NanoAppInstanceInfo;->getName()Ljava/lang/String;
 Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V
+Landroid/location/GeocoderParams;->getClientPackage()Ljava/lang/String;
+Landroid/location/GeocoderParams;->getLocale()Ljava/util/Locale;
+Landroid/location/LocationManager;->requestLocationUpdates(Landroid/location/LocationRequest;Landroid/location/LocationListener;Landroid/os/Looper;)V
 Landroid/location/LocationRequest;->createFromDeprecatedProvider(Ljava/lang/String;JFZ)Landroid/location/LocationRequest;
+Landroid/location/LocationRequest;->setHideFromAppOps(Z)V
 Landroid/location/LocationRequest;->setWorkSource(Landroid/os/WorkSource;)V
 Landroid/location/Location;->setIsFromMockProvider(Z)V
 Landroid/media/AudioAttributes$Builder;->setInternalCapturePreset(I)Landroid/media/AudioAttributes$Builder;
+Landroid/media/AudioFocusInfo;->getClientId()Ljava/lang/String;
+Landroid/media/AudioFocusInfo;->getClientUid()I
+Landroid/media/AudioFocusInfo;->getLossReceived()I
 Landroid/media/AudioManager;->abandonAudioFocus(Landroid/media/AudioManager$OnAudioFocusChangeListener;Landroid/media/AudioAttributes;)I
 Landroid/media/AudioManager;->mAudioFocusIdListenerMap:Ljava/util/concurrent/ConcurrentHashMap;
+Landroid/media/AudioManager;->registerAudioPolicy(Landroid/media/audiopolicy/AudioPolicy;)I
 Landroid/media/AudioManager;->requestAudioFocus(Landroid/media/AudioFocusRequest;Landroid/media/audiopolicy/AudioPolicy;)I
 Landroid/media/AudioManager;->requestAudioFocus(Landroid/media/AudioManager$OnAudioFocusChangeListener;Landroid/media/AudioAttributes;II)I
 Landroid/media/AudioManager;->requestAudioFocus(Landroid/media/AudioManager$OnAudioFocusChangeListener;Landroid/media/AudioAttributes;IILandroid/media/audiopolicy/AudioPolicy;)I
@@ -329,6 +444,21 @@
 Landroid/media/AudioManager;->STREAM_BLUETOOTH_SCO:I
 Landroid/media/AudioManager;->STREAM_SYSTEM_ENFORCED:I
 Landroid/media/AudioManager;->STREAM_TTS:I
+Landroid/media/AudioManager;->unregisterAudioPolicyAsync(Landroid/media/audiopolicy/AudioPolicy;)V
+Landroid/media/audiopolicy/AudioMix$Builder;->build()Landroid/media/audiopolicy/AudioMix;
+Landroid/media/audiopolicy/AudioMix$Builder;-><init>(Landroid/media/audiopolicy/AudioMixingRule;)V
+Landroid/media/audiopolicy/AudioMix$Builder;->setFormat(Landroid/media/AudioFormat;)Landroid/media/audiopolicy/AudioMix$Builder;
+Landroid/media/audiopolicy/AudioMix$Builder;->setRouteFlags(I)Landroid/media/audiopolicy/AudioMix$Builder;
+Landroid/media/audiopolicy/AudioMixingRule$Builder;->addRule(Landroid/media/AudioAttributes;I)Landroid/media/audiopolicy/AudioMixingRule$Builder;
+Landroid/media/audiopolicy/AudioMixingRule$Builder;->build()Landroid/media/audiopolicy/AudioMixingRule;
+Landroid/media/audiopolicy/AudioMixingRule$Builder;-><init>()V
+Landroid/media/audiopolicy/AudioPolicy$AudioPolicyFocusListener;-><init>()V
+Landroid/media/audiopolicy/AudioPolicy$Builder;->addMix(Landroid/media/audiopolicy/AudioMix;)Landroid/media/audiopolicy/AudioPolicy$Builder;
+Landroid/media/audiopolicy/AudioPolicy$Builder;->build()Landroid/media/audiopolicy/AudioPolicy;
+Landroid/media/audiopolicy/AudioPolicy$Builder;-><init>(Landroid/content/Context;)V
+Landroid/media/audiopolicy/AudioPolicy$Builder;->setAudioPolicyFocusListener(Landroid/media/audiopolicy/AudioPolicy$AudioPolicyFocusListener;)V
+Landroid/media/audiopolicy/AudioPolicy$Builder;->setLooper(Landroid/os/Looper;)Landroid/media/audiopolicy/AudioPolicy$Builder;
+Landroid/media/audiopolicy/AudioPolicy;->createAudioRecordSink(Landroid/media/audiopolicy/AudioMix;)Landroid/media/AudioRecord;
 Landroid/media/AudioSystem;->setDeviceConnectionState(IILjava/lang/String;Ljava/lang/String;)I
 Landroid/media/AudioTrack;->getLatency()I
 Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService;
@@ -358,6 +488,19 @@
 Landroid/media/Ringtone;->setVolume(F)V
 Landroid/media/SubtitleController;->mHandler:Landroid/os/Handler;
 Landroid/media/ThumbnailUtils;->createImageThumbnail(Ljava/lang/String;I)Landroid/graphics/Bitmap;
+Landroid/metrics/LogMaker;->getCategory()I
+Landroid/metrics/LogMaker;->getCounterBucket()J
+Landroid/metrics/LogMaker;->getCounterName()Ljava/lang/String;
+Landroid/metrics/LogMaker;->getCounterValue()I
+Landroid/metrics/LogMaker;->getTimestamp()J
+Landroid/metrics/LogMaker;->isLongCounterBucket()Z
+Landroid/metrics/LogMaker;->serialize()[Ljava/lang/Object;
+Landroid/metrics/MetricsReader;->checkpoint()V
+Landroid/metrics/MetricsReader;->hasNext()Z
+Landroid/metrics/MetricsReader;-><init>()V
+Landroid/metrics/MetricsReader;->next()Landroid/metrics/LogMaker;
+Landroid/metrics/MetricsReader;->read(J)V
+Landroid/metrics/MetricsReader;->reset()V
 Landroid/net/ConnectivityManager;->ACTION_TETHER_STATE_CHANGED:Ljava/lang/String;
 Landroid/net/ConnectivityManager;->EXTRA_ACTIVE_TETHER:Ljava/lang/String;
 Landroid/net/ConnectivityManager;->getActiveLinkProperties()Landroid/net/LinkProperties;
@@ -370,11 +513,20 @@
 Landroid/net/ConnectivityManager;->isNetworkTypeMobile(I)Z
 Landroid/net/ConnectivityManager;->isTetheringSupported()Z
 Landroid/net/ConnectivityManager;->mService:Landroid/net/IConnectivityManager;
+Landroid/net/ConnectivityManager$OnStartTetheringCallback;-><init>()V
 Landroid/net/ConnectivityManager;->requestRouteToHostAddress(ILjava/net/InetAddress;)Z
 Landroid/net/ConnectivityManager;->requestRouteToHost(II)Z
+Landroid/net/ConnectivityManager;->startTethering(IZLandroid/net/ConnectivityManager$OnStartTetheringCallback;Landroid/os/Handler;)V
+Landroid/net/ConnectivityManager;->startTethering(IZLandroid/net/ConnectivityManager$OnStartTetheringCallback;)V
+Landroid/net/ConnectivityManager;->stopTethering(I)V
 Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String;
 Landroid/net/LinkProperties;->setHttpProxy(Landroid/net/ProxyInfo;)V
+Landroid/net/NetworkKey;-><init>(Landroid/net/WifiKey;)V
 Landroid/net/NetworkPolicyManager;->mService:Landroid/net/INetworkPolicyManager;
+Landroid/net/NetworkRecommendationProvider;-><init>(Landroid/content/Context;Ljava/util/concurrent/Executor;)V
+Landroid/net/NetworkScoreManager;->clearScores()Z
+Landroid/net/NetworkScoreManager;->getActiveScorerPackage()Ljava/lang/String;
+Landroid/net/NetworkScoreManager;->updateScores([Landroid/net/ScoredNetwork;)Z
 Landroid/net/NetworkStats;->capacity:I
 Landroid/net/NetworkStats;->defaultNetwork:[I
 Landroid/net/NetworkStats;->iface:[Ljava/lang/String;
@@ -389,37 +541,92 @@
 Landroid/net/NetworkStats;->txBytes:[J
 Landroid/net/NetworkStats;->txPackets:[J
 Landroid/net/NetworkStats;->uid:[I
+Landroid/net/RssiCurve;-><init>(II[BI)V
+Landroid/net/RssiCurve;-><init>(II[B)V
+Landroid/net/RssiCurve;->lookupScore(IZ)B
+Landroid/net/ScoredNetwork;-><init>(Landroid/net/NetworkKey;Landroid/net/RssiCurve;)V
+Landroid/net/ScoredNetwork;-><init>(Landroid/net/NetworkKey;Landroid/net/RssiCurve;ZLandroid/os/Bundle;)V
+Landroid/net/ScoredNetwork;-><init>(Landroid/net/NetworkKey;Landroid/net/RssiCurve;Z)V
+Landroid/net/SSLCertificateSocketFactory;->castToOpenSSLSocket(Ljava/net/Socket;)Lcom/android/org/conscrypt/OpenSSLSocketImpl;
+Landroid/net/SSLCertificateSocketFactory;->getAlpnSelectedProtocol(Ljava/net/Socket;)[B
+Landroid/net/SSLCertificateSocketFactory;->getDelegate()Ljavax/net/ssl/SSLSocketFactory;
 Landroid/net/SSLCertificateSocketFactory;->getHttpSocketFactory(ILandroid/net/SSLSessionCache;)Lorg/apache/http/conn/ssl/SSLSocketFactory;
+Landroid/net/SSLCertificateSocketFactory;-><init>(ILandroid/net/SSLSessionCache;Z)V
+Landroid/net/SSLCertificateSocketFactory;->INSECURE_TRUST_MANAGER:[Ljavax/net/ssl/TrustManager;
+Landroid/net/SSLCertificateSocketFactory;->isSslCheckRelaxed()Z
+Landroid/net/SSLCertificateSocketFactory;->makeSocketFactory([Ljavax/net/ssl/KeyManager;[Ljavax/net/ssl/TrustManager;)Ljavax/net/ssl/SSLSocketFactory;
+Landroid/net/SSLCertificateSocketFactory;->mAlpnProtocols:[B
+Landroid/net/SSLCertificateSocketFactory;->mChannelIdPrivateKey:Ljava/security/PrivateKey;
+Landroid/net/SSLCertificateSocketFactory;->mHandshakeTimeoutMillis:I
+Landroid/net/SSLCertificateSocketFactory;->mInsecureFactory:Ljavax/net/ssl/SSLSocketFactory;
+Landroid/net/SSLCertificateSocketFactory;->mKeyManagers:[Ljavax/net/ssl/KeyManager;
+Landroid/net/SSLCertificateSocketFactory;->mNpnProtocols:[B
+Landroid/net/SSLCertificateSocketFactory;->mSecureFactory:Ljavax/net/ssl/SSLSocketFactory;
+Landroid/net/SSLCertificateSocketFactory;->mSecure:Z
+Landroid/net/SSLCertificateSocketFactory;->mSessionCache:Lcom/android/org/conscrypt/SSLClientSessionCache;
+Landroid/net/SSLCertificateSocketFactory;->mTrustManagers:[Ljavax/net/ssl/TrustManager;
+Landroid/net/SSLCertificateSocketFactory;->setAlpnProtocols([[B)V
+Landroid/net/SSLCertificateSocketFactory;->setChannelIdPrivateKey(Ljava/security/PrivateKey;)V
+Landroid/net/SSLCertificateSocketFactory;->setSoWriteTimeout(Ljava/net/Socket;I)V
+Landroid/net/SSLCertificateSocketFactory;->TAG:Ljava/lang/String;
+Landroid/net/SSLCertificateSocketFactory;->toLengthPrefixedList([[[B)[B
+Landroid/net/SSLCertificateSocketFactory;->verifyHostname(Ljava/net/Socket;Ljava/lang/String;)V
 Landroid/net/TrafficStats;->getStatsService()Landroid/net/INetworkStatsService;
+Landroid/net/TrafficStats;->setThreadStatsTagBackup()V
+Landroid/net/TrafficStats;->setThreadStatsTagRestore()V
+Landroid/net/TrafficStats;->setThreadStatsUid(I)V
+Landroid/net/WebAddress;-><init>(Ljava/lang/String;)V
+Landroid/net/WifiKey;-><init>(Ljava/lang/String;Ljava/lang/String;)V
 Landroid/net/wifi/p2p/WifiP2pGroup;->getNetworkId()I
 Landroid/net/wifi/p2p/WifiP2pGroupList;->getGroupList()Ljava/util/Collection;
 Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p2p/WifiP2pManager$Channel;ILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->requestPersistentGroupInfo(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/p2p/WifiP2pManager$PersistentGroupInfoListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->setDeviceName(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Ljava/lang/String;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
+Landroid/net/wifi/RttManager;->getRttCapabilities()Landroid/net/wifi/RttManager$RttCapabilities;
+Landroid/net/wifi/RttManager$RttParams;-><init>()V
+Landroid/net/wifi/RttManager;->startRanging([Landroid/net/wifi/RttManager$RttParams;Landroid/net/wifi/RttManager$RttListener;)V
 Landroid/net/wifi/WifiConfiguration;->apBand:I
 Landroid/net/wifi/WifiConfiguration;->apChannel:I
 Landroid/net/wifi/WifiConfiguration;->hasNoInternetAccess()Z
+Landroid/net/wifi/WifiConfiguration;->isEphemeral()Z
+Landroid/net/wifi/WifiConfiguration;->isNoInternetAccessExpected()Z
 Landroid/net/wifi/WifiConfiguration;->mIpConfiguration:Landroid/net/IpConfiguration;
 Landroid/net/wifi/WifiConfiguration;->validatedInternetAccess:Z
 Landroid/net/wifi/WifiManager;->connect(ILandroid/net/wifi/WifiManager$ActionListener;)V
 Landroid/net/wifi/WifiManager;->connect(Landroid/net/wifi/WifiConfiguration;Landroid/net/wifi/WifiManager$ActionListener;)V
 Landroid/net/wifi/WifiManager;->EXTRA_WIFI_AP_STATE:Ljava/lang/String;
 Landroid/net/wifi/WifiManager;->forget(ILandroid/net/wifi/WifiManager$ActionListener;)V
+Landroid/net/wifi/WifiManager;->getPrivilegedConfiguredNetworks()Ljava/util/List;
 Landroid/net/wifi/WifiManager;->getWifiApConfiguration()Landroid/net/wifi/WifiConfiguration;
 Landroid/net/wifi/WifiManager;->getWifiApState()I
 Landroid/net/wifi/WifiManager;->isDualBandSupported()Z
 Landroid/net/wifi/WifiManager;->isWifiApEnabled()Z
+Landroid/net/wifi/WifiManager;->isWifiScannerSupported()Z
 Landroid/net/wifi/WifiManager;->mService:Landroid/net/wifi/IWifiManager;
 Landroid/net/wifi/WifiManager;->save(Landroid/net/wifi/WifiConfiguration;Landroid/net/wifi/WifiManager$ActionListener;)V
 Landroid/net/wifi/WifiManager;->setWifiApConfiguration(Landroid/net/wifi/WifiConfiguration;)Z
+Landroid/net/wifi/WifiManager;->startScan(Landroid/os/WorkSource;)Z
 Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_CHANGED_ACTION:Ljava/lang/String;
 Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_DISABLED:I
 Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_DISABLING:I
 Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_ENABLED:I
 Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_ENABLING:I
 Landroid/net/wifi/WifiManager;->WIFI_AP_STATE_FAILED:I
+Landroid/net/wifi/WifiScanner;->getScanResults()Z
+Landroid/net/wifi/WifiScanner$ScanData;->getResults()[Landroid/net/wifi/ScanResult;
+Landroid/net/wifi/WifiScanner$ScanSettings;-><init>()V
+Landroid/net/wifi/WifiScanner;->startBackgroundScan(Landroid/net/wifi/WifiScanner$ScanSettings;Landroid/net/wifi/WifiScanner$ScanListener;)V
+Landroid/net/wifi/WifiScanner;->startScan(Landroid/net/wifi/WifiScanner$ScanSettings;Landroid/net/wifi/WifiScanner$ScanListener;Landroid/os/WorkSource;)V
+Landroid/net/wifi/WifiScanner;->startScan(Landroid/net/wifi/WifiScanner$ScanSettings;Landroid/net/wifi/WifiScanner$ScanListener;)V
+Landroid/net/wifi/WifiScanner;->stopBackgroundScan(Landroid/net/wifi/WifiScanner$ScanListener;)V
+Landroid/net/wifi/WifiSsid;->NONE:Ljava/lang/String;
+Landroid/nfc/NfcAdapter;->addNfcUnlockHandler(Landroid/nfc/NfcAdapter$NfcUnlockHandler;[Ljava/lang/String;)Z
+Landroid/nfc/NfcAdapter;->disable()Z
+Landroid/nfc/NfcAdapter;->enable()Z
 Landroid/nfc/NfcAdapter;->getDefaultAdapter()Landroid/nfc/NfcAdapter;
+Landroid/nfc/NfcAdapter;->removeNfcUnlockHandler(Landroid/nfc/NfcAdapter$NfcUnlockHandler;)Z
 Landroid/nfc/NfcAdapter;->setNdefPushMessageCallback(Landroid/nfc/NfcAdapter$CreateNdefMessageCallback;Landroid/app/Activity;I)V
+Landroid/nfc/NfcAdapter;->setNdefPushMessage(Landroid/nfc/NdefMessage;Landroid/app/Activity;I)V
 Landroid/opengl/GLSurfaceView$EglHelper;->mEglContext:Ljavax/microedition/khronos/egl/EGLContext;
 Landroid/opengl/GLSurfaceView$GLThread;->mEglHelper:Landroid/opengl/GLSurfaceView$EglHelper;
 Landroid/opengl/GLSurfaceView;->mGLThread:Landroid/opengl/GLSurfaceView$GLThread;
@@ -429,6 +636,7 @@
 Landroid/os/AsyncTask;->mWorker:Landroid/os/AsyncTask$WorkerRunnable;
 Landroid/os/AsyncTask;->sDefaultExecutor:Ljava/util/concurrent/Executor;
 Landroid/os/AsyncTask;->setDefaultExecutor(Ljava/util/concurrent/Executor;)V
+Landroid/os/BatteryStats$HistoryItem;->states2:I
 Landroid/os/BatteryStats;->NUM_DATA_CONNECTION_TYPES:I
 Landroid/os/BatteryStats$Timer;->getTotalTimeLocked(JI)J
 Landroid/os/BatteryStats$Uid;->getFullWifiLockTime(JI)J
@@ -546,27 +754,40 @@
 Landroid/os/UpdateEngine;->applyPayload(Ljava/lang/String;JJ[Ljava/lang/String;)V
 Landroid/os/UpdateEngine;->bind(Landroid/os/UpdateEngineCallback;Landroid/os/Handler;)Z
 Landroid/os/UpdateEngine;->bind(Landroid/os/UpdateEngineCallback;)Z
+Landroid/os/UpdateEngineCallback;-><init>()V
+Landroid/os/UpdateEngineCallback;->onPayloadApplicationComplete(I)V
+Landroid/os/UpdateEngineCallback;->onStatusUpdate(IF)V
 Landroid/os/UpdateEngine;->cancel()V
+Landroid/os/UpdateEngine;-><init>()V
 Landroid/os/UpdateEngine;->resetStatus()V
 Landroid/os/UpdateLock;->acquire()V
 Landroid/os/UpdateLock;->isHeld()Z
+Landroid/os/UpdateLock;->NOW_IS_CONVENIENT:Ljava/lang/String;
 Landroid/os/UpdateLock;->release()V
+Landroid/os/UpdateLock;->UPDATE_LOCK_CHANGED:Ljava/lang/String;
 Landroid/os/UserHandle;->ALL:Landroid/os/UserHandle;
+Landroid/os/UserHandle;->getAppIdFromSharedAppGid(I)I
+Landroid/os/UserHandle;->getCallingUserId()I
 Landroid/os/UserHandle;->getIdentifier()I
 Landroid/os/UserHandle;->getUserId(I)I
+Landroid/os/UserHandle;-><init>(I)V
 Landroid/os/UserHandle;->isOwner()Z
 Landroid/os/UserHandle;->myUserId()I
 Landroid/os/UserHandle;->of(I)Landroid/os/UserHandle;
+Landroid/os/UserHandle;->USER_OWNER:I
+Landroid/os/UserManager;->getBadgedLabelForUser(Ljava/lang/CharSequence;Landroid/os/UserHandle;)Ljava/lang/CharSequence;
 Landroid/os/UserManager;->get(Landroid/content/Context;)Landroid/os/UserManager;
 Landroid/os/UserManager;->getMaxSupportedUsers()I
 Landroid/os/UserManager;->getProfiles(I)Ljava/util/List;
 Landroid/os/UserManager;->getUserHandle()I
 Landroid/os/UserManager;->getUserHandle(I)I
 Landroid/os/UserManager;->getUserInfo(I)Landroid/content/pm/UserInfo;
+Landroid/os/UserManager;->getUserRestrictionSource(Ljava/lang/String;Landroid/os/UserHandle;)I
 Landroid/os/UserManager;->getUserSerialNumber(I)I
 Landroid/os/UserManager;->getUsers()Ljava/util/List;
 Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
 Landroid/os/UserManager;->isLinkedUser()Z
+Landroid/os/UserManager;->isManagedProfile()Z
 Landroid/os/UserManager;->isUserUnlocked(I)Z
 Landroid/os/WorkSource;->add(ILjava/lang/String;)Z
 Landroid/os/WorkSource;->add(I)Z
@@ -641,10 +862,40 @@
 Landroid/service/media/IMediaBrowserServiceCallbacks;->onLoadChildren(Ljava/lang/String;Landroid/content/pm/ParceledListSlice;)V
 Landroid/service/media/IMediaBrowserServiceCallbacks;->onLoadChildrenWithOptions(Ljava/lang/String;Landroid/content/pm/ParceledListSlice;Landroid/os/Bundle;)V
 Landroid/service/media/MediaBrowserService;->KEY_MEDIA_ITEM:Ljava/lang/String;
+Landroid/service/media/MediaBrowserService$Result;->mFlags:I
 Landroid/service/notification/NotificationListenerService;->registerAsSystemService(Landroid/content/Context;Landroid/content/ComponentName;I)V
 Landroid/service/notification/NotificationListenerService;->unregisterAsSystemService()V
+Landroid/service/persistentdata/PersistentDataBlockManager;->getMaximumDataBlockSize()J
+Landroid/service/persistentdata/PersistentDataBlockManager;->read()[B
+Landroid/service/persistentdata/PersistentDataBlockManager;->write([B)I
+Landroid/service/resolver/ResolverRankerService;-><init>()V
+Landroid/service/resolver/ResolverTarget;->getChooserScore()F
+Landroid/service/resolver/ResolverTarget;->getLaunchScore()F
+Landroid/service/resolver/ResolverTarget;->getRecencyScore()F
+Landroid/service/resolver/ResolverTarget;->getSelectProbability()F
+Landroid/service/resolver/ResolverTarget;->getTimeSpentScore()F
+Landroid/service/resolver/ResolverTarget;->setSelectProbability(F)V
+Landroid/service/trust/TrustAgentService;-><init>()V
+Landroid/service/voice/VoiceInteractionService;->isKeyphraseAndLocaleSupportedForHotword(Ljava/lang/String;Ljava/util/Locale;)Z
 Landroid/service/wallpaper/WallpaperService$Engine;->setFixedSizeAllowed(Z)V
 Landroid/speech/tts/TextToSpeech;->getCurrentEngine()Ljava/lang/String;
+Landroid/system/StructTimeval;->fromMillis(J)Landroid/system/StructTimeval;
+Landroid/telecom/AudioState;->getRoute()I
+Landroid/telecom/AudioState;->getSupportedRouteMask()I
+Landroid/telecom/AudioState;->isMuted()Z
+Landroid/telecom/Call;->addListener(Landroid/telecom/Call$Listener;)V
+Landroid/telecom/Call$Listener;-><init>()V
+Landroid/telecom/Call;->removeListener(Landroid/telecom/Call$Listener;)V
+Landroid/telecom/Phone;->addListener(Landroid/telecom/Phone$Listener;)V
+Landroid/telecom/Phone;->getAudioState()Landroid/telecom/AudioState;
+Landroid/telecom/Phone;->getCallAudioState()Landroid/telecom/CallAudioState;
+Landroid/telecom/Phone;->getCalls()Ljava/util/List;
+Landroid/telecom/Phone$Listener;-><init>()V
+Landroid/telecom/Phone;->removeListener(Landroid/telecom/Phone$Listener;)V
+Landroid/telecom/Phone;->setAudioRoute(I)V
+Landroid/telecom/Phone;->setMuted(Z)V
+Landroid/telecom/TelecomManager;->endCall()Z
+Landroid/telecom/TelecomManager;->EXTRA_IS_HANDOVER:Ljava/lang/String;
 Landroid/telephony/PhoneStateListener;->mSubId:Ljava/lang/Integer;
 Landroid/telephony/ServiceState;->newFromBundle(Landroid/os/Bundle;)Landroid/telephony/ServiceState;
 Landroid/telephony/SignalStrength;->getCdmaLevel()I
@@ -657,10 +908,12 @@
 Landroid/telephony/SmsMessage;->mWrappedSmsMessage:Lcom/android/internal/telephony/SmsMessageBase;
 Landroid/telephony/SubscriptionManager;->getDefaultSmsPhoneId()I
 Landroid/telephony/SubscriptionManager;->getPhoneId(I)I
+Landroid/telephony/SubscriptionManager;->getSlotIndex(I)I
 Landroid/telephony/SubscriptionManager;->getSubId(I)[I
 Landroid/telephony/SubscriptionManager;->setDefaultSmsSubId(I)V
 Landroid/telephony/TelephonyManager;->checkCarrierPrivilegesForPackage(Ljava/lang/String;)I
 Landroid/telephony/TelephonyManager;->from(Landroid/content/Context;)Landroid/telephony/TelephonyManager;
+Landroid/telephony/TelephonyManager;->getCarrierPackageNamesForIntent(Landroid/content/Intent;)Ljava/util/List;
 Landroid/telephony/TelephonyManager;->getCurrentPhoneType()I
 Landroid/telephony/TelephonyManager;->getCurrentPhoneType(I)I
 Landroid/telephony/TelephonyManager;->getDataEnabled(I)Z
@@ -691,6 +944,37 @@
 Landroid/text/SpannableStringBuilder;->mSpanFlags:[I
 Landroid/text/SpannableStringBuilder;->mSpans:[Ljava/lang/Object;
 Landroid/text/SpannableStringBuilder;->mSpanStarts:[I
+Landroid/text/SpannableStringInternal;->charAt(I)C
+Landroid/text/SpannableStringInternal;->checkRange(Ljava/lang/String;II)V
+Landroid/text/SpannableStringInternal;->COLUMNS:I
+Landroid/text/SpannableStringInternal;->copySpans(Landroid/text/SpannableStringInternal;II)V
+Landroid/text/SpannableStringInternal;->copySpans(Landroid/text/Spanned;II)V
+Landroid/text/SpannableStringInternal;->EMPTY:[Ljava/lang/Object;
+Landroid/text/SpannableStringInternal;->END:I
+Landroid/text/SpannableStringInternal;->FLAGS:I
+Landroid/text/SpannableStringInternal;->getChars(II[CI)V
+Landroid/text/SpannableStringInternal;->getSpanEnd(Ljava/lang/Object;)I
+Landroid/text/SpannableStringInternal;->getSpanFlags(Ljava/lang/Object;)I
+Landroid/text/SpannableStringInternal;->getSpans(IILjava/lang/Class;)[Ljava/lang/Object;
+Landroid/text/SpannableStringInternal;->getSpanStart(Ljava/lang/Object;)I
+Landroid/text/SpannableStringInternal;-><init>(Ljava/lang/CharSequence;II)V
+Landroid/text/SpannableStringInternal;->isIndexFollowsNextLine(I)Z
+Landroid/text/SpannableStringInternal;->isOutOfCopyRange(IIII)Z
+Landroid/text/SpannableStringInternal;->length()I
+Landroid/text/SpannableStringInternal;->mSpanCount:I
+Landroid/text/SpannableStringInternal;->mSpanData:[I
+Landroid/text/SpannableStringInternal;->mSpans:[Ljava/lang/Object;
+Landroid/text/SpannableStringInternal;->mText:Ljava/lang/String;
+Landroid/text/SpannableStringInternal;->nextSpanTransition(IILjava/lang/Class;)I
+Landroid/text/SpannableStringInternal;->region(II)Ljava/lang/String;
+Landroid/text/SpannableStringInternal;->removeSpan(Ljava/lang/Object;)V
+Landroid/text/SpannableStringInternal;->sendSpanAdded(Ljava/lang/Object;II)V
+Landroid/text/SpannableStringInternal;->sendSpanChanged(Ljava/lang/Object;IIII)V
+Landroid/text/SpannableStringInternal;->sendSpanRemoved(Ljava/lang/Object;II)V
+Landroid/text/SpannableStringInternal;->setSpan(Ljava/lang/Object;III)V
+Landroid/text/SpannableStringInternal;->setSpan(Ljava/lang/Object;IIIZ)V
+Landroid/text/SpannableStringInternal;->START:I
+Landroid/text/StaticLayout;-><init>(Ljava/lang/CharSequence;IILandroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZLandroid/text/TextUtils$TruncateAt;II)V
 Landroid/text/StaticLayout;->mColumns:I
 Landroid/text/StaticLayout;->mLineCount:I
 Landroid/text/StaticLayout;->mLines:[I
@@ -732,11 +1016,14 @@
 Landroid/view/IWindowManager;->setStrictModeVisualIndicatorPreference(Ljava/lang/String;)V
 Landroid/view/IWindowManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindowManager;
 Landroid/view/IWindowSession$Stub$Proxy;->relayout(Landroid/view/IWindow;ILandroid/view/WindowManager$LayoutParams;IIIILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/view/DisplayCutout$ParcelableWrapper;Landroid/util/MergedConfiguration;Landroid/view/Surface;)I
+Landroid/view/LayoutInflater;->createViewFromTag(Landroid/view/View;Ljava/lang/String;Landroid/content/Context;Landroid/util/AttributeSet;)Landroid/view/View;
+Landroid/view/LayoutInflater;->createViewFromTag(Landroid/view/View;Ljava/lang/String;Landroid/content/Context;Landroid/util/AttributeSet;Z)Landroid/view/View;
 Landroid/view/LayoutInflater;->mConstructorArgs:[Ljava/lang/Object;
 Landroid/view/LayoutInflater;->mFactory2:Landroid/view/LayoutInflater$Factory2;
 Landroid/view/LayoutInflater;->mFactory:Landroid/view/LayoutInflater$Factory;
 Landroid/view/LayoutInflater;->mFactorySet:Z
 Landroid/view/LayoutInflater;->sConstructorMap:Ljava/util/HashMap;
+Landroid/view/LayoutInflater;->setPrivateFactory(Landroid/view/LayoutInflater$Factory2;)V
 Landroid/view/MotionEvent;->HISTORY_CURRENT:I
 Landroid/view/MotionEvent;->mNativePtr:J
 Landroid/view/MotionEvent;->nativeGetRawAxisValue(JIII)F
@@ -809,6 +1096,7 @@
 Landroid/view/View;->mScrollX:I
 Landroid/view/View;->mScrollY:I
 Landroid/view/View;->mStartActivityRequestWho:Ljava/lang/String;
+Landroid/view/View;->mTag:Ljava/lang/Object;
 Landroid/view/View;->mTop:I
 Landroid/view/View;->mUnscaledDrawingCache:Landroid/graphics/Bitmap;
 Landroid/view/View;->notifySubtreeAccessibilityStateChangedIfNeeded()V
@@ -847,20 +1135,72 @@
 Landroid/view/Window;->mAppName:Ljava/lang/String;
 Landroid/view/Window;->mAppToken:Landroid/os/IBinder;
 Landroid/view/Window;->mHardwareAccelerated:Z
+Landroid/webkit/FindActionModeCallback;->findAll()V
+Landroid/webkit/FindActionModeCallback;-><init>(Landroid/content/Context;)V
+Landroid/webkit/FindActionModeCallback;->setText(Ljava/lang/String;)V
+Landroid/webkit/FindActionModeCallback;->setWebView(Landroid/webkit/WebView;)V
+Landroid/webkit/FindActionModeCallback;->showSoftInput()V
+Landroid/webkit/GeolocationPermissions;-><init>()V
+Landroid/webkit/HttpAuthHandler;-><init>()V
+Landroid/webkit/JsDialogHelper;-><init>(Landroid/webkit/JsPromptResult;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Landroid/webkit/JsDialogHelper;->showDialog(Landroid/content/Context;)V
+Landroid/webkit/JsPromptResult;->getStringResult()Ljava/lang/String;
+Landroid/webkit/JsPromptResult;-><init>(Landroid/webkit/JsResult$ResultReceiver;)V
+Landroid/webkit/SslErrorHandler;-><init>()V
+Landroid/webkit/TokenBindingService;-><init>()V
+Landroid/webkit/TokenBindingService$TokenBindingKey;-><init>()V
+Landroid/webkit/WebChromeClient;->openFileChooser(Landroid/webkit/ValueCallback;Ljava/lang/String;Ljava/lang/String;)V
+Landroid/webkit/WebMessagePort;-><init>()V
+Landroid/webkit/WebResourceError;-><init>()V
+Landroid/webkit/WebResourceResponse;-><init>(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;Ljava/io/InputStream;)V
+Landroid/webkit/WebSettings;->getAcceptThirdPartyCookies()Z
+Landroid/webkit/WebSettings;->setAcceptThirdPartyCookies(Z)V
 Landroid/webkit/WebSettings;->setNavDump(Z)V
 Landroid/webkit/WebSettings;->setPluginsEnabled(Z)V
+Landroid/webkit/WebStorage;-><init>()V
+Landroid/webkit/WebStorage$Origin;-><init>(Ljava/lang/String;JJ)V
 Landroid/webkit/WebView;->debugDump()V
+Landroid/webkit/WebViewDelegate;->addWebViewAssetPath(Landroid/content/Context;)V
+Landroid/webkit/WebViewDelegate;->callDrawGlFunction(Landroid/graphics/Canvas;JLjava/lang/Runnable;)V
+Landroid/webkit/WebViewDelegate;->callDrawGlFunction(Landroid/graphics/Canvas;J)V
+Landroid/webkit/WebViewDelegate;->canInvokeDrawGlFunctor(Landroid/view/View;)Z
+Landroid/webkit/WebViewDelegate;->detachDrawGlFunctor(Landroid/view/View;J)V
+Landroid/webkit/WebViewDelegate;->getApplication()Landroid/app/Application;
+Landroid/webkit/WebViewDelegate;->getDataDirectorySuffix()Ljava/lang/String;
+Landroid/webkit/WebViewDelegate;->getErrorString(Landroid/content/Context;I)Ljava/lang/String;
+Landroid/webkit/WebViewDelegate;->getPackageId(Landroid/content/res/Resources;Ljava/lang/String;)I
+Landroid/webkit/WebViewDelegate;->invokeDrawGlFunctor(Landroid/view/View;JZ)V
+Landroid/webkit/WebViewDelegate;->isMultiProcessEnabled()Z
+Landroid/webkit/WebViewDelegate;->isTraceTagEnabled()Z
+Landroid/webkit/WebViewDelegate;->setOnTraceEnabledChangeListener(Landroid/webkit/WebViewDelegate$OnTraceEnabledChangeListener;)V
 Landroid/webkit/WebView;->disablePlatformNotifications()V
 Landroid/webkit/WebView;->emulateShiftHeld()V
 Landroid/webkit/WebView;->enablePlatformNotifications()V
 Landroid/webkit/WebViewFactory;->getLoadedPackageInfo()Landroid/content/pm/PackageInfo;
 Landroid/webkit/WebViewFactory;->getProvider()Landroid/webkit/WebViewFactoryProvider;
+Landroid/webkit/WebViewFactory;->loadWebViewNativeLibraryFromPackage(Ljava/lang/String;Ljava/lang/ClassLoader;)I
 Landroid/webkit/WebViewFactory;->sPackageInfo:Landroid/content/pm/PackageInfo;
 Landroid/webkit/WebView;->getVisibleTitleHeight()I
 Landroid/webkit/WebView;->getWebViewProvider()Landroid/webkit/WebViewProvider;
+Landroid/webkit/WebView$HitTestResult;-><init>()V
+Landroid/webkit/WebView$HitTestResult;->setExtra(Ljava/lang/String;)V
+Landroid/webkit/WebView$HitTestResult;->setType(I)V
 Landroid/webkit/WebView;->isPaused()Z
 Landroid/webkit/WebView;->mProvider:Landroid/webkit/WebViewProvider;
 Landroid/webkit/WebView;->notifyFindDialogDismissed()V
+Landroid/webkit/WebView$PrivateAccess;->overScrollBy(IIIIIIIIZ)V
+Landroid/webkit/WebView$PrivateAccess;->setMeasuredDimension(II)V
+Landroid/webkit/WebView$PrivateAccess;->super_dispatchKeyEvent(Landroid/view/KeyEvent;)Z
+Landroid/webkit/WebView$PrivateAccess;->super_getScrollBarStyle()I
+Landroid/webkit/WebView$PrivateAccess;->super_onDrawVerticalScrollBar(Landroid/graphics/Canvas;Landroid/graphics/drawable/Drawable;IIII)V
+Landroid/webkit/WebView$PrivateAccess;->super_onGenericMotionEvent(Landroid/view/MotionEvent;)Z
+Landroid/webkit/WebView$PrivateAccess;->super_performAccessibilityAction(ILandroid/os/Bundle;)Z
+Landroid/webkit/WebView$PrivateAccess;->super_performLongClick()Z
+Landroid/webkit/WebView$PrivateAccess;->super_requestFocus(ILandroid/graphics/Rect;)Z
+Landroid/webkit/WebView$PrivateAccess;->super_scrollTo(II)V
+Landroid/webkit/WebView$PrivateAccess;->super_setFrame(IIII)Z
+Landroid/webkit/WebView$PrivateAccess;->super_setLayoutParams(Landroid/view/ViewGroup$LayoutParams;)V
+Landroid/webkit/WebView$PrivateAccess;->super_startActivityForResult(Landroid/content/Intent;I)V
 Landroid/webkit/WebView;->restorePicture(Landroid/os/Bundle;Ljava/io/File;)Z
 Landroid/webkit/WebView;->savePicture(Landroid/os/Bundle;Ljava/io/File;)Z
 Landroid/webkit/WebView;->sEnforceThreadChecking:Z
@@ -1003,9 +1343,27 @@
 Landroid/widget/VideoView;->mVideoWidth:I
 Lcom/android/internal/app/IBatteryStats;->getStatistics()[B
 Lcom/android/internal/app/IBatteryStats$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IBatteryStats;
+Lcom/android/internal/os/BatterySipper;->add(Lcom/android/internal/os/BatterySipper;)V
+Lcom/android/internal/os/BatterySipper;->drainType:Lcom/android/internal/os/BatterySipper$DrainType;
+Lcom/android/internal/os/BatterySipper;->getUid()I
+Lcom/android/internal/os/BatterySipper;-><init>(Lcom/android/internal/os/BatterySipper$DrainType;Landroid/os/BatteryStats$Uid;D)V
+Lcom/android/internal/os/BatterySipper;->mPackages:[Ljava/lang/String;
+Lcom/android/internal/os/BatterySipper;->packageWithHighestDrain:Ljava/lang/String;
+Lcom/android/internal/os/BatterySipper;->totalPowerMah:D
+Lcom/android/internal/os/BatterySipper;->uidObj:Landroid/os/BatteryStats$Uid;
+Lcom/android/internal/os/BatteryStatsHelper;->getMaxPower()D
+Lcom/android/internal/os/BatteryStatsHelper;->getStats()Landroid/os/BatteryStats;
+Lcom/android/internal/os/BatteryStatsHelper;->getTotalPower()D
+Lcom/android/internal/os/BatteryStatsHelper;-><init>(Landroid/content/Context;ZZ)V
+Lcom/android/internal/os/BatteryStatsHelper;->load()V
+Lcom/android/internal/os/BatteryStatsHelper;->mBatteryInfo:Lcom/android/internal/app/IBatteryStats;
+Lcom/android/internal/os/BatteryStatsHelper;->mPowerProfile:Lcom/android/internal/os/PowerProfile;
+Lcom/android/internal/os/BatteryStatsHelper;->mUsageList:Ljava/util/List;
+Lcom/android/internal/os/BatteryStatsHelper;->refreshStats(II)V
 Lcom/android/internal/os/BatteryStatsImpl;->computeBatteryRealtime(JI)J
 Lcom/android/internal/os/BatteryStatsImpl;->computeBatteryUptime(JI)J
 Lcom/android/internal/os/BatteryStatsImpl;->CREATOR:Landroid/os/Parcelable$Creator;
+Lcom/android/internal/os/BatteryStatsImpl;->getDischargeAmount(I)I
 Lcom/android/internal/os/BatteryStatsImpl;->getGlobalWifiRunningTime(JI)J
 Lcom/android/internal/os/BatteryStatsImpl;->getScreenOnTime(JI)J
 Lcom/android/internal/os/BatteryStatsImpl;->getUidStats()Landroid/util/SparseArray;
@@ -1091,9 +1449,13 @@
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([B)V
 Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
 Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
+Ldalvik/system/BlockGuard;->getThreadPolicy()Ldalvik/system/BlockGuard$Policy;
+Ldalvik/system/BlockGuard$Policy;->onNetwork()V
+Ldalvik/system/CloseGuard;->close()V
 Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard;
 Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
 Ldalvik/system/CloseGuard;->warnIfOpen()V
+Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class;
 Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
 Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
 Ldalvik/system/DexFile;->openDexFile(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object;
@@ -1113,6 +1475,7 @@
 Ldalvik/system/VMRuntime;->newNonMovableArray(Ljava/lang/Class;I)Ljava/lang/Object;
 Ldalvik/system/VMRuntime;->registerNativeAllocation(I)V
 Ldalvik/system/VMRuntime;->registerNativeFree(I)V
+Ldalvik/system/VMRuntime;->runFinalization(J)V
 Ldalvik/system/VMRuntime;->setMinimumHeapSize(J)J
 Ldalvik/system/VMRuntime;->setTargetHeapUtilization(F)F
 Ldalvik/system/VMRuntime;->trackExternalAllocation(J)Z
@@ -1133,13 +1496,39 @@
 Ljava/lang/Daemons$FinalizerDaemon;->finalizingObject:Ljava/lang/Object;
 Ljava/lang/Daemons$FinalizerDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerDaemon;
 Ljava/lang/Daemons$FinalizerWatchdogDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerWatchdogDaemon;
+Ljava/lang/Daemons;->requestHeapTrim()V
+Ljava/lang/Daemons;->start()V
+Ljava/lang/Daemons;->stop()V
+Ljava/lang/ref/FinalizerReference;->add(Ljava/lang/Object;)V
+Ljava/lang/reflect/Executable;->artMethod:J
+Ljava/lang/reflect/Parameter;-><init>(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V
+Ljava/lang/ref/ReferenceQueue;->add(Ljava/lang/ref/Reference;)V
 Ljava/lang/Runtime;->loadLibrary(Ljava/lang/String;Ljava/lang/ClassLoader;)V
 Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V
 Ljava/lang/Runtime;->nativeLoad(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;
+Ljava/lang/String;-><init>(II[C)V
+Ljava/lang/Thread;->daemon:Z
+Ljava/lang/Thread;->dispatchUncaughtException(Ljava/lang/Throwable;)V
+Ljava/lang/ThreadGroup;->add(Ljava/lang/Thread;)V
+Ljava/lang/ThreadGroup;->groups:[Ljava/lang/ThreadGroup;
+Ljava/lang/Thread;->group:Ljava/lang/ThreadGroup;
+Ljava/lang/ThreadGroup;->mainThreadGroup:Ljava/lang/ThreadGroup;
+Ljava/lang/ThreadGroup;->name:Ljava/lang/String;
+Ljava/lang/ThreadGroup;->ngroups:I
 Ljava/lang/ThreadGroup;->parent:Ljava/lang/ThreadGroup;
 Ljava/lang/ThreadGroup;->systemThreadGroup:Ljava/lang/ThreadGroup;
+Ljava/lang/ThreadGroup;->threadTerminated(Ljava/lang/Thread;)V
 Ljava/lang/Thread;->inheritableThreadLocals:Ljava/lang/ThreadLocal$ThreadLocalMap;
+Ljava/lang/Thread;-><init>(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V
+Ljava/lang/Thread;->lock:Ljava/lang/Object;
+Ljava/lang/Thread;->name:Ljava/lang/String;
+Ljava/lang/Thread;->nativePeer:J
+Ljava/lang/Thread;->priority:I
+Ljava/lang/Throwable;->backtrace:Ljava/lang/Object;
+Ljava/lang/Throwable;->cause:Ljava/lang/Throwable;
 Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;
+Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement;
+Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List;
 Ljava/net/Authenticator;->theAuthenticator:Ljava/net/Authenticator;
 Ljava/net/DatagramSocket;->impl:Ljava/net/DatagramSocketImpl;
 Ljava/net/InetAddress;->clearDnsCache()V
@@ -1147,9 +1536,18 @@
 Ljava/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress;
 Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
 Ljava/net/URI;->host:Ljava/lang/String;
+Ljava/nio/Buffer;->address:J
+Ljava/nio/Buffer;->capacity:I
+Ljava/nio/Buffer;->limit:I
+Ljava/nio/ByteBuffer;->hb:[B
+Ljava/nio/ByteBuffer;->isReadOnly:Z
+Ljava/nio/ByteBuffer;->offset:I
 Ljava/nio/charset/CharsetEncoder;->canEncode(Ljava/nio/CharBuffer;)Z
+Ljava/nio/DirectByteBuffer;-><init>(JI)V
 Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String;
 Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
+Ljava/util/ArrayList;->elementData:[Ljava/lang/Object;
+Ljava/util/ArrayList;->size:I
 Ljava/util/ArrayList$SubList;->parent:Ljava/util/AbstractList;
 Ljava/util/ArrayList$SubList;->parentOffset:I
 Ljava/util/ArrayList$SubList;->size:I
@@ -1159,6 +1557,7 @@
 Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
 Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory;
 Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
+Llibcore/util/ZoneInfo;->mTransitions:[J
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
 Lorg/json/JSONArray;->values:Ljava/util/List;
 Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 5ee7ede..4626cb2 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -348,4 +348,9 @@
      * Returns is the caller has the same uid as the Recents component
      */
     public abstract boolean isCallerRecents(int callingUid);
+
+    /**
+     * Whether an UID is active or idle.
+     */
+    public abstract boolean isUidActive(int uid);
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3d088ff..5a63319 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -113,6 +113,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.LogPrinter;
+import android.util.MergedConfiguration;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
@@ -166,9 +167,9 @@
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.text.DateFormat;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -204,7 +205,7 @@
     private static final boolean DEBUG_SERVICE = false;
     public static final boolean DEBUG_MEMORY_TRIM = false;
     private static final boolean DEBUG_PROVIDER = false;
-    private static final boolean DEBUG_ORDER = false;
+    public static final boolean DEBUG_ORDER = false;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
     private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
@@ -222,7 +223,7 @@
     private static final boolean REPORT_TO_ACTIVITY = true;
 
     // Maximum number of recent tokens to maintain for debugging purposes
-    private static final int MAX_RECENT_TOKENS = 10;
+    private static final int MAX_DESTROYED_ACTIVITIES = 10;
 
     /**
      * Denotes an invalid sequence number corresponding to a process state change.
@@ -256,7 +257,7 @@
     final H mH = new H();
     final Executor mExecutor = new HandlerExecutor(mH);
     final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
-    final ArrayDeque<Integer> mRecentTokens = new ArrayDeque<>();
+    final ArrayList<DestroyedActivityInfo> mRecentDestroyedActivities = new ArrayList<>();
 
     // List of new activities (via ActivityRecord.nextIdle) that should
     // be reported when next we idle.
@@ -339,6 +340,26 @@
         }
     }
 
+    /**
+     * TODO(b/71506345): Remove this once bug is resolved.
+     */
+    private static final class DestroyedActivityInfo {
+        private final Integer mToken;
+        private final String mReason;
+        private final long mTime;
+
+        DestroyedActivityInfo(Integer token, String reason) {
+            mToken = token;
+            mReason = reason;
+            mTime = System.currentTimeMillis();
+        }
+
+        void dump(PrintWriter pw, String prefix) {
+            pw.println(prefix + "[token:" + mToken + " | time:" + mTime + " | reason:" + mReason
+                    + "]");
+        }
+    }
+
     // The lock of mProviderMap protects the following variables.
     final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
         = new ArrayMap<ProviderKey, ProviderClientRecord>();
@@ -398,7 +419,6 @@
         boolean startsNotResumed;
         public final boolean isForward;
         int pendingConfigChanges;
-        boolean onlyLocalRequest;
 
         Window mPendingRemoveWindow;
         WindowManager mPendingRemoveWindowManager;
@@ -520,7 +540,6 @@
             sb.append(", startsNotResumed=").append(startsNotResumed);
             sb.append(", isForward=").append(isForward);
             sb.append(", pendingConfigChanges=").append(pendingConfigChanges);
-            sb.append(", onlyLocalRequest=").append(onlyLocalRequest);
             sb.append(", preserveWindow=").append(mPreserveWindow);
             if (activity != null) {
                 sb.append(", Activity{");
@@ -765,15 +784,6 @@
             sendMessage(H.SLEEPING, token, sleeping ? 1 : 0);
         }
 
-        @Override
-        public final void scheduleRelaunchActivity(IBinder token,
-                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-                int configChanges, boolean notResumed, Configuration config,
-                Configuration overrideConfig, boolean preserveWindow) {
-            requestRelaunchActivity(token, pendingResults, pendingNewIntents,
-                    configChanges, notResumed, config, overrideConfig, true, preserveWindow);
-        }
-
         public final void scheduleReceiver(Intent intent, ActivityInfo info,
                 CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
                 boolean sync, int sendingUser, int processState) {
@@ -1531,7 +1541,6 @@
         public static final int UNBIND_SERVICE          = 122;
         public static final int DUMP_SERVICE            = 123;
         public static final int LOW_MEMORY              = 124;
-        public static final int RELAUNCH_ACTIVITY       = 126;
         public static final int PROFILER_CONTROL        = 127;
         public static final int CREATE_BACKUP_AGENT     = 128;
         public static final int DESTROY_BACKUP_AGENT    = 129;
@@ -1577,7 +1586,6 @@
                     case UNBIND_SERVICE: return "UNBIND_SERVICE";
                     case DUMP_SERVICE: return "DUMP_SERVICE";
                     case LOW_MEMORY: return "LOW_MEMORY";
-                    case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
                     case PROFILER_CONTROL: return "PROFILER_CONTROL";
                     case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
                     case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
@@ -1611,12 +1619,6 @@
         public void handleMessage(Message msg) {
             if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
             switch (msg.what) {
-                case RELAUNCH_ACTIVITY: {
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
-                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;
-                    handleRelaunchActivity(r);
-                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                } break;
                 case BIND_APPLICATION:
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                     AppBindData data = (AppBindData)msg.obj;
@@ -2182,14 +2184,28 @@
 
     @Override
     public void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + "mActivities:");
+        pw.println(prefix + "Activities:");
 
-        for (ArrayMap.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
-            pw.println(prefix + "  [token:" + entry.getKey().hashCode() + " record:"
-                    + entry.getValue().toString() + "]");
+        if (!mActivities.isEmpty()) {
+            final Iterator<Map.Entry<IBinder, ActivityClientRecord>> activitiesIterator =
+                    mActivities.entrySet().iterator();
+
+            while (activitiesIterator.hasNext()) {
+                final ArrayMap.Entry<IBinder, ActivityClientRecord> entry =
+                        activitiesIterator.next();
+                pw.println(prefix + "  [token:" + entry.getKey().hashCode() + " record:"
+                        + entry.getValue().toString() + "]");
+            }
         }
 
-        pw.println(prefix + "mRecentTokens:" + mRecentTokens);
+        if (!mRecentDestroyedActivities.isEmpty()) {
+            pw.println(prefix + "Recent destroyed activities:");
+            for (int i = 0, size = mRecentDestroyedActivities.size(); i < size; i++) {
+                final DestroyedActivityInfo info = mRecentDestroyedActivities.get(i);
+                pw.print(prefix);
+                info.dump(pw, "  ");
+            }
+        }
     }
 
     public static void dumpMemInfoTable(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
@@ -2876,11 +2892,6 @@
             r.setState(ON_CREATE);
 
             mActivities.put(r.token, r);
-            mRecentTokens.push(r.token.hashCode());
-
-            if (mRecentTokens.size() > MAX_RECENT_TOKENS) {
-                mRecentTokens.removeLast();
-            }
 
         } catch (SuperNotCalledException e) {
             throw e;
@@ -3726,20 +3737,6 @@
                 }
                 r.activity.performResume(r.startsNotResumed);
 
-                synchronized (mResourcesManager) {
-                    // If there is a pending local relaunch that was requested when the activity was
-                    // paused, it will put the activity into paused state when it finally happens.
-                    // Since the activity resumed before being relaunched, we don't want that to
-                    // happen, so we need to clear the request to relaunch paused.
-                    for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) {
-                        final ActivityClientRecord relaunching = mRelaunchingActivities.get(i);
-                        if (relaunching.token == r.token
-                                && relaunching.onlyLocalRequest && relaunching.startsNotResumed) {
-                            relaunching.startsNotResumed = false;
-                        }
-                    }
-                }
-
                 EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED, UserHandle.myUserId(),
                         r.activity.getComponentName().getClassName(), reason);
 
@@ -3888,14 +3885,12 @@
                 }
             }
 
-            if (!r.onlyLocalRequest) {
-                r.nextIdle = mNewActivities;
-                mNewActivities = r;
-                if (localLOGV) Slog.v(
-                    TAG, "Scheduling idle handler for " + r);
-                Looper.myQueue().addIdleHandler(new Idler());
+            r.nextIdle = mNewActivities;
+            mNewActivities = r;
+            if (localLOGV) {
+                Slog.v(TAG, "Scheduling idle handler for " + r);
             }
-            r.onlyLocalRequest = false;
+            Looper.myQueue().addIdleHandler(new Idler());
         } else {
             // If an exception was thrown when trying to resume, then
             // just end this activity.
@@ -4453,7 +4448,7 @@
 
     /** Core implementation of activity destroy call. */
     ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
-            int configChanges, boolean getNonConfigInstance) {
+            int configChanges, boolean getNonConfigInstance, String reason) {
         ActivityClientRecord r = mActivities.get(token);
         Class<? extends Activity> activityClass = null;
         if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
@@ -4505,6 +4500,12 @@
             r.setState(ON_DESTROY);
         }
         mActivities.remove(token);
+        mRecentDestroyedActivities.add(0, new DestroyedActivityInfo(token.hashCode(), reason));
+
+        final int recentDestroyedActivitiesSize = mRecentDestroyedActivities.size();
+        if (recentDestroyedActivitiesSize > MAX_DESTROYED_ACTIVITIES) {
+            mRecentDestroyedActivities.remove(recentDestroyedActivitiesSize - 1);
+        }
         StrictMode.decrementExpectedActivityCount(activityClass);
         return r;
     }
@@ -4516,9 +4517,9 @@
 
     @Override
     public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
-            boolean getNonConfigInstance) {
+            boolean getNonConfigInstance, String reason) {
         ActivityClientRecord r = performDestroyActivity(token, finishing,
-                configChanges, getNonConfigInstance);
+                configChanges, getNonConfigInstance, reason);
         if (r != null) {
             cleanUpPendingRemoveWindows(r, finishing);
             WindowManager wm = r.activity.getWindowManager();
@@ -4586,15 +4587,12 @@
         mSomeActivitiesChanged = true;
     }
 
-    /**
-     * @param preserveWindow Whether the activity should try to reuse the window it created,
-     *                        including the decor view after the relaunch.
-     */
-    public final void requestRelaunchActivity(IBinder token,
+    @Override
+    public ActivityClientRecord prepareRelaunchActivity(IBinder token,
             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-            int configChanges, boolean notResumed, Configuration config,
-            Configuration overrideConfig, boolean fromServer, boolean preserveWindow) {
+            int configChanges, MergedConfiguration config, boolean preserveWindow) {
         ActivityClientRecord target = null;
+        boolean scheduleRelaunch = false;
 
         synchronized (mResourcesManager) {
             for (int i=0; i<mRelaunchingActivities.size(); i++) {
@@ -4616,57 +4614,31 @@
                             r.pendingIntents = pendingNewIntents;
                         }
                     }
-
-                    // For each relaunch request, activity manager expects an answer
-                    if (!r.onlyLocalRequest && fromServer) {
-                        try {
-                            ActivityManager.getService().activityRelaunched(token);
-                        } catch (RemoteException e) {
-                            throw e.rethrowFromSystemServer();
-                        }
-                    }
                     break;
                 }
             }
 
             if (target == null) {
-                if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null, fromServer:"
-                        + fromServer);
+                if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null");
                 target = new ActivityClientRecord();
                 target.token = token;
                 target.pendingResults = pendingResults;
                 target.pendingIntents = pendingNewIntents;
                 target.mPreserveWindow = preserveWindow;
-                if (!fromServer) {
-                    final ActivityClientRecord existing = mActivities.get(token);
-                    if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: " + existing);
-                    if (existing != null) {
-                        if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: paused= "
-                                + existing.paused);;
-                        target.startsNotResumed = existing.paused;
-                        target.overrideConfig = existing.overrideConfig;
-                    }
-                    target.onlyLocalRequest = true;
-                }
                 mRelaunchingActivities.add(target);
-                sendMessage(H.RELAUNCH_ACTIVITY, target);
+                scheduleRelaunch = true;
             }
-
-            if (fromServer) {
-                target.startsNotResumed = notResumed;
-                target.onlyLocalRequest = false;
-            }
-            if (config != null) {
-                target.createdConfig = config;
-            }
-            if (overrideConfig != null) {
-                target.overrideConfig = overrideConfig;
-            }
+            target.createdConfig = config.getGlobalConfiguration();
+            target.overrideConfig = config.getOverrideConfiguration();
             target.pendingConfigChanges |= configChanges;
         }
+
+        return scheduleRelaunch ? target : null;
     }
 
-    private void handleRelaunchActivity(ActivityClientRecord tmp) {
+    @Override
+    public void handleRelaunchActivity(ActivityClientRecord tmp,
+            PendingTransactionActions pendingActions) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
         unscheduleGcIdler();
@@ -4735,18 +4707,10 @@
         ActivityClientRecord r = mActivities.get(tmp.token);
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
         if (r == null) {
-            if (!tmp.onlyLocalRequest) {
-                try {
-                    ActivityManager.getService().activityRelaunched(tmp.token);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
-            }
             return;
         }
 
         r.activity.mConfigChangeFlags |= configChanges;
-        r.onlyLocalRequest = tmp.onlyLocalRequest;
         r.mPreserveWindow = tmp.mPreserveWindow;
 
         r.activity.mChangingConfigurations = true;
@@ -4763,9 +4727,9 @@
         // preserved by the server, so we want to notify it that we are preparing to replace
         // everything
         try {
-            if (r.mPreserveWindow || r.onlyLocalRequest) {
+            if (r.mPreserveWindow) {
                 WindowManagerGlobal.getWindowSession().prepareToReplaceWindows(
-                        r.token, !r.onlyLocalRequest);
+                        r.token, true /* childrenOnly */);
             }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -4780,7 +4744,7 @@
             callActivityOnStop(r, true /* saveState */, "handleRelaunchActivity");
         }
 
-        handleDestroyActivity(r.token, false, configChanges, true);
+        handleDestroyActivity(r.token, false, configChanges, true, "handleRelaunchActivity");
 
         r.activity = null;
         r.window = null;
@@ -4804,24 +4768,22 @@
         r.startsNotResumed = tmp.startsNotResumed;
         r.overrideConfig = tmp.overrideConfig;
 
-        // TODO(lifecycler): Move relaunch to lifecycler.
-        PendingTransactionActions pendingActions = new PendingTransactionActions();
         handleLaunchActivity(r, pendingActions);
-        handleStartActivity(r, pendingActions);
-        handleResumeActivity(r.token, false /* clearHide */, r.isForward, "relaunch");
-        if (r.startsNotResumed) {
-            performPauseActivity(r, false /* finished */, "relaunch", pendingActions);
-        }
+        // Only report a successful relaunch to WindowManager.
+        pendingActions.setReportRelaunchToWindowManager(true);
+    }
 
-        if (!tmp.onlyLocalRequest) {
-            try {
-                ActivityManager.getService().activityRelaunched(r.token);
-                if (r.window != null) {
-                    r.window.reportActivityRelaunched();
-                }
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+    @Override
+    public void reportRelaunch(IBinder token, PendingTransactionActions pendingActions) {
+        try {
+            ActivityManager.getService().activityRelaunched(token);
+            final ActivityClientRecord r = mActivities.get(token);
+            if (pendingActions.shouldReportRelaunchToWindowManager() && r != null
+                    && r.window != null) {
+                r.window.reportActivityRelaunched();
             }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -5890,21 +5852,23 @@
 
         // Preload fonts resources
         FontsContract.setApplicationContextForResources(appContext);
-        try {
-            final ApplicationInfo info =
-                    getPackageManager().getApplicationInfo(
-                            data.appInfo.packageName,
-                            PackageManager.GET_META_DATA /*flags*/,
-                            UserHandle.myUserId());
-            if (info.metaData != null) {
-                final int preloadedFontsResource = info.metaData.getInt(
-                        ApplicationInfo.METADATA_PRELOADED_FONTS, 0);
-                if (preloadedFontsResource != 0) {
-                    data.info.getResources().preloadFonts(preloadedFontsResource);
+        if (!Process.isIsolated()) {
+            try {
+                final ApplicationInfo info =
+                        getPackageManager().getApplicationInfo(
+                                data.appInfo.packageName,
+                                PackageManager.GET_META_DATA /*flags*/,
+                                UserHandle.myUserId());
+                if (info.metaData != null) {
+                    final int preloadedFontsResource = info.metaData.getInt(
+                            ApplicationInfo.METADATA_PRELOADED_FONTS, 0);
+                    if (preloadedFontsResource != 0) {
+                        data.info.getResources().preloadFonts(preloadedFontsResource);
+                    }
                 }
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 5b61fdf..310965e 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -21,6 +21,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.os.IBinder;
+import android.util.MergedConfiguration;
 
 import com.android.internal.content.ReferrerIntent;
 
@@ -60,7 +61,7 @@
 
     /** Destroy the activity. */
     public abstract void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
-            boolean getNonConfigInstance);
+            boolean getNonConfigInstance, String reason);
 
     /** Pause the activity. */
     public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
@@ -124,6 +125,39 @@
     public abstract ActivityThread.ActivityClientRecord getActivityClient(IBinder token);
 
     /**
+     * Prepare activity relaunch to update internal bookkeeping. This is used to track multiple
+     * relaunch and config update requests.
+     * @param token Activity token.
+     * @param pendingResults Activity results to be delivered.
+     * @param pendingNewIntents New intent messages to be delivered.
+     * @param configChanges Mask of configuration changes that have occurred.
+     * @param config New configuration applied to the activity.
+     * @param preserveWindow Whether the activity should try to reuse the window it created,
+     *                        including the decor view after the relaunch.
+     * @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during
+     *         relaunch, or {@code null} if relaunch cancelled.
+     */
+    public abstract ActivityThread.ActivityClientRecord prepareRelaunchActivity(IBinder token,
+            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
+            int configChanges, MergedConfiguration config, boolean preserveWindow);
+
+    /**
+     * Perform activity relaunch.
+     * @param r Activity client record prepared for relaunch.
+     * @param pendingActions Pending actions to be used on later stages of activity transaction.
+     * */
+    public abstract void handleRelaunchActivity(ActivityThread.ActivityClientRecord r,
+            PendingTransactionActions pendingActions);
+
+    /**
+     * Report that relaunch request was handled.
+     * @param token Target activity token.
+     * @param pendingActions Pending actions initialized on earlier stages of activity transaction.
+     *                       Used to check if we should report relaunch to WM.
+     * */
+    public abstract void reportRelaunch(IBinder token, PendingTransactionActions pendingActions);
+
+    /**
      * Debugging output.
      * @param pw {@link PrintWriter} to write logs to.
      * @param prefix Prefix to prepend to output.
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4a9b2bc..a1ba13d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -409,6 +409,7 @@
         return sp;
     }
 
+    @GuardedBy("ContextImpl.class")
     private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked() {
         if (sSharedPrefsCache == null) {
             sSharedPrefsCache = new ArrayMap<>();
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 2b648ea..eb26026 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -609,18 +609,19 @@
 
     /**
      * A key was pressed down.
+     * <p>
+     * If the focused view didn't want this event, this method is called.
+     * <p>
+     * Default implementation consumes {@link KeyEvent#KEYCODE_BACK KEYCODE_BACK}
+     * and, as of {@link android.os.Build.VERSION_CODES#P P}, {@link KeyEvent#KEYCODE_ESCAPE
+     * KEYCODE_ESCAPE} to later handle them in {@link #onKeyUp}.
      * 
-     * <p>If the focused view didn't want this event, this method is called.
-     *
-     * <p>The default implementation consumed the KEYCODE_BACK to later
-     * handle it in {@link #onKeyUp}.
-     *
      * @see #onKeyUp
      * @see android.view.KeyEvent
      */
     @Override
     public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
+        if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
             event.startTracking();
             return true;
         }
@@ -640,16 +641,18 @@
 
     /**
      * A key was released.
-     * 
-     * <p>The default implementation handles KEYCODE_BACK to close the
-     * dialog.
+     * <p>
+     * Default implementation consumes {@link KeyEvent#KEYCODE_BACK KEYCODE_BACK}
+     * and, as of {@link android.os.Build.VERSION_CODES#P P}, {@link KeyEvent#KEYCODE_ESCAPE
+     * KEYCODE_ESCAPE} to close the dialog.
      *
      * @see #onKeyDown
-     * @see KeyEvent
+     * @see android.view.KeyEvent
      */
     @Override
     public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
+        if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
+                && event.isTracking()
                 && !event.isCanceled()) {
             onBackPressed();
             return true;
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 9e99a78..ae9b83e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -83,9 +83,6 @@
             int resultCode, in String data, in Bundle extras, boolean ordered,
             boolean sticky, int sendingUser, int processState);
     void scheduleLowMemory();
-    void scheduleRelaunchActivity(IBinder token, in List<ResultInfo> pendingResults,
-            in List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
-            in Configuration config, in Configuration overrideConfig, boolean preserveWindow);
     void scheduleSleeping(IBinder token, boolean sleeping);
     void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType);
     void setSchedulingGroup(int group);
diff --git a/core/java/android/app/InstantAppResolverService.java b/core/java/android/app/InstantAppResolverService.java
index 76a3682..2ba4c00 100644
--- a/core/java/android/app/InstantAppResolverService.java
+++ b/core/java/android/app/InstantAppResolverService.java
@@ -88,7 +88,7 @@
     public void onGetInstantAppResolveInfo(Intent sanitizedIntent, int[] hostDigestPrefix,
             String token, InstantAppResolutionCallback callback) {
         // if not overridden, forward to old methods and filter out non-web intents
-        if (sanitizedIntent.isBrowsableWebIntent()) {
+        if (sanitizedIntent.isWebIntent()) {
             onGetInstantAppResolveInfo(hostDigestPrefix, token, callback);
         } else {
             callback.onInstantAppResolveInfo(Collections.emptyList());
@@ -107,7 +107,7 @@
             String token, InstantAppResolutionCallback callback) {
         Log.e(TAG, "New onGetInstantAppIntentFilter is not overridden");
         // if not overridden, forward to old methods and filter out non-web intents
-        if (sanitizedIntent.isBrowsableWebIntent()) {
+        if (sanitizedIntent.isWebIntent()) {
             onGetInstantAppIntentFilter(hostDigestPrefix, token, callback);
         } else {
             callback.onInstantAppResolveInfo(Collections.emptyList());
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 1d34595..e297719 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -380,7 +380,7 @@
         }
         if (localLOGV) Log.v(TAG, r.id + ": destroying");
         mActivityThread.performDestroyActivity(r, finish, 0 /* configChanges */,
-                false /* getNonConfigInstance */);
+                false /* getNonConfigInstance */, "LocalActivityManager::performDestroy");
         r.activity = null;
         r.window = null;
         if (finish) {
@@ -645,7 +645,7 @@
             LocalActivityRecord r = mActivityArray.get(i);
             if (localLOGV) Log.v(TAG, r.id + ": destroying");
             mActivityThread.performDestroyActivity(r, finishing, 0 /* configChanges */,
-                    false /* getNonConfigInstance */);
+                    false /* getNonConfigInstance */, "LocalActivityManager::dispatchDestroy");
         }
         mActivities.clear();
         mActivityArray.clear();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6e40986..c805658 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1055,11 +1055,10 @@
     /**
      * {@link #extras} key: A
      * {@link android.content.ContentUris content URI} pointing to an image that can be displayed
-     * in the background when the notification is selected. The URI must point to an image stream
-     * suitable for passing into
+     * in the background when the notification is selected. Used on television platforms.
+     * The URI must point to an image stream suitable for passing into
      * {@link android.graphics.BitmapFactory#decodeStream(java.io.InputStream)
-     * BitmapFactory.decodeStream}; all other content types will be ignored. The content provider
-     * URI used for this purpose must require no permissions to read the image data.
+     * BitmapFactory.decodeStream}; all other content types will be ignored.
      */
     public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
 
@@ -4617,10 +4616,15 @@
                 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
                 for (int i=0; i<N; i++) {
                     Action action = mActions.get(i);
-                    validRemoteInput |= hasValidRemoteInput(action);
+                    boolean actionHasValidInput = hasValidRemoteInput(action);
+                    validRemoteInput |= actionHasValidInput;
 
                     final RemoteViews button = generateActionButton(action, emphazisedMode,
                             i % 2 != 0, p.ambient);
+                    if (actionHasValidInput) {
+                        // Clear the drawable
+                        button.setInt(R.id.action0, "setBackgroundResource", 0);
+                    }
                     big.addView(R.id.actions, button);
                 }
             } else {
@@ -6435,7 +6439,7 @@
         public RemoteViews makeContentView(boolean increasedHeight) {
             mBuilder.mOriginalActions = mBuilder.mActions;
             mBuilder.mActions = new ArrayList<>();
-            RemoteViews remoteViews = makeBigContentView(true /* showRightIcon */);
+            RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */);
             mBuilder.mActions = mBuilder.mOriginalActions;
             mBuilder.mOriginalActions = null;
             return remoteViews;
@@ -6470,11 +6474,11 @@
          */
         @Override
         public RemoteViews makeBigContentView() {
-            return makeBigContentView(false /* showRightIcon */);
+            return makeMessagingView(false /* isCollapsed */);
         }
 
         @NonNull
-        private RemoteViews makeBigContentView(boolean showRightIcon) {
+        private RemoteViews makeMessagingView(boolean isCollapsed) {
             CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
                     ? super.mBigContentTitle
                     : mConversationTitle;
@@ -6485,21 +6489,24 @@
                 nameReplacement = conversationTitle;
                 conversationTitle = null;
             }
+            boolean hideLargeIcon = !isCollapsed || isOneToOne;
             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
                     mBuilder.getMessagingLayoutResource(),
                     mBuilder.mParams.reset().hasProgress(false).title(conversationTitle).text(null)
-                            .hideLargeIcon(!showRightIcon || isOneToOne)
+                            .hideLargeIcon(hideLargeIcon)
                             .headerTextSecondary(conversationTitle)
-                            .alwaysShowReply(showRightIcon));
+                            .alwaysShowReply(isCollapsed));
             addExtras(mBuilder.mN.extras);
             // also update the end margin if there is an image
             int endMargin = R.dimen.notification_content_margin_end;
-            if (mBuilder.mN.hasLargeIcon() && showRightIcon) {
+            if (isCollapsed) {
                 endMargin = R.dimen.notification_content_plus_picture_margin_end;
             }
             contentView.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
                     mBuilder.resolveContrastColor());
+            contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsCollapsed",
+                    isCollapsed);
             contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
                     mBuilder.mN.mLargeIcon);
             contentView.setCharSequence(R.id.status_bar_latest_event_content, "setNameReplacement",
@@ -6566,7 +6573,7 @@
          */
         @Override
         public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
-            RemoteViews remoteViews = makeBigContentView(true /* showRightIcon */);
+            RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */);
             remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
             return remoteViews;
         }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index ae4ac3c..b10e608 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -24,6 +24,7 @@
 import android.app.Notification.Builder;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
@@ -98,7 +99,7 @@
      * This broadcast is only sent to the app whose block state has changed.
      *
      * Input: nothing
-     * Output: nothing
+     * Output: {@link #EXTRA_BLOCKED_STATE}
      */
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_APP_BLOCK_STATE_CHANGED =
@@ -113,24 +114,31 @@
      * This broadcast is only sent to the app that owns the channel that has changed.
      *
      * Input: nothing
-     * Output: {@link #EXTRA_BLOCK_STATE_CHANGED_ID}
+     * Output: {@link #EXTRA_NOTIFICATION_CHANNEL_ID}
+     * Output: {@link #EXTRA_BLOCKED_STATE}
      */
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED =
             "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
 
     /**
-     * Extra for {@link #ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED} or
-     * {@link #ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED} containing the id of the
-     * object which has a new blocked state.
+     * Extra for {@link #ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED} containing the id of the
+     * {@link NotificationChannel} which has a new blocked state.
      *
-     * The value will be the {@link NotificationChannel#getId()} of the channel for
-     * {@link #ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED} and
-     * the {@link NotificationChannelGroup#getId()} of the group for
-     * {@link #ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED}.
+     * The value will be the {@link NotificationChannel#getId()} of the channel.
      */
-    public static final String EXTRA_BLOCK_STATE_CHANGED_ID =
-            "android.app.extra.BLOCK_STATE_CHANGED_ID";
+    public static final String EXTRA_NOTIFICATION_CHANNEL_ID =
+            "android.app.extra.NOTIFICATION_CHANNEL_ID";
+
+    /**
+     * Extra for {@link #ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED} containing the id
+     * of the {@link NotificationChannelGroup} which has a new blocked state.
+     *
+     * The value will be the {@link NotificationChannelGroup#getId()} of the group.
+     */
+    public static final String EXTRA_NOTIFICATION_CHANNEL_GROUP_ID =
+            "android.app.extra.NOTIFICATION_CHANNEL_GROUP_ID";
+
 
     /**
      * Extra for {@link #ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED} or
@@ -142,7 +150,6 @@
      */
     public static final String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
 
-
     /**
      * Intent that is broadcast when a {@link NotificationChannelGroup} is
      * {@link NotificationChannelGroup#isBlocked() blocked} or unblocked.
@@ -150,7 +157,8 @@
      * This broadcast is only sent to the app that owns the channel group that has changed.
      *
      * Input: nothing
-     * Output: {@link #EXTRA_BLOCK_STATE_CHANGED_ID}
+     * Output: {@link #EXTRA_NOTIFICATION_CHANNEL_GROUP_ID}
+     * Output: {@link #EXTRA_BLOCKED_STATE}
      */
     @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED =
@@ -343,6 +351,14 @@
      * the same tag and id has already been posted by your application and has not yet been
      * canceled, it will be replaced by the updated information.
      *
+     * All {@link android.service.notification.NotificationListenerService listener services} will
+     * be granted {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} access to any {@link Uri uris}
+     * provided on this notification or the
+     * {@link NotificationChannel} this notification is posted to using
+     * {@link Context#grantUriPermission(String, Uri, int)}. Permission will be revoked when the
+     * notification is canceled, or you can revoke permissions with
+     * {@link Context#revokeUriPermission(Uri, int)}.
+     *
      * @param tag A string identifier for this notification.  May be {@code null}.
      * @param id An identifier for this notification.  The pair (tag, id) must be unique
      *        within your application.
@@ -363,11 +379,13 @@
         String pkg = mContext.getPackageName();
         // Fix the notification as best we can.
         Notification.addFieldsFromContext(mContext, notification);
+
         if (notification.sound != null) {
             notification.sound = notification.sound.getCanonicalUri();
             if (StrictMode.vmFileUriExposureEnabled()) {
                 notification.sound.checkFileUriExposed("Notification.sound");
             }
+
         }
         fixLegacySmallIcon(notification, pkg);
         if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
@@ -378,6 +396,7 @@
         }
         if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
         notification.reduceImageSizes(mContext);
+
         ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
         boolean isLowRam = am.isLowRamDevice();
         final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam);
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index c525c89..c2c91c2 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -30,20 +30,27 @@
  * @hide
  */
 @SystemApi
-public final class StatsManager extends android.util.StatsManager { // TODO: Remove the extends.
+public final class StatsManager {
     IStatsManager mService;
     private static final String TAG = "StatsManager";
+    private static final boolean DEBUG = false;
 
-    /** Long extra of uid that added the relevant stats config. */
-    public static final String EXTRA_STATS_CONFIG_UID =
-            "android.app.extra.STATS_CONFIG_UID";
-    /** Long extra of the relevant stats config's configKey. */
-    public static final String EXTRA_STATS_CONFIG_KEY =
-            "android.app.extra.STATS_CONFIG_KEY";
-    /** Long extra of the relevant statsd_config.proto's Subscription.id. */
+    /**
+     * Long extra of uid that added the relevant stats config.
+     */
+    public static final String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
+    /**
+     * Long extra of the relevant stats config's configKey.
+     */
+    public static final String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
+    /**
+     * Long extra of the relevant statsd_config.proto's Subscription.id.
+     */
     public static final String EXTRA_STATS_SUBSCRIPTION_ID =
             "android.app.extra.STATS_SUBSCRIPTION_ID";
-    /** Long extra of the relevant statsd_config.proto's Subscription.rule_id. */
+    /**
+     * Long extra of the relevant statsd_config.proto's Subscription.rule_id.
+     */
     public static final String EXTRA_STATS_SUBSCRIPTION_RULE_ID =
             "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
     /**
@@ -68,28 +75,34 @@
     }
 
     /**
+     * Temporary. Will be deleted.
+     */
+    @RequiresPermission(Manifest.permission.DUMP)
+    public boolean addConfiguration(long configKey, byte[] config, String a, String b) {
+        return addConfiguration(configKey, config);
+    }
+
+    /**
      * Clients can send a configuration and simultaneously registers the name of a broadcast
      * receiver that listens for when it should request data.
      *
      * @param configKey An arbitrary integer that allows clients to track the configuration.
      * @param config    Wire-encoded StatsDConfig proto that specifies metrics (and all
      *                  dependencies eg, conditions and matchers).
-     * @param pkg       The package name to receive the broadcast.
-     * @param cls       The name of the class that receives the broadcast.
      * @return true if successful
      */
     @RequiresPermission(Manifest.permission.DUMP)
-    public boolean addConfiguration(long configKey, byte[] config, String pkg, String cls) {
+    public boolean addConfiguration(long configKey, byte[] config) {
         synchronized (this) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when adding configuration");
+                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when adding configuration");
                     return false;
                 }
-                return service.addConfiguration(configKey, config, pkg, cls);
+                return service.addConfiguration(configKey, config);
             } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when adding configuration");
+                if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when adding configuration");
                 return false;
             }
         }
@@ -107,12 +120,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when removing configuration");
+                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when removing configuration");
                     return false;
                 }
                 return service.removeConfiguration(configKey);
             } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when removing configuration");
+                if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when removing configuration");
                 return false;
             }
         }
@@ -121,38 +134,34 @@
     /**
      * Set the PendingIntent to be used when broadcasting subscriber information to the given
      * subscriberId within the given config.
-     *
      * <p>
      * Suppose that the calling uid has added a config with key configKey, and that in this config
      * it is specified that when a particular anomaly is detected, a broadcast should be sent to
      * a BroadcastSubscriber with id subscriberId. This function links the given pendingIntent with
      * that subscriberId (for that config), so that this pendingIntent is used to send the broadcast
      * when the anomaly is detected.
-     *
      * <p>
      * When statsd sends the broadcast, the PendingIntent will used to send an intent with
      * information of
-     *   {@link #EXTRA_STATS_CONFIG_UID},
-     *   {@link #EXTRA_STATS_CONFIG_KEY},
-     *   {@link #EXTRA_STATS_SUBSCRIPTION_ID},
-     *   {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID}, and
-     *   {@link #EXTRA_STATS_DIMENSIONS_VALUE}.
-     *
+     * {@link #EXTRA_STATS_CONFIG_UID},
+     * {@link #EXTRA_STATS_CONFIG_KEY},
+     * {@link #EXTRA_STATS_SUBSCRIPTION_ID},
+     * {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID}, and
+     * {@link #EXTRA_STATS_DIMENSIONS_VALUE}.
      * <p>
      * This function can only be called by the owner (uid) of the config. It must be called each
      * time statsd starts. The config must have been added first (via addConfiguration()).
      *
-     * @param configKey The integer naming the config to which this subscriber is attached.
-     * @param subscriberId ID of the subscriber, as used in the config.
+     * @param configKey     The integer naming the config to which this subscriber is attached.
+     * @param subscriberId  ID of the subscriber, as used in the config.
      * @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
      *                      associated with the given subscriberId. May be null, in which case
      *                      it undoes any previous setting of this subscriberId.
      * @return true if successful
      */
     @RequiresPermission(Manifest.permission.DUMP)
-    public boolean setBroadcastSubscriber(long configKey,
-                                          long subscriberId,
-                                          PendingIntent pendingIntent) {
+    public boolean setBroadcastSubscriber(
+            long configKey, long subscriberId, PendingIntent pendingIntent) {
         synchronized (this) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
@@ -175,6 +184,44 @@
     }
 
     /**
+     * Registers the operation that is called to retrieve the metrics data. This must be called
+     * each time statsd starts. The config must have been added first (via addConfiguration(),
+     * although addConfiguration could have been called on a previous boot). This operation allows
+     * statsd to send metrics data whenever statsd determines that the metrics in memory are
+     * approaching the memory limits. The fetch operation should call {@link #getData} to fetch the
+     * data, which also deletes the retrieved metrics from statsd's memory.
+     *
+     * @param configKey     The integer naming the config to which this operation is attached.
+     * @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
+     *                      associated with the given subscriberId. May be null, in which case
+     *                      it removes any associated pending intent with this configKey.
+     * @return true if successful
+     */
+    @RequiresPermission(Manifest.permission.DUMP)
+    public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
+        synchronized (this) {
+            try {
+                IStatsManager service = getIStatsManagerLocked();
+                if (service == null) {
+                    Slog.d(TAG, "Failed to find statsd when registering data listener.");
+                    return false;
+                }
+                if (pendingIntent == null) {
+                    return service.removeDataFetchOperation(configKey);
+                } else {
+                    // Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
+                    IBinder intentSender = pendingIntent.getTarget().asBinder();
+                    return service.setDataFetchOperation(configKey, intentSender);
+                }
+
+            } catch (RemoteException e) {
+                Slog.d(TAG, "Failed to connect to statsd when registering data listener.");
+                return false;
+            }
+        }
+    }
+
+    /**
      * Clients can request data with a binder call. This getter is destructive and also clears
      * the retrieved metrics from statsd memory.
      *
@@ -187,12 +234,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting data");
+                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting data");
                     return null;
                 }
                 return service.getData(configKey);
             } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting data");
+                if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting data");
                 return null;
             }
         }
@@ -211,12 +258,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting metadata");
+                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting metadata");
                     return null;
                 }
                 return service.getMetadata();
             } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting metadata");
+                if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting metadata");
                 return null;
             }
         }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 87f32b2..aa52cde 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -38,7 +38,6 @@
 import android.content.Context;
 import android.content.IRestrictionsManager;
 import android.content.RestrictionsManager;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.CrossProfileApps;
 import android.content.pm.ICrossProfileApps;
 import android.content.pm.IShortcutService;
@@ -90,7 +89,6 @@
 import android.net.lowpan.LowpanManager;
 import android.net.nsd.INsdManager;
 import android.net.nsd.NsdManager;
-import android.net.wifi.IRttManager;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.IWifiScanner;
 import android.net.wifi.RttManager;
@@ -117,7 +115,6 @@
 import android.os.IUserManager;
 import android.os.IncidentManager;
 import android.os.PowerManager;
-import android.os.Process;
 import android.os.RecoverySystem;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
@@ -639,13 +636,13 @@
 
         registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
                 new CachedServiceFetcher<RttManager>() {
-            @Override
-            public RttManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT_SERVICE);
-                IRttManager service = IRttManager.Stub.asInterface(b);
-                return new RttManager(ctx.getOuterContext(), service,
-                        ConnectivityThread.getInstanceLooper());
-            }});
+                @Override
+                public RttManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                    IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT_RANGING_SERVICE);
+                    IWifiRttManager service = IWifiRttManager.Stub.asInterface(b);
+                    return new RttManager(ctx.getOuterContext(),
+                            new WifiRttManager(ctx.getOuterContext(), service));
+                }});
 
         registerService(Context.WIFI_RTT_RANGING_SERVICE, WifiRttManager.class,
                 new CachedServiceFetcher<WifiRttManager>() {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 26eb3bc..77e118c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -7682,6 +7682,7 @@
             throw re.rethrowFromSystemServer();
         }
     }
+
     /**
      * Called by a device owner or profile owner of secondary users that is affiliated with the
      * device to disable the keyguard altogether.
@@ -8320,6 +8321,22 @@
     }
 
     /**
+     * Forces a batch of security logs to be fetched from logd and makes it available for DPC.
+     * Only callable by ADB. If throttled, returns time to wait in milliseconds, otherwise 0.
+     * @hide
+     */
+    public long forceSecurityLogs() {
+        if (mService == null) {
+            return 0;
+        }
+        try {
+            return mService.forceSecurityLogs();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Called by the system to obtain a {@link DevicePolicyManager} whose calls act on the parent
      * profile.
      *
@@ -9387,41 +9404,6 @@
     }
 
     /**
-     * Allows/disallows printing.
-     *
-     * Called by a device owner or a profile owner.
-     * Device owner changes policy for all users. Profile owner can override it if present.
-     * Printing is enabled by default. If {@code FEATURE_PRINTING} is absent, the call is ignored.
-     *
-     * @param admin which {@link DeviceAdminReceiver} this request is associated with.
-     * @param enabled whether printing should be allowed or not.
-     * @throws SecurityException if {@code admin} is neither device, nor profile owner.
-     */
-    public void setPrintingEnabled(@NonNull ComponentName admin, boolean enabled) {
-        try {
-            mService.setPrintingEnabled(admin, enabled);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Returns whether printing is enabled for this user.
-     *
-     * Always {@code false} if {@code FEATURE_PRINTING} is absent.
-     * Otherwise, {@code true} by default.
-     *
-     * @return {@code true} iff printing is enabled.
-     */
-    public boolean isPrintingEnabled() {
-        try {
-            return mService.isPrintingEnabled();
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Called by device owner to add an override APN.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 5197de4..5218a73 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -349,6 +349,7 @@
     boolean isSecurityLoggingEnabled(in ComponentName admin);
     ParceledListSlice retrieveSecurityLogs(in ComponentName admin);
     ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin);
+    long forceSecurityLogs();
 
     boolean isUninstallInQueue(String packageName);
     void uninstallPackageWithActiveAdmins(String packageName);
@@ -401,9 +402,6 @@
     CharSequence getStartUserSessionMessage(in ComponentName admin);
     CharSequence getEndUserSessionMessage(in ComponentName admin);
 
-    void setPrintingEnabled(in ComponentName admin, boolean enabled);
-    boolean isPrintingEnabled();
-
     List<String> setMeteredDataDisabled(in ComponentName admin, in List<String> packageNames);
     List<String> getMeteredDataDisabled(in ComponentName admin);
 
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 08effd9..202b894 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -77,6 +77,7 @@
             TAG_KEY_DESTRUCTION,
             TAG_CERT_AUTHORITY_INSTALLED,
             TAG_CERT_AUTHORITY_REMOVED,
+            TAG_CRYPTO_SELF_TEST_COMPLETED,
     })
     public @interface SecurityLogTag {}
 
@@ -400,6 +401,14 @@
             SecurityLogTags.SECURITY_USER_RESTRICTION_REMOVED;
 
     /**
+     * Indicates that cryptographic functionality self test has completed. The log entry contains an
+     * {@code Integer} payload, indicating the result of the test (0 if the test failed, 1 if
+     * succeeded) and accessible via {@link SecurityEvent#getData()}.
+     */
+    public static final int TAG_CRYPTO_SELF_TEST_COMPLETED =
+            SecurityLogTags.SECURITY_CRYPTO_SELF_TEST_COMPLETED;
+
+    /**
      * Event severity level indicating that the event corresponds to normal workflow.
      */
     public static final int LEVEL_INFO = 1;
@@ -529,6 +538,7 @@
                 case TAG_USER_RESTRICTION_REMOVED:
                     return LEVEL_INFO;
                 case TAG_CERT_AUTHORITY_REMOVED:
+                case TAG_CRYPTO_SELF_TEST_COMPLETED:
                     return getSuccess() ? LEVEL_INFO : LEVEL_ERROR;
                 case TAG_CERT_AUTHORITY_INSTALLED:
                 case TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT:
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index be62678..b64b7e3 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -34,4 +34,5 @@
 210027 security_user_restriction_added          (package|3),(admin_user|1),(restriction|3)
 210028 security_user_restriction_removed        (package|3),(admin_user|1),(restriction|3)
 210029 security_cert_authority_installed        (success|1),(subject|3)
-210030 security_cert_authority_removed          (success|1),(subject|3)
\ No newline at end of file
+210030 security_cert_authority_removed          (success|1),(subject|3)
+210031 security_crypto_self_test_completed      (success|1)
\ No newline at end of file
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 8f49bc1..0f1c249 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -24,6 +24,7 @@
 import android.util.Log;
 import android.util.Pair;
 import android.view.View;
+import android.view.View.AutofillImportance;
 import android.view.ViewRootImpl;
 import android.view.ViewStructure;
 import android.view.ViewStructure.HtmlInfo;
@@ -632,6 +633,7 @@
         int mMaxEms = -1;
         int mMaxLength = -1;
         @Nullable String mTextIdEntry;
+        @AutofillImportance int mImportantForAutofill;
 
         // POJO used to override some autofill-related values when the node is parcelized.
         // Not written to parcel.
@@ -733,6 +735,7 @@
                 mMaxEms = in.readInt();
                 mMaxLength = in.readInt();
                 mTextIdEntry = preader.readString();
+                mImportantForAutofill = in.readInt();
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 mX = in.readInt();
@@ -900,6 +903,7 @@
                 out.writeInt(mMaxEms);
                 out.writeInt(mMaxLength);
                 pwriter.writeString(mTextIdEntry);
+                out.writeInt(mImportantForAutofill);
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 out.writeInt(mX);
@@ -1512,6 +1516,16 @@
         public int getMaxTextLength() {
             return mMaxLength;
         }
+
+        /**
+         * Gets the {@link View#setImportantForAutofill(int) importantForAutofill mode} of
+         * the view associated with this node.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
+         */
+        public @AutofillImportance int getImportantForAutofill() {
+            return mImportantForAutofill;
+        }
     }
 
     /**
@@ -1844,6 +1858,11 @@
         }
 
         @Override
+        public void setImportantForAutofill(@AutofillImportance int mode) {
+            mNode.mImportantForAutofill = mode;
+        }
+
+        @Override
         public void setInputType(int inputType) {
             mNode.mInputType = inputType;
         }
@@ -2144,7 +2163,8 @@
                     + ", options=" + Arrays.toString(node.getAutofillOptions())
                     + ", hints=" + Arrays.toString(node.getAutofillHints())
                     + ", value=" + node.getAutofillValue()
-                    + ", sanitized=" + node.isSanitized());
+                    + ", sanitized=" + node.isSanitized()
+                    + ", importantFor=" + node.getImportantForAutofill());
         }
 
         final int NCHILDREN = node.getChildCount();
diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
new file mode 100644
index 0000000..d8a7463
--- /dev/null
+++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.servertransaction;
+
+import static android.app.ActivityThread.DEBUG_ORDER;
+
+import android.app.ActivityThread;
+import android.app.ClientTransactionHandler;
+import android.app.ResultInfo;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Trace;
+import android.util.MergedConfiguration;
+import android.util.Slog;
+
+import com.android.internal.content.ReferrerIntent;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Activity relaunch callback.
+ * @hide
+ */
+public class ActivityRelaunchItem extends ClientTransactionItem {
+
+    private static final String TAG = "ActivityRelaunchItem";
+
+    private List<ResultInfo> mPendingResults;
+    private List<ReferrerIntent> mPendingNewIntents;
+    private int mConfigChanges;
+    private MergedConfiguration mConfig;
+    private boolean mPreserveWindow;
+
+    /**
+     * A record that was properly configured for relaunch. Execution will be cancelled if not
+     * initialized after {@link #preExecute(ClientTransactionHandler, IBinder)}.
+     */
+    private ActivityThread.ActivityClientRecord mActivityClientRecord;
+
+    @Override
+    public void preExecute(ClientTransactionHandler client, IBinder token) {
+        mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults,
+                mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
+    }
+
+    @Override
+    public void execute(ClientTransactionHandler client, IBinder token,
+            PendingTransactionActions pendingActions) {
+        if (mActivityClientRecord == null) {
+            if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled");
+            return;
+        }
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
+        client.handleRelaunchActivity(mActivityClientRecord, pendingActions);
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+    }
+
+    @Override
+    public void postExecute(ClientTransactionHandler client, IBinder token,
+            PendingTransactionActions pendingActions) {
+        client.reportRelaunch(token, pendingActions);
+    }
+
+    // ObjectPoolItem implementation
+
+    private ActivityRelaunchItem() {}
+
+    /** Obtain an instance initialized with provided params. */
+    public static ActivityRelaunchItem obtain(List<ResultInfo> pendingResults,
+            List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config,
+            boolean preserveWindow) {
+        ActivityRelaunchItem instance = ObjectPool.obtain(ActivityRelaunchItem.class);
+        if (instance == null) {
+            instance = new ActivityRelaunchItem();
+        }
+        instance.mPendingResults = pendingResults;
+        instance.mPendingNewIntents = pendingNewIntents;
+        instance.mConfigChanges = configChanges;
+        instance.mConfig = config;
+        instance.mPreserveWindow = preserveWindow;
+
+        return instance;
+    }
+
+    @Override
+    public void recycle() {
+        mPendingResults = null;
+        mPendingNewIntents = null;
+        mConfigChanges = 0;
+        mConfig = null;
+        mPreserveWindow = false;
+        mActivityClientRecord = null;
+        ObjectPool.recycle(this);
+    }
+
+
+    // Parcelable implementation
+
+    /** Write to Parcel. */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedList(mPendingResults, flags);
+        dest.writeTypedList(mPendingNewIntents, flags);
+        dest.writeInt(mConfigChanges);
+        dest.writeTypedObject(mConfig, flags);
+        dest.writeBoolean(mPreserveWindow);
+    }
+
+    /** Read from Parcel. */
+    private ActivityRelaunchItem(Parcel in) {
+        mPendingResults = in.createTypedArrayList(ResultInfo.CREATOR);
+        mPendingNewIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
+        mConfigChanges = in.readInt();
+        mConfig = in.readTypedObject(MergedConfiguration.CREATOR);
+        mPreserveWindow = in.readBoolean();
+    }
+
+    public static final Creator<ActivityRelaunchItem> CREATOR =
+            new Creator<ActivityRelaunchItem>() {
+                public ActivityRelaunchItem createFromParcel(Parcel in) {
+                    return new ActivityRelaunchItem(in);
+                }
+
+                public ActivityRelaunchItem[] newArray(int size) {
+                    return new ActivityRelaunchItem[size];
+                }
+            };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final ActivityRelaunchItem other = (ActivityRelaunchItem) o;
+        return Objects.equals(mPendingResults, other.mPendingResults)
+                && Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
+                && mConfigChanges == other.mConfigChanges && Objects.equals(mConfig, other.mConfig)
+                && mPreserveWindow == other.mPreserveWindow;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + Objects.hashCode(mPendingResults);
+        result = 31 * result + Objects.hashCode(mPendingNewIntents);
+        result = 31 * result + mConfigChanges;
+        result = 31 * result + Objects.hashCode(mConfig);
+        result = 31 * result + (mPreserveWindow ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "ActivityRelaunchItem{pendingResults=" + mPendingResults
+                + ",pendingNewIntents=" + mPendingNewIntents + ",configChanges="  + mConfigChanges
+                + ",config=" + mConfig + ",preserveWindow" + mPreserveWindow + "}";
+    }
+}
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
index cbcf6c7..48a79f7 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -37,7 +37,7 @@
             PendingTransactionActions pendingActions) {
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
         client.handleDestroyActivity(token, mFinished, mConfigChanges,
-                false /* getNonConfigInstance */);
+                false /* getNonConfigInstance */, getDescription());
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
diff --git a/core/java/android/app/servertransaction/PendingTransactionActions.java b/core/java/android/app/servertransaction/PendingTransactionActions.java
index 073d28c..af7b7a2 100644
--- a/core/java/android/app/servertransaction/PendingTransactionActions.java
+++ b/core/java/android/app/servertransaction/PendingTransactionActions.java
@@ -44,6 +44,7 @@
     private boolean mCallOnPostCreate;
     private Bundle mOldState;
     private StopInfo mStopInfo;
+    private boolean mReportRelaunchToWM;
 
     public PendingTransactionActions() {
         clear();
@@ -91,6 +92,24 @@
         mStopInfo = stopInfo;
     }
 
+    /**
+     * Check if we should report an activity relaunch to WindowManager. We report back for every
+     * relaunch request to ActivityManager, but only for those that were actually finished to we
+     * report to WindowManager.
+     */
+    public boolean shouldReportRelaunchToWindowManager() {
+        return mReportRelaunchToWM;
+    }
+
+    /**
+     * Set if we should report an activity relaunch to WindowManager. We report back for every
+     * relaunch request to ActivityManager, but only for those that were actually finished we report
+     * to WindowManager.
+     */
+    public void setReportRelaunchToWindowManager(boolean reportToWm) {
+        mReportRelaunchToWM = reportToWm;
+    }
+
     /** Reports to server about activity stop. */
     public static class StopInfo implements Runnable {
         private static final String TAG = "ActivityStopInfo";
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 78b393a..840fef8 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -194,7 +194,9 @@
                     break;
                 case ON_DESTROY:
                     mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */,
-                            0 /* configChanges */, false /* getNonConfigInstance */);
+                            0 /* configChanges */, false /* getNonConfigInstance */,
+                            "performLifecycleSequence. cycling to:"
+                                    + mLifecycleSequence.get(size - 1));
                     break;
                 case ON_RESTART:
                     mTransactionHandler.performRestartActivity(r.token, false /* start */);
diff --git a/core/java/android/app/timezone/RulesManager.java b/core/java/android/app/timezone/RulesManager.java
index 0a38eb9..dc79256 100644
--- a/core/java/android/app/timezone/RulesManager.java
+++ b/core/java/android/app/timezone/RulesManager.java
@@ -68,6 +68,23 @@
     private static final String TAG = "timezone.RulesManager";
     private static final boolean DEBUG = false;
 
+    /**
+     * The action of the intent that the Android system will broadcast when a time zone rules update
+     * operation has been successfully staged  (i.e. to be applied next reboot) or unstaged.
+     *
+     * <p>See {@link #EXTRA_OPERATION_STAGED}
+     *
+     * <p>This is a protected intent that can only be sent by the system.
+     */
+    public static final String ACTION_RULES_UPDATE_OPERATION =
+            "com.android.intent.action.timezone.RULES_UPDATE_OPERATION";
+
+    /**
+     * The key for a boolean extra for the {@link #ACTION_RULES_UPDATE_OPERATION} intent used to
+     * indicate whether the operation was a "stage" or an "unstage".
+     */
+    public static final String EXTRA_OPERATION_STAGED = "staged";
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "SUCCESS", "ERROR_" }, value = {
             SUCCESS,
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index edb992b..6b573e9 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -16,6 +16,7 @@
 package android.app.usage;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
 import android.content.res.Configuration;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -104,12 +105,14 @@
          * An event type denoting that a notification was viewed by the user.
          * @hide
          */
+        @SystemApi
         public static final int NOTIFICATION_SEEN = 10;
 
         /**
          * An event type denoting a change in App Standby Bucket.
          * @hide
          */
+        @SystemApi
         public static final int STANDBY_BUCKET_CHANGED = 11;
 
         /** @hide */
@@ -257,6 +260,17 @@
             return mShortcutId;
         }
 
+        /**
+         * Returns the standby bucket of the app, if the event is of type
+         * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0.
+         * @return the standby bucket associated with the event.
+         * @hide
+         */
+        @SystemApi
+        public int getStandbyBucket() {
+            return mBucket;
+        }
+
         /** @hide */
         public Event getObfuscatedIfInstantApp() {
             if ((mFlags & FLAG_IS_PACKAGE_INSTANT_APP) == 0) {
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 09f9684..09a5b59 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -676,6 +676,35 @@
         mExcludeSdp = excludeSdp;
     }
 
+    /**
+     * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This
+     * parameter is used by the BT Controller to set the maximum transmission packet size on this
+     * connection. This function is currently used for testing only.
+     * @hide
+     */
+    public void requestMaximumTxDataLength() throws IOException {
+        if (mDevice == null) {
+            throw new IOException("requestMaximumTxDataLength is called on null device");
+        }
+
+        try {
+            if (mSocketState == SocketState.CLOSED) {
+                throw new IOException("socket closed");
+            }
+            IBluetooth bluetoothProxy =
+                    BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+            if (bluetoothProxy == null) {
+                throw new IOException("Bluetooth is off");
+            }
+
+            if (DBG) Log.d(TAG, "requestMaximumTxDataLength");
+            bluetoothProxy.getSocketManager().requestMaximumTxDataLength(mDevice);
+        } catch (RemoteException e) {
+            Log.e(TAG, Log.getStackTraceString(new Throwable()));
+            throw new IOException("unable to send RPC: " + e.getMessage());
+        }
+    }
+
     private String convertAddr(final byte[] addr) {
         return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
                 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b85a319..15f3777 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -560,6 +560,7 @@
      *
      * @param resId Resource id for the CharSequence text
      */
+    @NonNull
     public final CharSequence getText(@StringRes int resId) {
         return getResources().getText(resId);
     }
@@ -616,12 +617,11 @@
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
-     * @return An object that can be used to draw this resource, or
-     *         {@code null} if the resource could not be resolved.
+     * @return An object that can be used to draw this resource.
      * @throws android.content.res.Resources.NotFoundException if the given ID
      *         does not exist.
      */
-    @Nullable
+    @NonNull
     public final Drawable getDrawable(@DrawableRes int id) {
         return getResources().getDrawable(id, getTheme());
     }
@@ -633,12 +633,11 @@
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
-     * @return A color state list, or {@code null} if the resource could not be
-     *         resolved.
+     * @return A color state list.
      * @throws android.content.res.Resources.NotFoundException if the given ID
      *         does not exist.
      */
-    @Nullable
+    @NonNull
     public final ColorStateList getColorStateList(@ColorRes int id) {
         return getResources().getColorStateList(id, getTheme());
     }
@@ -3539,6 +3538,7 @@
      * @hide
      */
     @SystemApi
+    @Deprecated
     public static final String WIFI_RTT_SERVICE = "rttmanager";
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9b62f19..12d4079 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2399,6 +2399,26 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
+
+    /**
+     * Broadcast Action: The current device {@link android.content.res.Configuration} has changed
+     * such that the device may be eligible for the installation of additional configuration splits.
+     * Configuration properties that can trigger this broadcast include locale and display density.
+     *
+     * <p class="note">
+     * Unlike {@link #ACTION_CONFIGURATION_CHANGED}, you <em>can</em> receive this through
+     * components declared in manifests. However, the receiver <em>must</em> hold the
+     * {@link android.Manifest.permission#INSTALL_PACKAGES} permission.
+     *
+     * <p class="note">
+     * This is a protected intent that can only be sent by the system.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SPLIT_CONFIGURATION_CHANGED =
+            "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
     /**
      * Broadcast Action: The current device's locale has changed.
      *
@@ -10089,9 +10109,8 @@
     }
 
     /** @hide */
-    public boolean isBrowsableWebIntent() {
+    public boolean isWebIntent() {
         return ACTION_VIEW.equals(mAction)
-                && hasCategory(CATEGORY_BROWSABLE)
                 && hasWebURI();
     }
 
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index 1a207ba..8464e26 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -16,10 +16,14 @@
 
 package android.content.om;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Immutable overlay information about a package. All PackageInfos that
  * represent an overlay package will have a corresponding OverlayInfo.
@@ -27,6 +31,19 @@
  * @hide
  */
 public final class OverlayInfo implements Parcelable {
+
+    @IntDef(prefix = "STATE_", value = {
+            STATE_UNKNOWN,
+            STATE_MISSING_TARGET,
+            STATE_NO_IDMAP,
+            STATE_DISABLED,
+            STATE_ENABLED,
+            STATE_TARGET_UPGRADING,
+            STATE_OVERLAY_UPGRADING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {}
+
     /**
      * An internal state used as the initial state of an overlay. OverlayInfo
      * objects exposed outside the {@link
@@ -61,6 +78,18 @@
     public static final int STATE_ENABLED = 3;
 
     /**
+     * The target package is currently being upgraded; the state will change
+     * once the package installation has finished.
+     */
+    public static final int STATE_TARGET_UPGRADING = 4;
+
+    /**
+     * The overlay package is currently being upgraded; the state will change
+     * once the package installation has finished.
+     */
+    public static final int STATE_OVERLAY_UPGRADING = 5;
+
+    /**
      * Package name of the overlay package
      */
     public final String packageName;
@@ -77,13 +106,8 @@
 
     /**
      * The state of this OverlayInfo as defined by the STATE_* constants in this class.
-     *
-     * @see #STATE_MISSING_TARGET
-     * @see #STATE_NO_IDMAP
-     * @see #STATE_DISABLED
-     * @see #STATE_ENABLED
      */
-    public final int state;
+    public final @State int state;
 
     /**
      * User handle for which this overlay applies
@@ -96,13 +120,13 @@
      * @param source the source OverlayInfo to base the new instance on
      * @param state the new state for the source OverlayInfo
      */
-    public OverlayInfo(@NonNull OverlayInfo source, int state) {
+    public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
         this(source.packageName, source.targetPackageName, source.baseCodePath, state,
                 source.userId);
     }
 
     public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
-            @NonNull String baseCodePath, int state, int userId) {
+            @NonNull String baseCodePath, @State int state, int userId) {
         this.packageName = packageName;
         this.targetPackageName = targetPackageName;
         this.baseCodePath = baseCodePath;
@@ -136,6 +160,8 @@
             case STATE_NO_IDMAP:
             case STATE_DISABLED:
             case STATE_ENABLED:
+            case STATE_TARGET_UPGRADING:
+            case STATE_OVERLAY_UPGRADING:
                 break;
             default:
                 throw new IllegalArgumentException("State " + state + " is not a valid state");
@@ -156,7 +182,8 @@
         dest.writeInt(userId);
     }
 
-    public static final Parcelable.Creator<OverlayInfo> CREATOR = new Parcelable.Creator<OverlayInfo>() {
+    public static final Parcelable.Creator<OverlayInfo> CREATOR =
+            new Parcelable.Creator<OverlayInfo>() {
         @Override
         public OverlayInfo createFromParcel(Parcel source) {
             return new OverlayInfo(source);
@@ -189,14 +216,9 @@
      * Translate a state to a human readable string. Only intended for
      * debugging purposes.
      *
-     * @see #STATE_MISSING_TARGET
-     * @see #STATE_NO_IDMAP
-     * @see #STATE_DISABLED
-     * @see #STATE_ENABLED
-     *
      * @return a human readable String representing the state.
      */
-    public static String stateToString(int state) {
+    public static String stateToString(@State int state) {
         switch (state) {
             case STATE_UNKNOWN:
                 return "STATE_UNKNOWN";
@@ -208,6 +230,10 @@
                 return "STATE_DISABLED";
             case STATE_ENABLED:
                 return "STATE_ENABLED";
+            case STATE_TARGET_UPGRADING:
+                return "STATE_TARGET_UPGRADING";
+            case STATE_OVERLAY_UPGRADING:
+                return "STATE_OVERLAY_UPGRADING";
             default:
                 return "<unknown state>";
         }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b61a6d9..1adc9f5 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1601,7 +1601,7 @@
      * @hide
      */
     public boolean isAllowedToUseHiddenApi() {
-        return false;
+        return isSystemApp() || isUpdatedSystemApp();
     }
 
     /**
diff --git a/core/java/android/content/pm/InstantAppRequest.java b/core/java/android/content/pm/InstantAppRequest.java
index 38f0225..361d4e4 100644
--- a/core/java/android/content/pm/InstantAppRequest.java
+++ b/core/java/android/content/pm/InstantAppRequest.java
@@ -18,12 +18,14 @@
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.text.TextUtils;
 
 /**
  * Information needed to make an instant application resolution request.
  * @hide
  */
 public final class InstantAppRequest {
+
     /** Response from the first phase of instant application resolution */
     public final AuxiliaryResolveInfo responseObj;
     /** The original intent that triggered instant application resolution */
@@ -40,6 +42,8 @@
     public final Bundle verificationBundle;
     /** Whether resolution occurs because an application is starting */
     public final boolean resolveForStart;
+    /** The instant app digest for this request */
+    public final InstantAppResolveInfo.InstantAppDigest digest;
 
     public InstantAppRequest(AuxiliaryResolveInfo responseObj, Intent origIntent,
             String resolvedType, String callingPackage, int userId, Bundle verificationBundle,
@@ -51,5 +55,11 @@
         this.userId = userId;
         this.verificationBundle = verificationBundle;
         this.resolveForStart = resolveForStart;
+        if (origIntent.getData() != null && !TextUtils.isEmpty(origIntent.getData().getHost())) {
+            digest = new InstantAppResolveInfo.InstantAppDigest(
+                    origIntent.getData().getHost(), 5 /*maxDigests*/);
+        } else {
+            digest = InstantAppResolveInfo.InstantAppDigest.UNDEFINED;
+        }
     }
 }
diff --git a/core/java/android/content/pm/InstantAppResolveInfo.java b/core/java/android/content/pm/InstantAppResolveInfo.java
index 112c5da..3a95a5f 100644
--- a/core/java/android/content/pm/InstantAppResolveInfo.java
+++ b/core/java/android/content/pm/InstantAppResolveInfo.java
@@ -26,10 +26,13 @@
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Random;
 
 /**
  * Describes an externally resolvable instant application. There are three states that this class
@@ -227,14 +230,25 @@
      */
     @SystemApi
     public static final class InstantAppDigest implements Parcelable {
-        private static final int DIGEST_MASK = 0xfffff000;
-
+        static final int DIGEST_MASK = 0xfffff000;
         public static final InstantAppDigest UNDEFINED =
                 new InstantAppDigest(new byte[][]{}, new int[]{});
+
+        private static Random sRandom = null;
+        static {
+            try {
+                sRandom = SecureRandom.getInstance("SHA1PRNG");
+            } catch (NoSuchAlgorithmException e) {
+                // oh well
+                sRandom = new Random();
+            }
+        }
         /** Full digest of the domain hashes */
         private final byte[][] mDigestBytes;
-        /** The first 4 bytes of the domain hashes */
+        /** The first 5 bytes of the domain hashes */
         private final int[] mDigestPrefix;
+        /** The first 5 bytes of the domain hashes interspersed with random data */
+        private int[] mDigestPrefixSecure;
 
         public InstantAppDigest(@NonNull String hostName) {
             this(hostName, -1 /*maxDigests*/);
@@ -306,6 +320,7 @@
                 }
             }
             mDigestPrefix = in.createIntArray();
+            mDigestPrefixSecure = in.createIntArray();
         }
 
         public byte[][] getDigestBytes() {
@@ -316,6 +331,26 @@
             return mDigestPrefix;
         }
 
+        /**
+         * Returns a digest prefix with additional random prefixes interspersed.
+         * @hide
+         */
+        public int[] getDigestPrefixSecure() {
+            if (this == InstantAppResolveInfo.InstantAppDigest.UNDEFINED) {
+                return getDigestPrefix();
+            } else if (mDigestPrefixSecure == null) {
+                // let's generate some random data to intersperse throughout the set of prefixes
+                final int realSize = getDigestPrefix().length;
+                final int manufacturedSize = realSize + 10 + sRandom.nextInt(10);
+                mDigestPrefixSecure = Arrays.copyOf(getDigestPrefix(), manufacturedSize);
+                for (int i = realSize; i < manufacturedSize; i++) {
+                    mDigestPrefixSecure[i] = sRandom.nextInt() & DIGEST_MASK;
+                }
+                Arrays.sort(mDigestPrefixSecure);
+            }
+            return mDigestPrefixSecure;
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -323,6 +358,11 @@
 
         @Override
         public void writeToParcel(Parcel out, int flags) {
+            final boolean isUndefined = this == UNDEFINED;
+            out.writeBoolean(isUndefined);
+            if (isUndefined) {
+                return;
+            }
             if (mDigestBytes == null) {
                 out.writeInt(-1);
             } else {
@@ -332,6 +372,7 @@
                 }
             }
             out.writeIntArray(mDigestPrefix);
+            out.writeIntArray(mDigestPrefixSecure);
         }
 
         @SuppressWarnings("hiding")
@@ -339,6 +380,9 @@
                 new Parcelable.Creator<InstantAppDigest>() {
             @Override
             public InstantAppDigest createFromParcel(Parcel in) {
+                if (in.readBoolean() /* is undefined */) {
+                    return UNDEFINED;
+                }
                 return new InstantAppDigest(in);
             }
             @Override
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 09a46b8..0342c93 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -468,6 +468,18 @@
         dest.writeBoolean(mOverlayIsStatic);
         dest.writeInt(compileSdkVersion);
         dest.writeString(compileSdkVersionCodename);
+        writeSigningCertificateHistoryToParcel(dest, parcelableFlags);
+    }
+
+    private void writeSigningCertificateHistoryToParcel(Parcel dest, int parcelableFlags) {
+        if (signingCertificateHistory != null) {
+            dest.writeInt(signingCertificateHistory.length);
+            for (int i = 0; i < signingCertificateHistory.length; i++) {
+                dest.writeTypedArray(signingCertificateHistory[i], parcelableFlags);
+            }
+        } else {
+            dest.writeInt(-1);
+        }
     }
 
     public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -523,6 +535,7 @@
         mOverlayIsStatic = source.readBoolean();
         compileSdkVersion = source.readInt();
         compileSdkVersionCodename = source.readString();
+        readSigningCertificateHistoryFromParcel(source);
 
         // The component lists were flattened with the redundant ApplicationInfo
         // instances omitted.  Distribute the canonical one here as appropriate.
@@ -534,6 +547,16 @@
         }
     }
 
+    private void readSigningCertificateHistoryFromParcel(Parcel source) {
+        int len = source.readInt();
+        if (len != -1) {
+            signingCertificateHistory = new Signature[len][];
+            for (int i = 0; i < len; i++) {
+                signingCertificateHistory[i] = source.createTypedArray(Signature.CREATOR);
+            }
+        }
+    }
+
     private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) {
         if (components != null) {
             for (ComponentInfo ci : components) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4e5f835..486c86c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -441,6 +441,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int MATCH_FACTORY_ONLY = 0x00200000;
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2da8937..dda4167 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -196,10 +196,6 @@
     private static final String TAG_RESTRICT_UPDATE = "restrict-update";
     private static final String TAG_USES_SPLIT = "uses-split";
 
-    // [b/36551762] STOPSHIP remove the ability to expose components via meta-data
-    // Temporary workaround; allow meta-data to expose components to instant apps
-    private static final String META_DATA_INSTANT_APPS = "instantapps.clients.allowed";
-
     private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
 
     /**
@@ -4430,24 +4426,6 @@
                         outError)) == null) {
                     return null;
                 }
-                // we don't have an attribute [or it's false], but, we have meta-data
-                if (!visibleToEphemeral && a.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
-                    visibleToEphemeral = true; // set in case there are more intent filters
-                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                    a.info.flags &= ~ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
-                    owner.visibleToInstantApps = true;
-                    // cycle through any filters already seen
-                    for (int i = a.intents.size() - 1; i >= 0; --i) {
-                        a.intents.get(i)
-                                .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
-                    }
-                    if (owner.preferredActivityFilters != null) {
-                        for (int i = owner.preferredActivityFilters.size() - 1; i >= 0; --i) {
-                            owner.preferredActivityFilters.get(i)
-                                    .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
-                        }
-                    }
-                }
             } else if (!receiver && parser.getName().equals("layout")) {
                 parseLayout(res, parser, a);
             } else {
@@ -4942,7 +4920,7 @@
         p.info.authority = cpname.intern();
 
         if (!parseProviderTags(
-                res, parser, visibleToEphemeral, owner, p, outError)) {
+                res, parser, visibleToEphemeral, p, outError)) {
             return null;
         }
 
@@ -4950,7 +4928,7 @@
     }
 
     private boolean parseProviderTags(Resources res, XmlResourceParser parser,
-            boolean visibleToEphemeral, Package owner, Provider outInfo, String[] outError)
+            boolean visibleToEphemeral, Provider outInfo, String[] outError)
                     throws XmlPullParserException, IOException {
         int outerDepth = parser.getDepth();
         int type;
@@ -4978,17 +4956,6 @@
                         outInfo.metaData, outError)) == null) {
                     return false;
                 }
-                // we don't have an attribute [or it's false], but, we have meta-data
-                if (!visibleToEphemeral && outInfo.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
-                    visibleToEphemeral = true; // set in case there are more intent filters
-                    outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                    owner.visibleToInstantApps = true;
-                    // cycle through any filters already seen
-                    for (int i = outInfo.intents.size() - 1; i >= 0; --i) {
-                        outInfo.intents.get(i)
-                                .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
-                    }
-                }
 
             } else if (parser.getName().equals("grant-uri-permission")) {
                 TypedArray sa = res.obtainAttributes(parser,
@@ -5277,17 +5244,6 @@
                         outError)) == null) {
                     return null;
                 }
-                // we don't have an attribute [or it's false], but, we have meta-data
-                if (!visibleToEphemeral && s.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
-                    visibleToEphemeral = true; // set in case there are more intent filters
-                    s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
-                    owner.visibleToInstantApps = true;
-                    // cycle through any filters already seen
-                    for (int i = s.intents.size() - 1; i >= 0; --i) {
-                        s.intents.get(i)
-                                .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
-                    }
-                }
             } else {
                 if (!RIGID_PARSER) {
                     Slog.w(TAG, "Unknown element under <service>: "
@@ -6738,31 +6694,6 @@
                 + " " + packageName + "}";
         }
 
-        public String dumpState_temp() {
-            String flags = "";
-            flags += ((applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ? "U" : "");
-            flags += ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ? "S" : "");
-            if ("".equals(flags)) {
-                flags = "-";
-            }
-            String privFlags = "";
-            privFlags += ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0 ? "P" : "");
-            privFlags += ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0 ? "O" : "");
-            privFlags += ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0 ? "V" : "");
-            if ("".equals(privFlags)) {
-                privFlags = "-";
-            }
-            return "Package{"
-            + Integer.toHexString(System.identityHashCode(this))
-            + " " + packageName
-            + ", ver:" + getLongVersionCode()
-            + ", path: " + codePath
-            + ", flags: " + flags
-            + ", privFlags: " + privFlags
-            + ", extra: " + (mExtras == null ? "<<NULL>>" : Integer.toHexString(System.identityHashCode(mExtras)) + "}")
-            + "}";
-        }
-
         @Override
         public int describeContents() {
             return 0;
diff --git a/core/java/android/content/pm/VerifierDeviceIdentity.java b/core/java/android/content/pm/VerifierDeviceIdentity.java
index a8cdb6a..90be6f31 100644
--- a/core/java/android/content/pm/VerifierDeviceIdentity.java
+++ b/core/java/android/content/pm/VerifierDeviceIdentity.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.UnsupportedEncodingException;
 import java.security.SecureRandom;
 import java.util.Random;
@@ -86,6 +88,7 @@
      * @return verifier device identity based on the input from the provided
      *         random number generator
      */
+    @VisibleForTesting
     static VerifierDeviceIdentity generate(Random rng) {
         long identity = rng.nextLong();
         return new VerifierDeviceIdentity(identity);
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
index 02d0a6d..79bc9a3 100644
--- a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
+++ b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
@@ -274,6 +274,7 @@
             }
         }
 
+        @GuardedBy("mLock")
         private void scheduleNextMessageIfNeededLocked() {
             if (mBound && mRemoteInstance != null && !mPendingWork.isEmpty()) {
                 Message nextMessage = mPendingWork.remove(0);
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 7866560..5f8a34d 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -28,6 +28,8 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -915,6 +917,7 @@
     private native final void init(boolean isSystem);
     private native final void destroy();
 
+    @GuardedBy("this")
     private final void incRefsLocked(long id) {
         if (DEBUG_REFS) {
             if (mRefStacks == null) {
@@ -926,7 +929,8 @@
         }
         mNumRefs++;
     }
-    
+
+    @GuardedBy("this")
     private final void decRefsLocked(long id) {
         if (DEBUG_REFS && mRefStacks != null) {
             mRefStacks.remove(id);
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index e173653c..ad85e71 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -867,8 +867,9 @@
      * @param theme The theme used to style the drawable attributes, may be {@code null}.
      * @return Drawable An object that can be used to draw this resource.
      * @throws NotFoundException Throws NotFoundException if the given ID does
-     *             not exist.
+     *             not exist, or cannot be decoded.
      */
+    @NonNull
     public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
         final TypedValue value = obtainTempTypedValue();
         try {
@@ -980,7 +981,7 @@
      *         or multiple colors that can be selected based on a state.
      * @deprecated Use {@link #getColorStateList(int, Theme)} instead.
      */
-    @Nullable
+    @NonNull
     @Deprecated
     public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException {
         final ColorStateList csl = getColorStateList(id, null);
@@ -1011,7 +1012,7 @@
      * @return A themed ColorStateList object containing either a single solid
      *         color or multiple colors that can be selected based on a state.
      */
-    @Nullable
+    @NonNull
     public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
             throws NotFoundException {
         final TypedValue value = obtainTempTypedValue();
@@ -1024,7 +1025,7 @@
         }
     }
 
-    @Nullable
+    @NonNull
     ColorStateList loadColorStateList(@NonNull TypedValue value, int id, @Nullable Theme theme)
             throws NotFoundException {
         return mResourcesImpl.loadColorStateList(this, value, id, theme);
@@ -1033,7 +1034,7 @@
     /**
      * @hide
      */
-    @Nullable
+    @NonNull
     public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) {
         return mResourcesImpl.loadComplexColor(this, value, id, theme);
     }
@@ -1139,6 +1140,7 @@
      *         
      * @see #getXml
      */
+    @NonNull
     public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException {
         return loadXmlResourceParser(id, "layout");
     }
@@ -1163,6 +1165,7 @@
      *         
      * @see #getXml
      */
+    @NonNull
     public XmlResourceParser getAnimation(@AnimatorRes @AnimRes int id) throws NotFoundException {
         return loadXmlResourceParser(id, "anim");
     }
@@ -1188,6 +1191,7 @@
      *         
      * @see android.util.AttributeSet
      */
+    @NonNull
     public XmlResourceParser getXml(@XmlRes int id) throws NotFoundException {
         return loadXmlResourceParser(id, "xml");
     }
@@ -1203,8 +1207,8 @@
      * @return InputStream Access to the resource data.
      *
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
-     * 
      */
+    @NonNull
     public InputStream openRawResource(@RawRes int id) throws NotFoundException {
         final TypedValue value = obtainTempTypedValue();
         try {
@@ -1261,6 +1265,7 @@
      *
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      */
+    @NonNull
     public InputStream openRawResource(@RawRes int id, TypedValue value)
             throws NotFoundException {
         return mResourcesImpl.openRawResource(id, value);
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 97cb78b..cf01451 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -543,7 +543,7 @@
         }
     }
 
-    @Nullable
+    @NonNull
     Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id,
             int density, @Nullable Resources.Theme theme)
             throws NotFoundException {
@@ -627,7 +627,7 @@
             } else if (isColorDrawable) {
                 dr = new ColorDrawable(value.data);
             } else {
-                dr = loadDrawableForCookie(wrapper, value, id, density, null);
+                dr = loadDrawableForCookie(wrapper, value, id, density);
             }
             // DrawableContainer' constant state has drawables instances. In order to leave the
             // constant state intact in the cache, we need to create a new DrawableContainer after
@@ -754,8 +754,9 @@
     /**
      * Loads a drawable from XML or resources stream.
      */
+    @NonNull
     private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value,
-            int id, int density, @Nullable Resources.Theme theme) {
+            int id, int density) {
         if (value.string == null) {
             throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
                     + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
@@ -774,22 +775,23 @@
             }
         }
 
-        // For prelaod tracing.
+        // For preload tracing.
         long startTime = 0;
         int startBitmapCount = 0;
         long startBitmapSize = 0;
-        int startDrwableCount = 0;
+        int startDrawableCount = 0;
         if (TRACE_FOR_DETAILED_PRELOAD) {
             startTime = System.nanoTime();
             startBitmapCount = Bitmap.sPreloadTracingNumInstantiatedBitmaps;
             startBitmapSize = Bitmap.sPreloadTracingTotalBitmapsSize;
-            startDrwableCount = sPreloadTracingNumLoadedDrawables;
+            startDrawableCount = sPreloadTracingNumLoadedDrawables;
         }
 
         if (DEBUG_LOAD) {
             Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
         }
 
+
         final Drawable dr;
 
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
@@ -804,7 +806,7 @@
                 if (file.endsWith(".xml")) {
                     final XmlResourceParser rp = loadXmlResourceParser(
                             file, id, value.assetCookie, "drawable");
-                    dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
+                    dr = Drawable.createFromXmlForDensity(wrapper, rp, density, null);
                     rp.close();
                 } else {
                     final InputStream is = mAssets.openNonAsset(
@@ -834,7 +836,7 @@
                     final long loadedBitmapSize =
                             Bitmap.sPreloadTracingTotalBitmapsSize - startBitmapSize;
                     final int loadedDrawables =
-                            sPreloadTracingNumLoadedDrawables - startDrwableCount;
+                            sPreloadTracingNumLoadedDrawables - startDrawableCount;
 
                     sPreloadTracingNumLoadedDrawables++;
 
@@ -910,6 +912,7 @@
      * first try to load CSL from the cache. If not found, try to get from the constant state.
      * Last, parse the XML and generate the CSL.
      */
+    @Nullable
     private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
             TypedValue value, int id) {
         final long key = (((long) value.assetCookie) << 32) | value.data;
@@ -985,7 +988,7 @@
         return complexColor;
     }
 
-    @Nullable
+    @NonNull
     ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
             Resources.Theme theme)
             throws NotFoundException {
@@ -1043,9 +1046,10 @@
      * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
      * and selector tag.
      *
-     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
+     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content, or
+     *     {@code null} if the XML file is neither.
      */
-    @Nullable
+    @NonNull
     private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
             Resources.Theme theme) {
         if (value.string == null) {
diff --git a/core/java/android/content/res/XmlResourceParser.java b/core/java/android/content/res/XmlResourceParser.java
index 6be9b9e..86f4ba6 100644
--- a/core/java/android/content/res/XmlResourceParser.java
+++ b/core/java/android/content/res/XmlResourceParser.java
@@ -27,6 +27,8 @@
  * it is done reading the resource.
  */
 public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable {
+    String getAttributeNamespace (int index);
+
     /**
      * Close this parser. Calls on the interface are no longer valid after this call.
      */
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index b211700..dc60612 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -422,6 +422,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private boolean recycleConnectionLocked(SQLiteConnection connection,
             AcquiredConnectionStatus status) {
         if (status == AcquiredConnectionStatus.RECONFIGURE) {
@@ -531,6 +532,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void closeAvailableConnectionsAndLogExceptionsLocked() {
         closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked();
 
@@ -541,6 +543,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private boolean closeAvailableConnectionLocked(int connectionId) {
         final int count = mAvailableNonPrimaryConnections.size();
         for (int i = count - 1; i >= 0; i--) {
@@ -562,6 +565,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked() {
         final int count = mAvailableNonPrimaryConnections.size();
         for (int i = 0; i < count; i++) {
@@ -581,6 +585,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void closeExcessConnectionsAndLogExceptionsLocked() {
         int availableCount = mAvailableNonPrimaryConnections.size();
         while (availableCount-- > mMaxConnectionPoolSize - 1) {
@@ -591,6 +596,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void closeConnectionAndLogExceptionsLocked(SQLiteConnection connection) {
         try {
             connection.close(); // might throw
@@ -609,6 +615,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void reconfigureAllConnectionsLocked() {
         if (mAvailablePrimaryConnection != null) {
             try {
@@ -776,6 +783,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void cancelConnectionWaiterLocked(ConnectionWaiter waiter) {
         if (waiter.mAssignedConnection != null || waiter.mException != null) {
             // Waiter is done waiting but has not woken up yet.
@@ -848,6 +856,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void wakeConnectionWaitersLocked() {
         // Unpark all waiters that have requests that we can fulfill.
         // This method is designed to not throw runtime exceptions, although we might send
@@ -910,6 +919,7 @@
     }
 
     // Might throw.
+    @GuardedBy("mLock")
     private SQLiteConnection tryAcquirePrimaryConnectionLocked(int connectionFlags) {
         // If the primary connection is available, acquire it now.
         SQLiteConnection connection = mAvailablePrimaryConnection;
@@ -935,6 +945,7 @@
     }
 
     // Might throw.
+    @GuardedBy("mLock")
     private SQLiteConnection tryAcquireNonPrimaryConnectionLocked(
             String sql, int connectionFlags) {
         // Try to acquire the next connection in the queue.
@@ -974,6 +985,7 @@
     }
 
     // Might throw.
+    @GuardedBy("mLock")
     private void finishAcquireConnectionLocked(SQLiteConnection connection, int connectionFlags) {
         try {
             final boolean readOnly = (connectionFlags & CONNECTION_FLAG_READ_ONLY) != 0;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index c1c0812..ae1f57d 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -2006,7 +2006,6 @@
      *     SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
      *             SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING,
      *             myDatabaseErrorHandler);
-     *     db.enableWriteAheadLogging();
      * </pre></code>
      * </p><p>
      * Another way to enable write-ahead logging is to call {@link #enableWriteAheadLogging}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 40ee834..df64401 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -923,6 +923,14 @@
      * {@link CameraCaptureSession#setRepeatingRequest} or
      * {@link CameraCaptureSession#setRepeatingBurst}</p>
      *
+     * <p>Individual physical camera settings will only be honored for camera session
+     * that was initialiazed with corresponding physical camera id output configuration
+     * {@link OutputConfiguration#setPhysicalCameraId} and the same output targets are
+     * also attached in the request by {@link CaptureRequest.Builder#addTarget}.</p>
+     *
+     * <p>The output is undefined for any logical camera streams in case valid physical camera
+     * settings are attached.</p>
+     *
      * @param templateType An enumeration selecting the use case for this request. Not all template
      * types are supported on every device. See the documentation for each template type for
      * details.
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index bae2d04..0be45a0 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -17,7 +17,6 @@
 package android.hardware.camera2;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
@@ -26,6 +25,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * <p>The total assembled results of a single image capture from the image sensor.</p>
@@ -49,9 +49,9 @@
  *
  * <p>For a logical multi-camera device, if the CaptureRequest contains a surface for an underlying
  * physical camera, the corresponding {@link TotalCaptureResult} object will include the metadata
- * for that physical camera. And its keys and values can be accessed by
- * {@link #getPhysicalCameraKey}. If all requested surfaces are for the logical camera, no
- * metadata for physical camera will be included.</p>
+ * for that physical camera. And the mapping between the physical camera id and result metadata
+ * can be accessed via {@link #getPhysicalCameraResults}. If all requested surfaces are for the
+ * logical camera, no metadata for physical camera will be included.</p>
  *
  * <p>{@link TotalCaptureResult} objects are immutable.</p>
  *
@@ -62,7 +62,7 @@
     private final List<CaptureResult> mPartialResults;
     private final int mSessionId;
     // The map between physical camera id and capture result
-    private final HashMap<String, CameraMetadataNative> mPhysicalCaptureResults;
+    private final HashMap<String, CaptureResult> mPhysicalCaptureResults;
 
     /**
      * Takes ownership of the passed-in camera metadata and the partial results
@@ -83,10 +83,12 @@
 
         mSessionId = sessionId;
 
-        mPhysicalCaptureResults = new HashMap<String, CameraMetadataNative>();
+        mPhysicalCaptureResults = new HashMap<String, CaptureResult>();
         for (PhysicalCaptureResultInfo onePhysicalResult : physicalResults) {
+            CaptureResult physicalResult = new CaptureResult(
+                    onePhysicalResult.getCameraMetadata(), parent, extras);
             mPhysicalCaptureResults.put(onePhysicalResult.getCameraId(),
-                    onePhysicalResult.getCameraMetadata());
+                    physicalResult);
         }
     }
 
@@ -101,7 +103,7 @@
 
         mPartialResults = new ArrayList<>();
         mSessionId = CameraCaptureSession.SESSION_ID_NONE;
-        mPhysicalCaptureResults = new HashMap<String, CameraMetadataNative>();
+        mPhysicalCaptureResults = new HashMap<String, CaptureResult>();
     }
 
     /**
@@ -132,36 +134,20 @@
     }
 
     /**
-     * Get a capture result field value for a particular physical camera id.
+     * Get the map between physical camera ids and their capture result metadata
      *
-     * <p>The field definitions can be found in {@link CaptureResult}.</p>
-     *
-     * <p>This function can be called for logical camera devices, which are devices that have
+     * <p>This function can be called for logical multi-camera devices, which are devices that have
      * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability and calls to {@link
      * CameraCharacteristics#getPhysicalCameraIds} return a non-empty list of physical devices that
-     * are backing the logical camera. The camera id included in physicalCameraId argument
-     * selects an individual physical device, and returns its specific capture result field.</p>
+     * are backing the logical camera.</p>
      *
-     * <p>This function should only be called if one or more streams from the underlying
-     * 'physicalCameraId' was requested by the corresponding capture request.</p>
-     *
-     * @throws IllegalArgumentException if the key was not valid, or the physicalCameraId is not
-     * applicable to the current camera, or a stream from 'physicalCameraId' is not requested by the
-     * corresponding capture request.
-     *
-     * @param key The result field to read.
-     * @param physicalCameraId The physical camera the result originates from.
-     *
-     * @return The value of that key, or {@code null} if the field is not set.
-     */
-    @Nullable
-    public <T> T getPhysicalCameraKey(Key<T> key, @NonNull String physicalCameraId) {
-        if (!mPhysicalCaptureResults.containsKey(physicalCameraId)) {
-            throw new IllegalArgumentException(
-                    "No TotalCaptureResult exists for physical camera " + physicalCameraId);
-        }
+     * <p>If one or more streams from the underlying physical cameras were requested by the
+     * corresponding capture request, this function returns the result metadata for those physical
+     * cameras. Otherwise, an empty map is returned.</p>
 
-        CameraMetadataNative physicalMetadata = mPhysicalCaptureResults.get(physicalCameraId);
-        return physicalMetadata.get(key);
+     * @return unmodifiable map between physical camera ids and their capture result metadata
+     */
+    public Map<String, CaptureResult> getPhysicalCameraResults() {
+        return Collections.unmodifiableMap(mPhysicalCaptureResults);
     }
 }
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index eb4bced..b205e2c 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -368,7 +368,7 @@
      * desirable for the camera application to request streams from individual physical cameras.
      * This call achieves it by mapping the OutputConfiguration to the physical camera id.</p>
      *
-     * <p>The valid physical camera id can be queried by {@link
+     * <p>The valid physical camera ids can be queried by {@link
      * android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds}.
      * </p>
      *
diff --git a/core/java/android/hardware/display/AmbientBrightnessDayStats.java b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
index 00f3c36..1aa2557 100644
--- a/core/java/android/hardware/display/AmbientBrightnessDayStats.java
+++ b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
@@ -47,6 +47,11 @@
     private final float[] mStats;
 
     /**
+     * Initialize day stats from the given state. The time spent in each of the bucket is
+     * initialized to 0.
+     *
+     * @param localDate        The date for which stats are being tracked
+     * @param bucketBoundaries Bucket boundaries used from creating the buckets from
      * @hide
      */
     public AmbientBrightnessDayStats(@NonNull LocalDate localDate,
@@ -55,6 +60,11 @@
     }
 
     /**
+     * Initialize day stats from the given state
+     *
+     * @param localDate        The date for which stats are being tracked
+     * @param bucketBoundaries Bucket boundaries used from creating the buckets from
+     * @param stats            Time spent in each of the buckets (in seconds)
      * @hide
      */
     public AmbientBrightnessDayStats(@NonNull LocalDate localDate,
@@ -81,14 +91,26 @@
         mStats = stats;
     }
 
+    /**
+     * @return The {@link LocalDate} for which brightness stats are being tracked.
+     */
     public LocalDate getLocalDate() {
         return mLocalDate;
     }
 
+    /**
+     * @return Aggregated stats of time spent (in seconds) in various buckets.
+     */
     public float[] getStats() {
         return mStats;
     }
 
+    /**
+     * Returns the bucket boundaries (in lux) used for creating buckets. For eg., if the bucket
+     * boundaries array is {b1, b2, b3}, the buckets will be [b1, b2), [b2, b3), [b3, inf).
+     *
+     * @return The list of bucket boundaries.
+     */
     public float[] getBucketBoundaries() {
         return mBucketBoundaries;
     }
@@ -169,7 +191,14 @@
         dest.writeFloatArray(mStats);
     }
 
-    /** @hide */
+    /**
+     * Updates the stats by incrementing the time spent for the appropriate bucket based on ambient
+     * brightness reading.
+     *
+     * @param ambientBrightness Ambient brightness reading (in lux)
+     * @param durationSec       Time spent with the given reading (in seconds)
+     * @hide
+     */
     public void log(float ambientBrightness, float durationSec) {
         int bucketIndex = getBucketIndex(ambientBrightness);
         if (bucketIndex >= 0) {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index a817f33..017674f 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1818,9 +1818,9 @@
     }
 
     /**
-     * Called when the input method window has been shown to the user, after
-     * previously not being visible.  This is done after all of the UI setup
-     * for the window has occurred (creating its views etc).
+     * Called immediately before the input method window is shown to the user.
+     * You could override this to prepare for the window to be shown
+     * (update view structure etc).
      */
     public void onWindowShown() {
         // Intentionally empty
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 24a078f..b609847 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -19,6 +19,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -761,6 +762,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
             @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
             throws ResourceUnavailableException, IOException {
@@ -780,6 +782,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction,
             IpSecTransform transform) throws IOException {
         try {
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 0829b4a..38759a9 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -21,6 +21,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.Binder;
@@ -266,6 +267,10 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
+    })
     public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback,
             int intervalSeconds, @NonNull Handler handler) throws IOException {
         checkNotNull(userCallback);
@@ -305,6 +310,10 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
+    })
     public void stopNattKeepalive() {
         synchronized (mKeepaliveCallback) {
             if (mKeepalive == null) {
@@ -449,6 +458,7 @@
          * @hide
          */
         @SystemApi
+        @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
         public IpSecTransform buildTunnelModeTransform(
                 @NonNull InetAddress sourceAddress,
                 @NonNull IpSecManager.SecurityParameterIndex spi)
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 287bdc8..74d6470 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -26,6 +26,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.security.SecureRandom;
 import java.util.Arrays;
 import java.util.Random;
 
@@ -329,16 +330,34 @@
 
     /**
      * Returns a generated MAC address whose 24 least significant bits constituting the
-     * NIC part of the address are randomly selected.
+     * NIC part of the address are randomly selected and has Google OUI base.
      *
      * The locally assigned bit is always set to 1. The multicast bit is always set to 0.
      *
-     * @return a random locally assigned MacAddress.
+     * @return a random locally assigned, unicast MacAddress with Google OUI.
+     *
+     * @hide
+     */
+    public static @NonNull MacAddress createRandomUnicastAddressWithGoogleBase() {
+        return createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom());
+    }
+
+    /**
+     * Returns a generated MAC address whose 46 bits, excluding the locally assigned bit and the
+     * unicast bit, are randomly selected.
+     *
+     * The locally assigned bit is always set to 1. The multicast bit is always set to 0.
+     *
+     * @return a random locally assigned, unicast MacAddress.
      *
      * @hide
      */
     public static @NonNull MacAddress createRandomUnicastAddress() {
-        return createRandomUnicastAddress(BASE_GOOGLE_MAC, new Random());
+        SecureRandom r = new SecureRandom();
+        long addr = r.nextLong() & VALID_LONG_MASK;
+        addr |= LOCALLY_ASSIGNED_MASK;
+        addr &= ~MULTICAST_MASK;
+        return new MacAddress(addr);
     }
 
     /**
@@ -355,8 +374,8 @@
      */
     public static @NonNull MacAddress createRandomUnicastAddress(MacAddress base, Random r) {
         long addr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong());
-        addr = addr | LOCALLY_ASSIGNED_MASK;
-        addr = addr & ~MULTICAST_MASK;
+        addr |= LOCALLY_ASSIGNED_MASK;
+        addr &= ~MULTICAST_MASK;
         return new MacAddress(addr);
     }
 
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index a734719..8b4f02e 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -323,4 +323,16 @@
     public long getLongProperty(int id) {
         return queryProperty(id);
     }
+
+    /**
+     * Return true if the plugType given is wired
+     * @param plugType {@link #BATTERY_PLUGGED_AC}, {@link #BATTERY_PLUGGED_USB},
+     *        or {@link #BATTERY_PLUGGED_WIRELESS}
+     *
+     * @return true if plugType is wired
+     * @hide
+     */
+    public static boolean isPlugWired(int plugType) {
+        return plugType == BATTERY_PLUGGED_USB || plugType == BATTERY_PLUGGED_AC;
+    }
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fd0e5ae..5d7cf1e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1537,6 +1537,7 @@
         public static final int STATE2_BLUETOOTH_ON_FLAG = 1<<22;
         public static final int STATE2_CAMERA_FLAG = 1<<21;
         public static final int STATE2_BLUETOOTH_SCAN_FLAG = 1 << 20;
+        public static final int STATE2_CELLULAR_HIGH_TX_POWER_FLAG = 1 << 19;
 
         public static final int MOST_INTERESTING_STATES2 =
                 STATE2_POWER_SAVE_FLAG | STATE2_WIFI_ON_FLAG | STATE2_DEVICE_IDLE_MASK
@@ -2353,9 +2354,11 @@
                 WIFI_SUPPL_STATE_NAMES, WIFI_SUPPL_STATE_SHORT_NAMES),
         new BitDescription(HistoryItem.STATE2_CAMERA_FLAG, "camera", "ca"),
         new BitDescription(HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG, "ble_scan", "bles"),
+        new BitDescription(HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG,
+                "cellular_high_tx_power", "Chtp"),
         new BitDescription(HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK,
             HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT, "gps_signal_quality", "Gss",
-            new String[] { "poor", "good"}, new String[] { "poor", "good"}),
+            new String[] { "poor", "good"}, new String[] { "poor", "good"})
     };
 
     public static final String[] HISTORY_EVENT_NAMES = new String[] {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 4aadc5b..682fdb7 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -784,7 +784,7 @@
         private static final int MAIN_INDEX_SIZE = 1 <<  LOG_MAIN_INDEX_SIZE;
         private static final int MAIN_INDEX_MASK = MAIN_INDEX_SIZE - 1;
         // Debuggable builds will throw an AssertionError if the number of map entries exceeds:
-        private static final int CRASH_AT_SIZE = 5_000;
+        private static final int CRASH_AT_SIZE = 20_000;
 
         /**
          * We next warn when we exceed this bucket size.
diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java
index a565dee..fbdf27e 100644
--- a/core/java/android/os/IHwBinder.java
+++ b/core/java/android/os/IHwBinder.java
@@ -21,12 +21,6 @@
 /** @hide */
 @SystemApi
 public interface IHwBinder {
-    // These MUST match their corresponding libhwbinder/IBinder.h definition !!!
-    /** @hide */
-    public static final int FIRST_CALL_TRANSACTION = 1;
-    /** @hide */
-    public static final int FLAG_ONEWAY = 1;
-
     /**
      * Process a hwbinder transaction.
      *
diff --git a/core/java/android/os/IServiceManager.java b/core/java/android/os/IServiceManager.java
index 2176a78..89bf7b9 100644
--- a/core/java/android/os/IServiceManager.java
+++ b/core/java/android/os/IServiceManager.java
@@ -76,9 +76,15 @@
     int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
     int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
     int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
+    /**
+     * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
+     * same priority as NORMAL priority but the services are not called with dump priority
+     * arguments.
+     */
+    int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
     int DUMP_FLAG_PRIORITY_ALL = DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
-            | DUMP_FLAG_PRIORITY_NORMAL;
+            | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
     /* Allows services to dump sections in protobuf format. */
-    int DUMP_FLAG_PROTO = 1 << 3;
+    int DUMP_FLAG_PROTO = 1 << 4;
 
 }
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 8a27700..eae5217 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -55,9 +55,8 @@
     /** Pull the specified data. Results will be sent to statsd when complete. */
     StatsLogEventWrapper[] pullData(int pullCode);
 
-    /** Send a broadcast to the specified pkg and class that it should getData now. */
-    // TODO: Rename this and use a pending intent instead.
-    oneway void sendBroadcast(String pkg, String cls);
+    /** Send a broadcast to the specified PendingIntent's as IBinder that it should getData now. */
+    oneway void sendDataBroadcast(in IBinder intentSender);
 
     /**
      * Requests StatsCompanionService to send a broadcast using the given intentSender
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 679b49d..682a24f1 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -81,12 +81,26 @@
     /**
      * Sets a configuration with the specified config key and subscribes to updates for this
      * configuration key. Broadcasts will be sent if this configuration needs to be collected.
-     * The configuration must be a wire-encoded StatsdConfig. The caller specifies the name of the
-     * package and class that should receive these broadcasts.
+     * The configuration must be a wire-encoded StatsDConfig. The receiver for this data is
+     * registered in a separate function.
      *
      * Returns if this configuration was correctly registered.
      */
-    boolean addConfiguration(in long configKey, in byte[] config, in String pkg, in String cls);
+    boolean addConfiguration(in long configKey, in byte[] config);
+
+    /**
+     * Registers the given pending intent for this config key. This intent is invoked when the
+     * memory consumed by the metrics for this configuration approach the pre-defined limits. There
+     * can be at most one listener per config key.
+     *
+     * Returns if this listener was correctly registered.
+     */
+    boolean setDataFetchOperation(long configKey, in IBinder intentSender);
+
+    /**
+     * Removes the data fetch operation for the specified configuration.
+     */
+    boolean removeDataFetchOperation(long configKey);
 
     /**
      * Removes the configuration with the matching config key. No-op if this config key does not
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 42ec315..3be76d6 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -83,7 +83,7 @@
      * @param service the service object
      */
     public static void addService(String name, IBinder service) {
-        addService(name, service, false, IServiceManager.DUMP_FLAG_PRIORITY_NORMAL);
+        addService(name, service, false, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
     }
 
     /**
@@ -96,7 +96,7 @@
      * to access this service
      */
     public static void addService(String name, IBinder service, boolean allowIsolated) {
-        addService(name, service, allowIsolated, IServiceManager.DUMP_FLAG_PRIORITY_NORMAL);
+        addService(name, service, allowIsolated, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
     }
 
     /**
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index c6149be..24c9c91 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -271,4 +271,22 @@
             }
         }
     }
+
+    /**
+     * Verifies that a payload associated with the given payload metadata
+     * {@code payloadMetadataFilename} can be safely applied to ths device.
+     * Returns {@code true} if the update can successfully be applied and
+     * returns {@code false} otherwise.
+     *
+     * @param payloadMetadataFilename the location of the metadata without the
+     * {@code file://} prefix.
+     */
+    @SystemApi
+    public boolean verifyPayloadMetadata(String payloadMetadataFilename) {
+        try {
+            return mUpdateEngine.verifyPayloadApplicable(payloadMetadataFilename);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 2093cec..7e7af1a 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -943,6 +943,20 @@
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_SHARE_INTO_MANAGED_PROFILE = "no_sharing_into_profile";
+
+    /**
+     * Specifies whether the user is allowed to print.
+     *
+     * This restriction can be set by device or profile owner.
+     *
+     * The default value is {@code false}.
+     *
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_PRINTING = "no_printing";
+
     /**
      * Application restriction key that is used to indicate the pending arrival
      * of real restrictions for the app.
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index b6f16a7..e9b4853 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -16,10 +16,15 @@
 
 package android.os;
 
-import android.hardware.vibrator.V1_0.Constants.EffectStrength;
-import android.hardware.vibrator.V1_1.Constants.Effect_1_1;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.vibrator.V1_0.EffectStrength;
+import android.hardware.vibrator.V1_2.Effect;
+import android.net.Uri;
 import android.util.MathUtils;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.Arrays;
 
 /**
@@ -49,7 +54,7 @@
      * @see #get(int)
      * @hide
      */
-    public static final int EFFECT_CLICK = Effect_1_1.CLICK;
+    public static final int EFFECT_CLICK = Effect.CLICK;
 
     /**
      * A double click effect.
@@ -57,14 +62,62 @@
      * @see #get(int)
      * @hide
      */
-    public static final int EFFECT_DOUBLE_CLICK = Effect_1_1.DOUBLE_CLICK;
+    public static final int EFFECT_DOUBLE_CLICK = Effect.DOUBLE_CLICK;
 
     /**
      * A tick effect.
      * @see #get(int)
      * @hide
      */
-    public static final int EFFECT_TICK = Effect_1_1.TICK;
+    public static final int EFFECT_TICK = Effect.TICK;
+
+    /**
+     * A thud effect.
+     * @see #get(int)
+     * @hide
+     */
+    public static final int EFFECT_THUD = Effect.THUD;
+
+    /**
+     * A pop effect.
+     * @see #get(int)
+     * @hide
+     */
+    public static final int EFFECT_POP = Effect.POP;
+
+    /**
+     * A heavy click effect.
+     * @see #get(int)
+     * @hide
+     */
+    public static final int EFFECT_HEAVY_CLICK = Effect.HEAVY_CLICK;
+
+
+    /**
+     * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a
+     * pattern that can be played as a ringtone with any audio, depending on the device.
+     *
+     * @see #get(Uri, Context)
+     * @hide
+     */
+    @VisibleForTesting
+    public static final int[] RINGTONES = {
+        Effect.RINGTONE_1,
+        Effect.RINGTONE_2,
+        Effect.RINGTONE_3,
+        Effect.RINGTONE_4,
+        Effect.RINGTONE_5,
+        Effect.RINGTONE_6,
+        Effect.RINGTONE_7,
+        Effect.RINGTONE_8,
+        Effect.RINGTONE_9,
+        Effect.RINGTONE_10,
+        Effect.RINGTONE_11,
+        Effect.RINGTONE_12,
+        Effect.RINGTONE_13,
+        Effect.RINGTONE_14,
+        Effect.RINGTONE_15
+    };
 
     /** @hide to prevent subclassing from outside of the framework */
     public VibrationEffect() { }
@@ -198,6 +251,37 @@
         return effect;
     }
 
+    /**
+     * Get a predefined vibration effect associated with a given URI.
+     *
+     * Predefined effects are a set of common vibration effects that should be identical, regardless
+     * of the app they come from, in order to provide a cohesive experience for users across
+     * the entire device. They also may be custom tailored to the device hardware in order to
+     * provide a better experience than you could otherwise build using the generic building
+     * blocks.
+     *
+     * @param uri The URI associated with the haptic effect.
+     * @param context The context used to get the URI to haptic effect association.
+     *
+     * @return The desired effect, or {@code null} if there's no associated effect.
+     *
+     * @hide
+     */
+    @Nullable
+    public static VibrationEffect get(Uri uri, Context context) {
+        String[] uris = context.getResources().getStringArray(
+                com.android.internal.R.array.config_ringtoneEffectUris);
+        for (int i = 0; i < uris.length && i < RINGTONES.length; i++) {
+            if (uris[i] == null) {
+                continue;
+            }
+            if (Uri.parse(uris[i]).equals(uri)) {
+                return get(RINGTONES[i]);
+            }
+        }
+        return null;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -548,10 +632,15 @@
                 case EFFECT_CLICK:
                 case EFFECT_DOUBLE_CLICK:
                 case EFFECT_TICK:
+                case EFFECT_THUD:
+                case EFFECT_POP:
+                case EFFECT_HEAVY_CLICK:
                     break;
                 default:
-                    throw new IllegalArgumentException(
-                            "Unknown prebaked effect type (value=" + mEffectId + ")");
+                    if (mEffectId < RINGTONES[0] || mEffectId > RINGTONES[RINGTONES.length - 1]) {
+                        throw new IllegalArgumentException(
+                                "Unknown prebaked effect type (value=" + mEffectId + ")");
+                    }
             }
             if (!isValidEffectStrength(mEffectStrength)) {
                 throw new IllegalArgumentException(
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 12a495b..fb22194 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -80,4 +80,11 @@
      *  ("28", ["libjpeg.so", "libbase.so"])]
      */
     public static native Map<String, String[]> getVndkSnapshots();
+
+    /**
+     * @return target FCM version, a number specified in the device manifest
+     * indicating the FCM version that the device manifest implements. Null if
+     * device manifest doesn't specify this number (for legacy devices).
+     */
+    public static native Long getTargetFrameworkCompatibilityMatrixVersion();
 }
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 670f794..4a97640 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -61,18 +61,27 @@
     /**
      * The name of the socket used to communicate with the primary zygote.
      */
-    private final String mSocket;
+    private final LocalSocketAddress mSocket;
 
     /**
      * The name of the secondary (alternate ABI) zygote socket.
      */
-    private final String mSecondarySocket;
+    private final LocalSocketAddress mSecondarySocket;
 
     public ZygoteProcess(String primarySocket, String secondarySocket) {
+        this(new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED),
+                new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED));
+    }
+
+    public ZygoteProcess(LocalSocketAddress primarySocket, LocalSocketAddress secondarySocket) {
         mSocket = primarySocket;
         mSecondarySocket = secondarySocket;
     }
 
+    public LocalSocketAddress getPrimarySocketAddress() {
+        return mSocket;
+    }
+
     /**
      * State for communicating with the zygote process.
      */
@@ -92,14 +101,13 @@
             this.abiList = abiList;
         }
 
-        public static ZygoteState connect(String socketAddress) throws IOException {
+        public static ZygoteState connect(LocalSocketAddress address) throws IOException {
             DataInputStream zygoteInputStream = null;
             BufferedWriter zygoteWriter = null;
             final LocalSocket zygoteSocket = new LocalSocket();
 
             try {
-                zygoteSocket.connect(new LocalSocketAddress(socketAddress,
-                        LocalSocketAddress.Namespace.RESERVED));
+                zygoteSocket.connect(address);
 
                 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
 
@@ -115,8 +123,8 @@
             }
 
             String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
-            Log.i("Zygote", "Process: zygote socket " + socketAddress + " opened, supported ABIS: "
-                    + abiListString);
+            Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
+                    + address.getName() + " opened, supported ABIS: " + abiListString);
 
             return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                     Arrays.asList(abiListString.split(",")));
@@ -514,9 +522,19 @@
      * @param socketName The name of the socket to connect to.
      */
     public static void waitForConnectionToZygote(String socketName) {
+        final LocalSocketAddress address =
+                new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.RESERVED);
+        waitForConnectionToZygote(address);
+    }
+
+    /**
+     * Try connecting to the Zygote over and over again until we hit a time-out.
+     * @param address The name of the socket to connect to.
+     */
+    public static void waitForConnectionToZygote(LocalSocketAddress address) {
         for (int n = 20; n >= 0; n--) {
             try {
-                final ZygoteState zs = ZygoteState.connect(socketName);
+                final ZygoteState zs = ZygoteState.connect(address);
                 zs.close();
                 return;
             } catch (IOException ioe) {
@@ -529,6 +547,6 @@
             } catch (InterruptedException ie) {
             }
         }
-        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + socketName);
+        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
     }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6f62f6b..a183895 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3692,6 +3692,20 @@
                 new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
 
         /**
+         * User-selected RTT mode
+         * 0 = OFF
+         * 1 = FULL
+         * 2 = VCO
+         * 3 = HCO
+         * Uses the same constants as TTY (e.g. {@link android.telecom.TelecomManager#TTY_MODE_OFF})
+         * @hide
+         */
+        public static final String RTT_CALLING_MODE = "rtt_calling_mode";
+
+        /** @hide */
+        public static final Validator RTT_CALLING_MODE_VALIDATOR = TTY_MODE_VALIDATOR;
+
+        /**
          * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
          * boolean (1 or 0).
          */
@@ -4016,6 +4030,7 @@
             DTMF_TONE_WHEN_DIALING,
             DTMF_TONE_TYPE_WHEN_DIALING,
             HEARING_AID,
+            RTT_CALLING_MODE,
             TTY_MODE,
             MASTER_MONO,
             SOUND_EFFECTS_ENABLED,
@@ -4214,6 +4229,7 @@
             VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR);
             VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR);
             VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR);
+            VALIDATORS.put(RTT_CALLING_MODE, RTT_CALLING_MODE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR);
             VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR);
             VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);
@@ -7380,7 +7396,8 @@
          */
         public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode";
 
-        private static final Validator NIGHT_DISPLAY_AUTO_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
+        private static final Validator NIGHT_DISPLAY_AUTO_MODE_VALIDATOR =
+                new SettingsValidators.InclusiveIntegerRangeValidator(0, 2);
 
         /**
          * Control the color temperature of Night Display, represented in Kelvin.
@@ -8373,10 +8390,10 @@
         private static final Validator POWER_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
-         * URI for the "wireless charging started" sound.
+         * URI for the "wireless charging started" and "wired charging started" sound.
          * @hide
          */
-        public static final String WIRELESS_CHARGING_STARTED_SOUND =
+        public static final String CHARGING_STARTED_SOUND =
                 "wireless_charging_started_sound";
 
         /**
@@ -10255,6 +10272,20 @@
         public static final String BATTERY_TIP_CONSTANTS = "battery_tip_constants";
 
         /**
+         * An integer to show the version of the anomaly config. Ex: 1, which means
+         * current version is 1.
+         * @hide
+         */
+        public static final String ANOMALY_CONFIG_VERSION = "anomaly_config_version";
+
+        /**
+         * A base64-encoded string represents anomaly stats config, used for
+         * {@link android.app.StatsManager}.
+         * @hide
+         */
+        public static final String ANOMALY_CONFIG = "anomaly_config";
+
+        /**
          * Always on display(AOD) specific settings
          * This is encoded as a key=value list, separated by commas. Ex:
          *
@@ -10293,6 +10324,15 @@
         public static final String FPS_DEVISOR = "fps_divisor";
 
         /**
+         * Flag to enable or disable display panel low power mode (lpm)
+         * false -> Display panel power saving mode is disabled.
+         * true  -> Display panel power saving mode is enabled.
+         *
+         * @hide
+         */
+        public static final String DISPLAY_PANEL_LPM = "display_panel_lpm";
+
+        /**
          * App standby (app idle) specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          * <p>
@@ -12049,11 +12089,22 @@
                 "zram_enabled";
 
         /**
-         * Whether smart replies in notifications are enabled.
+         * Configuration flags for smart replies in notifications.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "enabled=1,max_squeeze_remeasure_count=3"
+         *
+         * The following keys are supported:
+         *
+         * <pre>
+         * enabled                         (boolean)
+         * max_squeeze_remeasure_attempts  (int)
+         * </pre>
+         * @see com.android.systemui.statusbar.policy.SmartReplyConstants
          * @hide
          */
-        public static final String ENABLE_SMART_REPLIES_IN_NOTIFICATIONS =
-                "enable_smart_replies_in_notifications";
+        public static final String SMART_REPLIES_IN_NOTIFICATIONS_FLAGS =
+                "smart_replies_in_notifications_flags";
 
         /**
          * If nonzero, crashes in foreground processes will bring up a dialog.
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index 29c6cea..7383de7 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -44,6 +44,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.Map;
 
 /**
@@ -247,4 +248,13 @@
                 && !mCompatibilityPackages.isEmpty()).append("]");
         return builder.toString();
     }
+
+    /**
+     * Dumps it!
+     */
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("Component: "); pw.println(getServiceInfo().getComponentName());
+        pw.print(prefix); pw.print("Settings: "); pw.println(mSettingsActivity);
+        pw.print(prefix); pw.print("Compat packages: "); pw.println(mCompatibilityPackages);
+    }
 }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b7b2b2d..422e36b 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1343,6 +1343,7 @@
     /**
      * @hide
      */
+    @GuardedBy("mLock")
     public final void applyUpdateLocked(NotificationRankingUpdate update) {
         mRankingMap = new RankingMap(update);
     }
diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS
index 0f85e1f..9f2182e 100644
--- a/core/java/android/text/OWNERS
+++ b/core/java/android/text/OWNERS
@@ -1,4 +1,3 @@
 siyamed@google.com
 nona@google.com
 clarabayarri@google.com
-toki@google.com
diff --git a/core/java/android/transition/ArcMotion.java b/core/java/android/transition/ArcMotion.java
index da14834..172c837 100644
--- a/core/java/android/transition/ArcMotion.java
+++ b/core/java/android/transition/ArcMotion.java
@@ -216,7 +216,13 @@
 
         boolean isMovingUpwards = startY > endY;
 
-        if ((Math.abs(deltaX) < Math.abs(deltaY))) {
+        if (deltaY == 0) {
+            ex = dx;
+            ey = dy + (Math.abs(deltaX) * 0.5f * mMinimumHorizontalTangent);
+        } else if (deltaX == 0) {
+            ex = dx + (Math.abs(deltaY) * 0.5f * mMinimumVerticalTangent);
+            ey = dy;
+        } else if ((Math.abs(deltaX) < Math.abs(deltaY))) {
             // Similar triangles bfa and bde mean that (ab/fb = eb/bd)
             // Therefore, eb = ab * bd / fb
             // ab = hypotenuse
@@ -254,7 +260,7 @@
         float maximumArcDist2 = midDist2 * mMaximumTangent * mMaximumTangent;
 
         float newArcDistance2 = 0;
-        if (arcDist2 < minimumArcDist2) {
+        if (arcDist2 != 0 && arcDist2 < minimumArcDist2) {
             newArcDistance2 = minimumArcDist2;
         } else if (arcDist2 > maximumArcDist2) {
             newArcDistance2 = maximumArcDist2;
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index 084b79d..60b77bc 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -163,10 +163,14 @@
     public static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds,
             ViewGroup sceneRoot) {
         final boolean addToOverlay = !view.isAttachedToWindow();
+        ViewGroup parent = null;
+        int indexInParent = 0;
         if (addToOverlay) {
             if (sceneRoot == null || !sceneRoot.isAttachedToWindow()) {
                 return null;
             }
+            parent = (ViewGroup) view.getParent();
+            indexInParent = parent.indexOfChild(view);
             sceneRoot.getOverlay().add(view);
         }
         Bitmap bitmap = null;
@@ -190,6 +194,7 @@
         }
         if (addToOverlay) {
             sceneRoot.getOverlay().remove(view);
+            parent.addView(view, indexInParent);
         }
         return bitmap;
     }
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index f0838a1..77c652e 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -402,8 +402,11 @@
                 // Becoming GONE
                 if (startView == endView) {
                     viewToKeep = endView;
-                } else {
+                } else if (mCanRemoveViews) {
                     overlayView = startView;
+                } else {
+                    overlayView = TransitionUtils.copyViewImage(sceneRoot, startView,
+                            (View) startView.getParent());
                 }
             }
         }
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
index eb8c168..7f327c7 100644
--- a/core/java/android/util/AttributeSet.java
+++ b/core/java/android/util/AttributeSet.java
@@ -17,6 +17,8 @@
 package android.util;
 
 
+import org.xmlpull.v1.XmlPullParser;
+
 /**
  * A collection of attributes, as found associated with a tag in an XML
  * document.  Often you will not want to use this interface directly, instead
@@ -54,18 +56,42 @@
  * compiled XML resource that is not available in a normal XML file, such
  * as {@link #getAttributeNameResource(int)} which returns the resource
  * identifier associated with a particular XML attribute name.
+ *
+ * @see XmlPullParser
  */
 public interface AttributeSet {
     /**
      * Returns the number of attributes available in the set.
-     * 
+     *
+     * <p>See also {@link XmlPullParser#getAttributeCount XmlPullParser.getAttributeCount()},
+     * which this method corresponds to when parsing a compiled XML file.</p>
+     *
      * @return A positive integer, or 0 if the set is empty.
      */
     public int getAttributeCount();
 
     /**
+     * Returns the namespace of the specified attribute.
+     *
+     * <p>See also {@link XmlPullParser#getAttributeNamespace XmlPullParser.getAttributeNamespace()},
+     * which this method corresponds to when parsing a compiled XML file.</p>
+     *
+     * @param index Index of the desired attribute, 0...count-1.
+     *
+     * @return A String containing the namespace of the attribute, or null if th
+     *         attribute cannot be found.
+     */
+    default String getAttributeNamespace (int index) {
+        // This is a new method since the first interface definition, so add stub impl.
+        return null;
+    }
+
+    /**
      * Returns the name of the specified attribute.
-     * 
+     *
+     * <p>See also {@link XmlPullParser#getAttributeName XmlPullParser.getAttributeName()},
+     * which this method corresponds to when parsing a compiled XML file.</p>
+     *
      * @param index Index of the desired attribute, 0...count-1.
      * 
      * @return A String containing the name of the attribute, or null if the
diff --git a/core/java/android/util/ByteStringUtils.java b/core/java/android/util/ByteStringUtils.java
index 333208d..f6460ad 100644
--- a/core/java/android/util/ByteStringUtils.java
+++ b/core/java/android/util/ByteStringUtils.java
@@ -22,61 +22,63 @@
  * @hide
  */
 public final class ByteStringUtils {
-  private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+    private static final char[] HEX_LOWERCASE_ARRAY = "0123456789abcdef".toCharArray();
+    private static final char[] HEX_UPPERCASE_ARRAY = "0123456789ABCDEF".toCharArray();
 
-  private ByteStringUtils() {
+    private ByteStringUtils() {
     /* hide constructor */
-  }
-
-  /**
-   * Returns the hex encoded string representation of bytes.
-   * @param bytes Byte array to encode.
-   * @return Hex encoded string representation of bytes.
-   */
-  public static String toHexString(byte[] bytes) {
-    if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
-      return null;
     }
 
-    final int byteLength = bytes.length;
-    final int charCount = 2 * byteLength;
-    final char[] chars = new char[charCount];
+    /**
+     * Returns the hex encoded string representation of bytes.
+     * @param bytes Byte array to encode.
+     * @return Hex encoded string representation of bytes.
+     */
+    public static String toHexString(byte[] bytes) {
+        if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
+            return null;
+        }
 
-    for (int i = 0; i < byteLength; i++) {
-      final int byteHex = bytes[i] & 0xFF;
-      chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
-      chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
-    }
-    return new String(chars);
-  }
+        final int byteLength = bytes.length;
+        final int charCount = 2 * byteLength;
+        final char[] chars = new char[charCount];
 
-  /**
-   * Returns the decoded byte array representation of str.
-   * @param str Hex encoded string to decode.
-   * @return Decoded byte array representation of str.
-   */
-  public static byte[] fromHexToByteArray(String str) {
-    if (str == null || str.length() == 0 || str.length() % 2 != 0) {
-      return null;
+        for (int i = 0; i < byteLength; i++) {
+            final int byteHex = bytes[i] & 0xFF;
+            chars[i * 2] = HEX_UPPERCASE_ARRAY[byteHex >>> 4];
+            chars[i * 2 + 1] = HEX_UPPERCASE_ARRAY[byteHex & 0x0F];
+        }
+        return new String(chars);
     }
 
-    final char[] chars = str.toCharArray();
-    final int charLength = chars.length;
-    final byte[] bytes = new byte[charLength / 2];
+    /**
+     * Returns the decoded byte array representation of str.
+     * @param str Hex encoded string to decode.
+     * @return Decoded byte array representation of str.
+     */
+    public static byte[] fromHexToByteArray(String str) {
+        if (str == null || str.length() == 0 || str.length() % 2 != 0) {
+            return null;
+        }
 
-    for (int i = 0; i < bytes.length; i++) {
-      bytes[i] =
-          (byte)(((getIndex(chars[i * 2]) << 4) & 0xF0) | (getIndex(chars[i * 2 + 1]) & 0x0F));
-    }
-    return bytes;
-  }
+        final char[] chars = str.toCharArray();
+        final int charLength = chars.length;
+        final byte[] bytes = new byte[charLength / 2];
 
-  private static int getIndex(char c) {
-    for (int i = 0; i < HEX_ARRAY.length; i++) {
-      if (HEX_ARRAY[i] == c) {
-        return i;
-      }
+        for (int i = 0; i < bytes.length; i++) {
+            bytes[i] =
+                    (byte) (((getIndex(chars[i * 2]) << 4) & 0xF0)
+                            | (getIndex(chars[i * 2 + 1]) & 0x0F));
+        }
+        return bytes;
     }
-    return -1;
-  }
+
+    private static int getIndex(char c) {
+        for (int i = 0; i < HEX_UPPERCASE_ARRAY.length; i++) {
+            if (HEX_UPPERCASE_ARRAY[i] == c || HEX_LOWERCASE_ARRAY[i] == c) {
+                return i;
+            }
+        }
+        return -1;
+    }
 }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 410cdc6..1ead0b4 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -37,13 +37,13 @@
     private static final Map<String, String> DEFAULT_FLAGS;
     static {
         DEFAULT_FLAGS = new HashMap<>();
-        DEFAULT_FLAGS.put("device_info_v2", "true");
         DEFAULT_FLAGS.put("settings_connected_device_v2", "true");
         DEFAULT_FLAGS.put("settings_battery_v2", "true");
         DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
         DEFAULT_FLAGS.put("settings_zone_picker_v2", "true");
-        DEFAULT_FLAGS.put("settings_about_phone_v2", "false");
+        DEFAULT_FLAGS.put("settings_about_phone_v2", "true");
         DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
+        DEFAULT_FLAGS.put("settings_data_usage_v2", "false");
     }
 
     /**
diff --git a/core/java/android/util/StatsManager.java b/core/java/android/util/StatsManager.java
deleted file mode 100644
index 51fb18a..0000000
--- a/core/java/android/util/StatsManager.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.util;
-
-import android.Manifest;
-import android.annotation.RequiresPermission;
-import android.os.IBinder;
-import android.os.IStatsManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-
-
-/*
- *
- *
- *
- *
- * THIS ENTIRE FILE IS ONLY TEMPORARY TO PREVENT BREAKAGES OF DEPENDENCIES ON OLD APIS.
- * The new StatsManager is to be found in android.app.StatsManager.
- * TODO: Delete this file!
- *
- *
- *
- *
- */
-
-
-/**
- * API for StatsD clients to send configurations and retrieve data.
- *
- * @hide
- */
-public class StatsManager {
-    IStatsManager mService;
-    private static final String TAG = "StatsManager";
-
-    /**
-     * Constructor for StatsManagerClient.
-     *
-     * @hide
-     */
-    public StatsManager() {
-    }
-
-    /**
-     * Temporary to prevent build failures. Will be deleted.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public boolean addConfiguration(String configKey, byte[] config, String pkg, String cls) {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when adding configuration");
-                    return false;
-                }
-                return service.addConfiguration(Long.parseLong(configKey), config, pkg, cls);
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when adding configuration");
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Clients can send a configuration and simultaneously registers the name of a broadcast
-     * receiver that listens for when it should request data.
-     *
-     * @param configKey An arbitrary integer that allows clients to track the configuration.
-     * @param config    Wire-encoded StatsDConfig proto that specifies metrics (and all
-     *                  dependencies eg, conditions and matchers).
-     * @param pkg       The package name to receive the broadcast.
-     * @param cls       The name of the class that receives the broadcast.
-     * @return true if successful
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public boolean addConfiguration(long configKey, byte[] config, String pkg, String cls) {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when adding configuration");
-                    return false;
-                }
-                return service.addConfiguration(configKey, config, pkg, cls);
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when adding configuration");
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Temporary to prevent build failures. Will be deleted.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public boolean removeConfiguration(String configKey) {
-        // To prevent breakages of old dependencies.
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when removing configuration");
-                    return false;
-                }
-                return service.removeConfiguration(Long.parseLong(configKey));
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when removing configuration");
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Remove a configuration from logging.
-     *
-     * @param configKey Configuration key to remove.
-     * @return true if successful
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public boolean removeConfiguration(long configKey) {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when removing configuration");
-                    return false;
-                }
-                return service.removeConfiguration(configKey);
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when removing configuration");
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Temporary to prevent build failures. Will be deleted.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public byte[] getData(String configKey) {
-        // TODO: remove this and all other methods with String-based config keys.
-        // To prevent build breakages of dependencies.
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting data");
-                    return null;
-                }
-                return service.getData(Long.parseLong(configKey));
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting data");
-                return null;
-            }
-        }
-    }
-
-    /**
-     * Clients can request data with a binder call. This getter is destructive and also clears
-     * the retrieved metrics from statsd memory.
-     *
-     * @param configKey Configuration key to retrieve data from.
-     * @return Serialized ConfigMetricsReportList proto. Returns null on failure.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public byte[] getData(long configKey) {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting data");
-                    return null;
-                }
-                return service.getData(configKey);
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting data");
-                return null;
-            }
-        }
-    }
-
-    /**
-     * Clients can request metadata for statsd. Will contain stats across all configurations but not
-     * the actual metrics themselves (metrics must be collected via {@link #getData(String)}.
-     * This getter is not destructive and will not reset any metrics/counters.
-     *
-     * @return Serialized StatsdStatsReport proto. Returns null on failure.
-     */
-    @RequiresPermission(Manifest.permission.DUMP)
-    public byte[] getMetadata() {
-        synchronized (this) {
-            try {
-                IStatsManager service = getIStatsManagerLocked();
-                if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting metadata");
-                    return null;
-                }
-                return service.getMetadata();
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting metadata");
-                return null;
-            }
-        }
-    }
-
-    private class StatsdDeathRecipient implements IBinder.DeathRecipient {
-        @Override
-        public void binderDied() {
-            synchronized (this) {
-                mService = null;
-            }
-        }
-    }
-
-    private IStatsManager getIStatsManagerLocked() throws RemoteException {
-        if (mService != null) {
-            return mService;
-        }
-        mService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
-        if (mService != null) {
-            mService.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
-        }
-        return mService;
-    }
-}
diff --git a/core/java/android/util/XmlPullAttributes.java b/core/java/android/util/XmlPullAttributes.java
index 6c8bb39..cb35eb5 100644
--- a/core/java/android/util/XmlPullAttributes.java
+++ b/core/java/android/util/XmlPullAttributes.java
@@ -34,6 +34,10 @@
         return mParser.getAttributeCount();
     }
 
+    public String getAttributeNamespace (int index) {
+        return mParser.getAttributeNamespace(index);
+    }
+
     public String getAttributeName(int index) {
         return mParser.getAttributeName(index);
     }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 37e9815..7251b71 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -20,6 +20,7 @@
 import static android.view.DisplayInfoProto.APP_WIDTH;
 import static android.view.DisplayInfoProto.LOGICAL_HEIGHT;
 import static android.view.DisplayInfoProto.LOGICAL_WIDTH;
+import static android.view.DisplayInfoProto.NAME;
 
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -685,6 +686,7 @@
         protoOutputStream.write(LOGICAL_HEIGHT, logicalHeight);
         protoOutputStream.write(APP_WIDTH, appWidth);
         protoOutputStream.write(APP_HEIGHT, appHeight);
+        protoOutputStream.write(NAME, name);
         protoOutputStream.end(token);
     }
 
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index ea6226b..69973e6 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Rect;
 import android.view.RemoteAnimationTarget;
 import android.view.IRecentsAnimationController;
 
@@ -28,15 +29,26 @@
 oneway interface IRecentsAnimationRunner {
 
     /**
-     * Called when the system is ready for the handler to start animating all the visible tasks.
+     * Deprecated, to be removed once Launcher updates
      */
     void onAnimationStart(in IRecentsAnimationController controller,
-            in RemoteAnimationTarget[] apps);
+            in RemoteAnimationTarget[] apps) = 0;
 
     /**
      * Called when the system needs to cancel the current animation. This can be due to the
      * wallpaper not drawing in time, or the handler not finishing the animation within a predefined
      * amount of time.
      */
-    void onAnimationCanceled();
+    void onAnimationCanceled() = 1;
+
+    /**
+     * Called when the system is ready for the handler to start animating all the visible tasks.
+     *
+     * @param homeContentInsets The current home app content insets
+     * @param minimizedHomeBounds Specifies the bounds of the minimized home app, will be
+     *                            {@code null} if the device is not currently in split screen
+     */
+    void onAnimationStart_New(in IRecentsAnimationController controller,
+            in RemoteAnimationTarget[] apps, in Rect homeContentInsets,
+            in Rect minimizedHomeBounds) = 2;
 }
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index c28c389..facf575 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -79,6 +79,11 @@
     public final Rect clipRect;
 
     /**
+     * The insets of the main app window.
+     */
+    public final Rect contentInsets;
+
+    /**
      * The index of the element in the tree in prefix order. This should be used for z-layering
      * to preserve original z-layer order in the hierarchy tree assuming no "boosting" needs to
      * happen.
@@ -105,13 +110,14 @@
     public final WindowConfiguration windowConfiguration;
 
     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
-            Rect clipRect, int prefixOrderIndex, Point position, Rect sourceContainerBounds,
-            WindowConfiguration windowConfig) {
+            Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
+            Rect sourceContainerBounds, WindowConfiguration windowConfig) {
         this.mode = mode;
         this.taskId = taskId;
         this.leash = leash;
         this.isTranslucent = isTranslucent;
         this.clipRect = new Rect(clipRect);
+        this.contentInsets = new Rect(contentInsets);
         this.prefixOrderIndex = prefixOrderIndex;
         this.position = new Point(position);
         this.sourceContainerBounds = new Rect(sourceContainerBounds);
@@ -124,6 +130,7 @@
         leash = in.readParcelable(null);
         isTranslucent = in.readBoolean();
         clipRect = in.readParcelable(null);
+        contentInsets = in.readParcelable(null);
         prefixOrderIndex = in.readInt();
         position = in.readParcelable(null);
         sourceContainerBounds = in.readParcelable(null);
@@ -142,6 +149,7 @@
         dest.writeParcelable(leash, 0 /* flags */);
         dest.writeBoolean(isTranslucent);
         dest.writeParcelable(clipRect, 0 /* flags */);
+        dest.writeParcelable(contentInsets, 0 /* flags */);
         dest.writeInt(prefixOrderIndex);
         dest.writeParcelable(position, 0 /* flags */);
         dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 79fc134..cf26b2b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
+
 import static java.lang.Math.max;
 
 import android.animation.AnimatorInflater;
@@ -906,6 +907,13 @@
      */
     private static boolean sThrowOnInvalidFloatProperties;
 
+    /**
+     * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow.
+     * Currently zero size SurfaceControl cannot be created thus we create a dummy 1x1 surface
+     * instead.
+     */
+    private static boolean sAcceptZeroSizeDragShadow;
+
     /** @hide */
     @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO})
     @Retention(RetentionPolicy.SOURCE)
@@ -4798,6 +4806,7 @@
 
             Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M;
             Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O;
+            Canvas.setCompatibilityVersion(targetSdkVersion);
 
             // In M and newer, our widgets can pass a "hint" value in the size
             // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers
@@ -4840,6 +4849,8 @@
 
             sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P;
 
+            sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P;
+
             sCompatibilityDone = true;
         }
     }
@@ -7860,6 +7871,7 @@
                 structure.setAutofillHints(getAutofillHints());
                 structure.setAutofillValue(getAutofillValue());
             }
+            structure.setImportantForAutofill(getImportantForAutofill());
         }
 
         int ignoredParentLeft = 0;
@@ -8378,7 +8390,7 @@
             AccessibilityNodeProvider provider, AccessibilityNodeInfo info,
             boolean forAutofill) {
         structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
-                null, null, null);
+                null, null, info.getViewIdResourceName());
         Rect rect = structure.getTempRect();
         info.getBoundsInParent(rect);
         structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height());
@@ -8418,6 +8430,13 @@
         CharSequence cname = info.getClassName();
         structure.setClassName(cname != null ? cname.toString() : null);
         structure.setContentDescription(info.getContentDescription());
+        if (forAutofill) {
+            final int maxTextLength = info.getMaxTextLength();
+            if (maxTextLength != -1) {
+                structure.setMaxTextLength(maxTextLength);
+            }
+            structure.setHint(info.getHintText());
+        }
         if ((info.getText() != null || info.getError() != null)) {
             structure.setText(info.getText(), info.getTextSelectionStart(),
                     info.getTextSelectionEnd());
@@ -8428,7 +8447,8 @@
                     final AutofillValue autofillValue = AutofillValue.forText(structure.getText());
                     structure.setAutofillValue(autofillValue);
                     if (info.isPassword()) {
-                        structure.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
+                        structure.setInputType(InputType.TYPE_CLASS_TEXT
+                                | InputType.TYPE_TEXT_VARIATION_PASSWORD);
                     }
                 } else {
                     structure.setDataIsSensitive(false);
@@ -23619,8 +23639,7 @@
          * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)}
          * and {@link #onDrawShadow(Canvas)} methods are also overridden in order
          * to supply the drag shadow's dimensions and appearance without
-         * reference to any View object. If they are not overridden, then the result is an
-         * invisible drag shadow.
+         * reference to any View object.
          */
         public DragShadowBuilder() {
             mView = new WeakReference<View>(null);
@@ -23774,6 +23793,9 @@
         // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder
         // does not accept zero size surface.
         if (shadowSize.x == 0  || shadowSize.y == 0) {
+            if (!sAcceptZeroSizeDragShadow) {
+                throw new IllegalStateException("Drag shadow dimensions must be positive");
+            }
             shadowSize.x = 1;
             shadowSize.y = 1;
         }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 273f097..8e60a72 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3971,15 +3971,7 @@
     }
 
     /**
-     * Layout debugging code which draws rectangles around layout params.
-     *
-     * <p>This function is called automatically when the developer setting is enabled.<p/>
-     *
-     * <p>It is strongly advised to only call this function from debug builds as there is
-     * a risk of leaking unwanted layout information.<p/>
-     *
-     * @param canvas the canvas on which to draw
-     * @param paint the paint used to draw through
+     * @hide
      */
     protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
         for (int i = 0; i < getChildCount(); i++) {
@@ -3989,19 +3981,7 @@
     }
 
     /**
-     * Layout debugging code which draws rectangles around:
-     * <ul>
-     *     <li>optical bounds<li/>
-     *     <li>margins<li/>
-     *     <li>clip bounds<li/>
-     * <ul/>
-     *
-     * <p>This function is called automatically when the developer setting is enabled.<p/>
-     *
-     * <p>It is strongly advised to only call this function from debug builds as there is
-     * a risk of leaking unwanted layout information.<p/>
-     *
-     * @param canvas the canvas on which to draw
+     * @hide
      */
     protected void onDebugDraw(Canvas canvas) {
         Paint paint = getDebugPaint();
@@ -7732,14 +7712,10 @@
         /**
          * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
          *
-         * <p>This function is called automatically when the developer setting is enabled.<p/>
-         *
-         * <p>It is strongly advised to only call this function from debug builds as there is
-         * a risk of leaking unwanted layout information.<p/>
-         *
          * @param view the view that contains these layout parameters
          * @param canvas the canvas on which to draw
-         * @param paint the paint used to draw through
+         *
+         * @hide
          */
         public void onDebugDraw(View view, Canvas canvas, Paint paint) {
         }
@@ -8243,6 +8219,9 @@
             return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
         }
 
+        /**
+         * @hide
+         */
         @Override
         public void onDebugDraw(View view, Canvas canvas, Paint paint) {
             Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 1d94abe..3f7ab2a 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -23,6 +23,8 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.util.Pair;
+import android.view.View.AutofillImportance;
+import android.view.ViewStructure.HtmlInfo;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 
@@ -347,6 +349,12 @@
     public abstract void setAutofillOptions(CharSequence[] options);
 
     /**
+     * Sets the {@link View#setImportantForAutofill(int) importantForAutofill mode} of the
+     * view associated with this node.
+     */
+    public void setImportantForAutofill(@AutofillImportance int mode) {}
+
+    /**
      * Sets the {@link android.text.InputType} bits of this node.
      *
      * @param inputType inputType bits as defined by {@link android.text.InputType}.
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 191c270..dee267d 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -774,8 +774,9 @@
      */
     public void removeAccessibilityServicesStateChangeListener(
             @NonNull AccessibilityServicesStateChangeListener listener) {
-        // Final CopyOnWriteArrayList - no lock needed.
-        mServicesStateChangeListeners.remove(listener);
+        synchronized (mLock) {
+            mServicesStateChangeListeners.remove(listener);
+        }
     }
 
     /**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 23e7d61..417a725 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3173,6 +3173,15 @@
      */
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
+        writeToParcelNoRecycle(parcel, flags);
+        // Since instances of this class are fetched via synchronous i.e. blocking
+        // calls in IPCs we always recycle as soon as the instance is marshaled.
+        recycle();
+    }
+
+    /** @hide */
+    @TestApi
+    public void writeToParcelNoRecycle(Parcel parcel, int flags) {
         // Write bit set of indices of fields with values differing from default
         long nonDefaultFields = 0;
         int fieldIndex = 0; // index of the current field
@@ -3406,10 +3415,6 @@
                         + " vs " + fieldIndex);
             }
         }
-
-        // Since instances of this class are fetched via synchronous i.e. blocking
-        // calls in IPCs we always recycle as soon as the instance is marshaled.
-        recycle();
     }
 
     /**
@@ -3557,7 +3562,7 @@
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
             mContentDescription = parcel.readCharSequence();
         }
-        if (isBitSet(nonDefaultFields, fieldIndex++)) mPaneTitle = parcel.readString();
+        if (isBitSet(nonDefaultFields, fieldIndex++)) mPaneTitle = parcel.readCharSequence();
         if (isBitSet(nonDefaultFields, fieldIndex++)) mTooltipText = parcel.readCharSequence();
         if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString();
 
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 63a9990..8b64bad 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,6 +16,10 @@
 
 package android.view.autofill;
 
+import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.view.autofill.Helper.sDebug;
+import static android.view.autofill.Helper.sVerbose;
+
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -47,13 +51,14 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.accessibility.AccessibilityWindowInfo;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
+
 import org.xmlpull.v1.XmlPullParserException;
-import sun.misc.Cleaner;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -66,9 +71,7 @@
 import java.util.List;
 import java.util.Objects;
 
-import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
-import static android.view.autofill.Helper.sDebug;
-import static android.view.autofill.Helper.sVerbose;
+import sun.misc.Cleaner;
 
 // TODO: use java.lang.ref.Cleaner once Android supports Java 9
 
@@ -616,10 +619,9 @@
     /**
      * @hide
      */
-    public boolean isCompatibilityModeEnabled() {
-        synchronized (mLock) {
-            return mCompatibilityBridge != null;
-        }
+    @GuardedBy("mLock")
+    public boolean isCompatibilityModeEnabledLocked() {
+        return mCompatibilityBridge != null;
     }
 
     /**
@@ -708,6 +710,7 @@
         notifyViewEntered(view, 0);
     }
 
+    @GuardedBy("mLock")
     private boolean shouldIgnoreViewEnteredLocked(@NonNull View view, int flags) {
         if (isDisabledByServiceLocked()) {
             if (sVerbose) {
@@ -748,6 +751,7 @@
     }
 
     /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
+    @GuardedBy("mLock")
     private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) {
         if (shouldIgnoreViewEnteredLocked(view, flags)) return null;
 
@@ -791,6 +795,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void notifyViewExitedLocked(@NonNull View view) {
         ensureServiceClientAddedIfNeededLocked();
 
@@ -892,6 +897,7 @@
     }
 
     /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
+    @GuardedBy("mLock")
     private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds,
                                                      int flags) {
         AutofillCallback callback = null;
@@ -935,6 +941,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void notifyViewExitedLocked(@NonNull View view, int virtualId) {
         ensureServiceClientAddedIfNeededLocked();
 
@@ -1086,6 +1093,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void commitLocked() {
         if (!mEnabled && !isActiveLocked()) {
             return;
@@ -1114,6 +1122,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void cancelLocked() {
         if (!mEnabled && !isActiveLocked()) {
             return;
@@ -1377,11 +1386,13 @@
         return new AutofillId(parent.getAutofillViewId(), virtualId);
     }
 
+    @GuardedBy("mLock")
     private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
             @NonNull AutofillValue value, int flags) {
         if (sVerbose) {
             Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
-                    + ", flags=" + flags + ", state=" + getStateAsStringLocked());
+                    + ", flags=" + flags + ", state=" + getStateAsStringLocked()
+                    + ", compatMode=" + isCompatibilityModeEnabledLocked());
         }
         if (mState != STATE_UNKNOWN && !isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
             if (sVerbose) {
@@ -1392,7 +1403,7 @@
         }
         try {
             final AutofillClient client = getClient();
-            if (client == null) return; // NOTE: getClient() already logd it..
+            if (client == null) return; // NOTE: getClient() already logged it..
 
             mSessionId = mService.startSession(client.autofillClientGetActivityToken(),
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
@@ -1406,6 +1417,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void finishSessionLocked() {
         if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + getStateAsStringLocked());
 
@@ -1420,6 +1432,7 @@
         resetSessionLocked();
     }
 
+    @GuardedBy("mLock")
     private void cancelSessionLocked() {
         if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + getStateAsStringLocked());
 
@@ -1434,6 +1447,7 @@
         resetSessionLocked();
     }
 
+    @GuardedBy("mLock")
     private void resetSessionLocked() {
         mSessionId = NO_SESSION;
         mState = STATE_UNKNOWN;
@@ -1442,6 +1456,7 @@
         mSaveTriggerId = null;
     }
 
+    @GuardedBy("mLock")
     private void updateSessionLocked(AutofillId id, Rect bounds, AutofillValue value, int action,
             int flags) {
         if (sVerbose && action != ACTION_VIEW_EXITED) {
@@ -1476,6 +1491,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void ensureServiceClientAddedIfNeededLocked() {
         if (getClient() == null) {
             return;
@@ -1939,11 +1955,13 @@
         pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
         pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
         pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
-        pw.print(pfx); pw.print("compat mode enabled: "); pw.println(isCompatibilityModeEnabled());
+        pw.print(pfx); pw.print("compat mode enabled: "); pw.println(
+                isCompatibilityModeEnabledLocked());
         pw.print(pfx); pw.print("debug: "); pw.print(sDebug);
         pw.print(" verbose: "); pw.println(sVerbose);
     }
 
+    @GuardedBy("mLock")
     private String getStateAsStringLocked() {
         switch (mState) {
             case STATE_UNKNOWN:
@@ -1961,14 +1979,17 @@
         }
     }
 
+    @GuardedBy("mLock")
     private boolean isActiveLocked() {
         return mState == STATE_ACTIVE;
     }
 
+    @GuardedBy("mLock")
     private boolean isDisabledByServiceLocked() {
         return mState == STATE_DISABLED_BY_SERVICE;
     }
 
+    @GuardedBy("mLock")
     private boolean isFinishedLocked() {
         return mState == STATE_FINISHED;
     }
@@ -2164,6 +2185,7 @@
                     AutofillValue.forText(node.getText()));
         }
 
+        @GuardedBy("mLock")
         private void updateTrackedViewsLocked() {
             if (mTrackedViews != null) {
                 mTrackedViews.onVisibleForAutofillChangedLocked();
@@ -2308,6 +2330,7 @@
          * @param id the id of the view/virtual view whose visibility changed.
          * @param isVisible visible if the view is visible in the view hierarchy.
          */
+        @GuardedBy("mLock")
         void notifyViewVisibilityChangedLocked(@NonNull AutofillId id, boolean isVisible) {
             if (sDebug) {
                 Log.d(TAG, "notifyViewVisibilityChangedLocked(): id=" + id + " isVisible="
@@ -2341,6 +2364,7 @@
          *
          * @see AutofillClient#autofillClientIsVisibleForAutofill()
          */
+        @GuardedBy("mLock")
         void onVisibleForAutofillChangedLocked() {
             // The visibility of the views might have changed while the client was not be visible,
             // hence update the visibility state for all views.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 33c9f7a..9de26a8 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1179,8 +1179,9 @@
         }
     }
 
-    /*
+    /**
      * This method toggles the input method window display.
+     *
      * If the input window is already displayed, it gets hidden.
      * If not the input window will be displayed.
      * @param showFlags Provides additional operating flags.  May be
@@ -1189,7 +1190,6 @@
      * @param hideFlags Provides additional operating flags.  May be
      * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
      * {@link #HIDE_NOT_ALWAYS} bit set.
-     * @hide
      */
     public void toggleSoftInput(int showFlags, int hideFlags) {
         if (mCurMethod != null) {
diff --git a/core/java/android/view/textclassifier/SmartSelection.java b/core/java/android/view/textclassifier/SmartSelection.java
index 8edf97e..69c38ee 100644
--- a/core/java/android/view/textclassifier/SmartSelection.java
+++ b/core/java/android/view/textclassifier/SmartSelection.java
@@ -108,9 +108,9 @@
     }
 
     /**
-     * Returns the language of the model.
+     * Returns a comma separated list of locales supported by the model as BCP 47 tags.
      */
-    public static String getLanguage(int fd) {
+    public static String getLanguages(int fd) {
         return nativeGetLanguage(fd);
     }
 
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index a6a2a94..8fe1d8f 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
@@ -378,7 +379,7 @@
         final List<Drawable> drawables = new ArrayList<>(bitmaps.size());
         for (Bitmap bitmap : bitmaps) {
             if (bitmap != null) {
-                drawables.add(new BitmapDrawable(null, bitmap));
+                drawables.add(new BitmapDrawable(Resources.getSystem(), bitmap));
             } else {
                 drawables.add(null);
             }
@@ -681,7 +682,8 @@
     private TextClassification(Parcel in) {
         mText = in.readString();
         mPrimaryIcon = in.readInt() == 0
-                ? null : new BitmapDrawable(null, Bitmap.CREATOR.createFromParcel(in));
+                ? null
+                : new BitmapDrawable(Resources.getSystem(), Bitmap.CREATOR.createFromParcel(in));
         mPrimaryLabel = in.readString();
         mPrimaryIntent = in.readInt() == 0 ? null : Intent.CREATOR.createFromParcel(in);
         mPrimaryOnClickListener = null;  // not parcelable
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 9f389ba..fc03493 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -27,8 +27,10 @@
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
+import android.os.UserManager;
 import android.provider.Browser;
 import android.provider.CalendarContract;
 import android.provider.ContactsContract;
@@ -56,6 +58,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
+import java.util.StringJoiner;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -99,11 +102,9 @@
 
     private final Object mLock = new Object();
     @GuardedBy("mLock") // Do not access outside this lock.
-    private Map<Locale, String> mModelFilePaths;
+    private List<ModelFile> mAllModelFiles;
     @GuardedBy("mLock") // Do not access outside this lock.
-    private Locale mLocale;
-    @GuardedBy("mLock") // Do not access outside this lock.
-    private int mVersion;
+    private ModelFile mModel;
     @GuardedBy("mLock") // Do not access outside this lock.
     private SmartSelection mSmartSelection;
 
@@ -279,18 +280,18 @@
     private SmartSelection getSmartSelection(LocaleList localeList) throws FileNotFoundException {
         synchronized (mLock) {
             localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
-            final Locale locale = findBestSupportedLocaleLocked(localeList);
-            if (locale == null) {
-                throw new FileNotFoundException("No file for null locale");
+            final ModelFile bestModel = findBestModelLocked(localeList);
+            if (bestModel == null) {
+                throw new FileNotFoundException("No model for " + localeList.toLanguageTags());
             }
-            if (mSmartSelection == null || !Objects.equals(mLocale, locale)) {
+            if (mSmartSelection == null || !Objects.equals(mModel, bestModel)) {
+                Log.d(DEFAULT_LOG_TAG, "Loading " + bestModel);
                 destroySmartSelectionIfExistsLocked();
-                final ParcelFileDescriptor fd = getFdLocked(locale);
-                final int modelFd = fd.getFd();
-                mVersion = SmartSelection.getVersion(modelFd);
-                mSmartSelection = new SmartSelection(modelFd);
+                final ParcelFileDescriptor fd = ParcelFileDescriptor.open(
+                        new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
+                mSmartSelection = new SmartSelection(fd.getFd());
                 closeAndLogError(fd);
-                mLocale = locale;
+                mModel = bestModel;
             }
             return mSmartSelection;
         }
@@ -298,74 +299,8 @@
 
     private String getSignature(String text, int start, int end) {
         synchronized (mLock) {
-            return DefaultLogger.createSignature(text, start, end, mContext, mVersion, mLocale);
-        }
-    }
-
-    @GuardedBy("mLock") // Do not call outside this lock.
-    private ParcelFileDescriptor getFdLocked(Locale locale) throws FileNotFoundException {
-        ParcelFileDescriptor updateFd;
-        int updateVersion = -1;
-        try {
-            updateFd = ParcelFileDescriptor.open(
-                    new File(UPDATED_MODEL_FILE_PATH), ParcelFileDescriptor.MODE_READ_ONLY);
-            if (updateFd != null) {
-                updateVersion = SmartSelection.getVersion(updateFd.getFd());
-            }
-        } catch (FileNotFoundException e) {
-            updateFd = null;
-        }
-        ParcelFileDescriptor factoryFd;
-        int factoryVersion = -1;
-        try {
-            final String factoryModelFilePath = getFactoryModelFilePathsLocked().get(locale);
-            if (factoryModelFilePath != null) {
-                factoryFd = ParcelFileDescriptor.open(
-                        new File(factoryModelFilePath), ParcelFileDescriptor.MODE_READ_ONLY);
-                if (factoryFd != null) {
-                    factoryVersion = SmartSelection.getVersion(factoryFd.getFd());
-                }
-            } else {
-                factoryFd = null;
-            }
-        } catch (FileNotFoundException e) {
-            factoryFd = null;
-        }
-
-        if (updateFd == null) {
-            if (factoryFd != null) {
-                return factoryFd;
-            } else {
-                throw new FileNotFoundException(
-                        String.format(Locale.US, "No model file found for %s", locale));
-            }
-        }
-
-        final int updateFdInt = updateFd.getFd();
-        final boolean localeMatches = Objects.equals(
-                locale.getLanguage().trim().toLowerCase(),
-                SmartSelection.getLanguage(updateFdInt).trim().toLowerCase());
-        if (factoryFd == null) {
-            if (localeMatches) {
-                return updateFd;
-            } else {
-                closeAndLogError(updateFd);
-                throw new FileNotFoundException(
-                        String.format(Locale.US, "No model file found for %s", locale));
-            }
-        }
-
-        if (!localeMatches) {
-            closeAndLogError(updateFd);
-            return factoryFd;
-        }
-
-        if (updateVersion > factoryVersion) {
-            closeAndLogError(factoryFd);
-            return updateFd;
-        } else {
-            closeAndLogError(updateFd);
-            return factoryFd;
+            return DefaultLogger.createSignature(text, start, end, mContext, mModel.getVersion(),
+                    mModel.getSupportedLocales());
         }
     }
 
@@ -377,60 +312,66 @@
         }
     }
 
+    /**
+     * Finds the most appropriate model to use for the given target locale list.
+     *
+     * The basic logic is: we ignore all models that don't support any of the target locales. For
+     * the remaining candidates, we take the update model unless its version number is lower than
+     * the factory version. It's assumed that factory models do not have overlapping locale ranges
+     * and conflict resolution between these models hence doesn't matter.
+     */
     @GuardedBy("mLock") // Do not call outside this lock.
     @Nullable
-    private Locale findBestSupportedLocaleLocked(LocaleList localeList) {
+    private ModelFile findBestModelLocked(LocaleList localeList) {
         // Specified localeList takes priority over the system default, so it is listed first.
         final String languages = localeList.isEmpty()
                 ? LocaleList.getDefault().toLanguageTags()
                 : localeList.toLanguageTags() + "," + LocaleList.getDefault().toLanguageTags();
         final List<Locale.LanguageRange> languageRangeList = Locale.LanguageRange.parse(languages);
 
-        final List<Locale> supportedLocales =
-                new ArrayList<>(getFactoryModelFilePathsLocked().keySet());
-        final Locale updatedModelLocale = getUpdatedModelLocale();
-        if (updatedModelLocale != null) {
-            supportedLocales.add(updatedModelLocale);
+        ModelFile bestModel = null;
+        int bestModelVersion = -1;
+        for (ModelFile model : listAllModelsLocked()) {
+            if (model.isAnyLanguageSupported(languageRangeList)) {
+                if (model.getVersion() >= bestModelVersion) {
+                    bestModel = model;
+                    bestModelVersion = model.getVersion();
+                }
+            }
         }
-        return Locale.lookup(languageRangeList, supportedLocales);
+        return bestModel;
     }
 
+    /** Returns a list of all model files available, in order of precedence. */
     @GuardedBy("mLock") // Do not call outside this lock.
-    private Map<Locale, String> getFactoryModelFilePathsLocked() {
-        if (mModelFilePaths == null) {
-            final Map<Locale, String> modelFilePaths = new HashMap<>();
+    private List<ModelFile> listAllModelsLocked() {
+        if (mAllModelFiles == null) {
+            final List<ModelFile> allModels = new ArrayList<>();
+            // The update model has the highest precedence.
+            if (new File(UPDATED_MODEL_FILE_PATH).exists()) {
+                final ModelFile updatedModel = ModelFile.fromPath(UPDATED_MODEL_FILE_PATH);
+                if (updatedModel != null) {
+                    allModels.add(updatedModel);
+                }
+            }
+            // Factory models should never have overlapping locales, so the order doesn't matter.
             final File modelsDir = new File(MODEL_DIR);
             if (modelsDir.exists() && modelsDir.isDirectory()) {
-                final File[] models = modelsDir.listFiles();
+                final File[] modelFiles = modelsDir.listFiles();
                 final Pattern modelFilenamePattern = Pattern.compile(MODEL_FILE_REGEX);
-                final int size = models.length;
-                for (int i = 0; i < size; i++) {
-                    final File modelFile = models[i];
+                for (File modelFile : modelFiles) {
                     final Matcher matcher = modelFilenamePattern.matcher(modelFile.getName());
                     if (matcher.matches() && modelFile.isFile()) {
-                        final String language = matcher.group(1);
-                        final Locale locale = Locale.forLanguageTag(language);
-                        modelFilePaths.put(locale, modelFile.getAbsolutePath());
+                        final ModelFile model = ModelFile.fromPath(modelFile.getAbsolutePath());
+                        if (model != null) {
+                            allModels.add(model);
+                        }
                     }
                 }
             }
-            mModelFilePaths = modelFilePaths;
+            mAllModelFiles = allModels;
         }
-        return mModelFilePaths;
-    }
-
-    @Nullable
-    private Locale getUpdatedModelLocale() {
-        try {
-            final ParcelFileDescriptor updateFd = ParcelFileDescriptor.open(
-                    new File(UPDATED_MODEL_FILE_PATH), ParcelFileDescriptor.MODE_READ_ONLY);
-            final Locale locale = Locale.forLanguageTag(
-                    SmartSelection.getLanguage(updateFd.getFd()));
-            closeAndLogError(updateFd);
-            return locale;
-        } catch (FileNotFoundException e) {
-            return null;
-        }
+        return mAllModelFiles;
     }
 
     private TextClassification createClassificationResult(
@@ -520,6 +461,95 @@
     }
 
     /**
+     * Describes TextClassifier model files on disk.
+     */
+    private static final class ModelFile {
+
+        private final String mPath;
+        private final String mName;
+        private final int mVersion;
+        private final List<Locale> mSupportedLocales;
+
+        /** Returns null if the path did not point to a compatible model. */
+        static @Nullable ModelFile fromPath(String path) {
+            final File file = new File(path);
+            try {
+                final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open(
+                        file, ParcelFileDescriptor.MODE_READ_ONLY);
+                final int version = SmartSelection.getVersion(modelFd.getFd());
+                final String supportedLocalesStr = SmartSelection.getLanguages(modelFd.getFd());
+                if (supportedLocalesStr.isEmpty()) {
+                    Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());
+                    return null;
+                }
+                final List<Locale> supportedLocales = new ArrayList<>();
+                for (String langTag : supportedLocalesStr.split(",")) {
+                    supportedLocales.add(Locale.forLanguageTag(langTag));
+                }
+                closeAndLogError(modelFd);
+                return new ModelFile(path, file.getName(), version, supportedLocales);
+            } catch (FileNotFoundException e) {
+                Log.e(DEFAULT_LOG_TAG, "Failed to peek " + file.getAbsolutePath(), e);
+                return null;
+            }
+        }
+
+        /** The absolute path to the model file. */
+        String getPath() {
+            return mPath;
+        }
+
+        /** A name to use for signature generation. Effectively the name of the model file. */
+        String getName() {
+            return mName;
+        }
+
+        /** Returns the version tag in the model's metadata. */
+        int getVersion() {
+            return mVersion;
+        }
+
+        /** Returns whether the language supports any language in the given ranges. */
+        boolean isAnyLanguageSupported(List<Locale.LanguageRange> languageRanges) {
+            return Locale.lookup(languageRanges, mSupportedLocales) != null;
+        }
+
+        /** All locales supported by the model. */
+        List<Locale> getSupportedLocales() {
+            return Collections.unmodifiableList(mSupportedLocales);
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            } else if (other == null || !ModelFile.class.isAssignableFrom(other.getClass())) {
+                return false;
+            } else {
+                final ModelFile otherModel = (ModelFile) other;
+                return mPath.equals(otherModel.mPath);
+            }
+        }
+
+        @Override
+        public String toString() {
+            final StringJoiner localesJoiner = new StringJoiner(",");
+            for (Locale locale : mSupportedLocales) {
+                localesJoiner.add(locale.toLanguageTag());
+            }
+            return String.format(Locale.US, "ModelFile { path=%s name=%s version=%d locales=%s }",
+                    mPath, mName, mVersion, localesJoiner.toString());
+        }
+
+        private ModelFile(String path, String name, int version, List<Locale> supportedLocales) {
+            mPath = path;
+            mName = name;
+            mVersion = version;
+            mSupportedLocales = supportedLocales;
+        }
+    }
+
+    /**
      * Creates intents based on the classification type.
      */
     static final class IntentFactory {
@@ -541,7 +571,7 @@
                 case TextClassifier.TYPE_EMAIL:
                     return createForEmail(text);
                 case TextClassifier.TYPE_PHONE:
-                    return createForPhone(text);
+                    return createForPhone(context, text);
                 case TextClassifier.TYPE_ADDRESS:
                     return createForAddress(text);
                 case TextClassifier.TYPE_URL:
@@ -573,15 +603,23 @@
         }
 
         @NonNull
-        private static List<Intent> createForPhone(String text) {
-            return Arrays.asList(
-                    new Intent(Intent.ACTION_DIAL)
-                            .setData(Uri.parse(String.format("tel:%s", text))),
-                    new Intent(Intent.ACTION_INSERT_OR_EDIT)
-                            .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
-                            .putExtra(ContactsContract.Intents.Insert.PHONE, text),
-                    new Intent(Intent.ACTION_SENDTO)
-                            .setData(Uri.parse(String.format("smsto:%s", text))));
+        private static List<Intent> createForPhone(Context context, String text) {
+            final List<Intent> intents = new ArrayList<>();
+            final UserManager userManager = context.getSystemService(UserManager.class);
+            final Bundle userRestrictions = userManager != null
+                    ? userManager.getUserRestrictions() : new Bundle();
+            if (!userRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS, false)) {
+                intents.add(new Intent(Intent.ACTION_DIAL)
+                        .setData(Uri.parse(String.format("tel:%s", text))));
+            }
+            intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
+                    .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
+                    .putExtra(ContactsContract.Intents.Insert.PHONE, text));
+            if (!userRestrictions.getBoolean(UserManager.DISALLOW_SMS, false)) {
+                intents.add(new Intent(Intent.ACTION_SENDTO)
+                        .setData(Uri.parse(String.format("smsto:%s", text))));
+            }
+            return intents;
         }
 
         @NonNull
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index ede5211..d866d13 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -198,7 +198,11 @@
         /**
          * Create a new TextLink.
          *
-         * @throws IllegalArgumentException if entityScores is null or empty.
+         * @param start The start index of the identified subsequence
+         * @param end The end index of the identified subsequence
+         * @param entityScores A mapping of entity type to confidence score
+         *
+         * @throws IllegalArgumentException if entityScores is null or empty
          */
         TextLink(int start, int end, Map<String, Float> entityScores) {
             Preconditions.checkNotNull(entityScores);
@@ -212,7 +216,7 @@
         /**
          * Returns the start index of this link in the original text.
          *
-         * @return the start index.
+         * @return the start index
          */
         public int getStart() {
             return mStart;
@@ -221,7 +225,7 @@
         /**
          * Returns the end index of this link in the original text.
          *
-         * @return the end index.
+         * @return the end index
          */
         public int getEnd() {
             return mEnd;
@@ -230,7 +234,7 @@
         /**
          * Returns the number of entity types that have confidence scores.
          *
-         * @return the entity count.
+         * @return the entity count
          */
         public int getEntityCount() {
             return mEntityScores.getEntities().size();
@@ -239,7 +243,7 @@
         /**
          * Returns the entity type at a given index. Entity types are sorted by confidence.
          *
-         * @return the entity type at the provided index.
+         * @return the entity type at the provided index
          */
         @NonNull public @EntityType String getEntity(int index) {
             return mEntityScores.getEntities().get(index);
@@ -248,7 +252,7 @@
         /**
          * Returns the confidence score for a particular entity type.
          *
-         * @param entityType the entity type.
+         * @param entityType the entity type
          */
         public @FloatRange(from = 0.0, to = 1.0) float getConfidenceScore(
                 @EntityType String entityType) {
@@ -371,7 +375,7 @@
 
         /**
          * @return ordered list of locale preferences that can be used to disambiguate
-         *      the provided text.
+         *      the provided text
          */
         @Nullable
         public LocaleList getDefaultLocales() {
@@ -389,7 +393,7 @@
 
         /**
          * @return the strategy for resolving conflictswhen applying generated links to text that
-         * already have links.
+         * already have links
          *
          * @see #APPLY_STRATEGY_IGNORE
          * @see #APPLY_STRATEGY_REPLACE
@@ -494,7 +498,7 @@
         /**
          * Create a new TextLinks.Builder.
          *
-         * @param fullText The full text to annotate with links.
+         * @param fullText The full text to annotate with links
          */
         public Builder(@NonNull String fullText) {
             mFullText = Preconditions.checkNotNull(fullText);
@@ -504,7 +508,7 @@
         /**
          * Adds a TextLink.
          *
-         * @return this instance.
+         * @return this instance
          *
          * @throws IllegalArgumentException if entityScores is null or empty.
          */
@@ -524,7 +528,7 @@
         /**
          * Constructs a TextLinks instance.
          *
-         * @return the constructed TextLinks.
+         * @return the constructed TextLinks
          */
         public TextLinks build() {
             return new TextLinks(mFullText, mLinks);
diff --git a/core/java/android/view/textclassifier/logging/DefaultLogger.java b/core/java/android/view/textclassifier/logging/DefaultLogger.java
index 6b84835..f510879 100644
--- a/core/java/android/view/textclassifier/logging/DefaultLogger.java
+++ b/core/java/android/view/textclassifier/logging/DefaultLogger.java
@@ -17,7 +17,6 @@
 package android.view.textclassifier.logging;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.Context;
 import android.metrics.LogMaker;
 import android.util.Log;
@@ -27,8 +26,10 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.Preconditions;
 
+import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.StringJoiner;
 
 /**
  * Default Logger.
@@ -79,7 +80,7 @@
         Preconditions.checkNotNull(event);
         final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_SESSION)
                 .setType(getLogType(event))
-                .setSubtype(MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL)
+                .setSubtype(getLogSubType(event))
                 .setPackageName(event.getPackageName())
                 .addTaggedData(START_EVENT_DELTA, event.getDurationSinceSessionStart())
                 .addTaggedData(PREV_EVENT_DELTA, event.getDurationSincePreviousEvent())
@@ -136,6 +137,17 @@
         }
     }
 
+    private static int getLogSubType(SelectionEvent event) {
+        switch (event.getInvocationMethod()) {
+            case SelectionEvent.INVOCATION_MANUAL:
+                return MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL;
+            case SelectionEvent.INVOCATION_LINK:
+                return MetricsEvent.TEXT_SELECTION_INVOCATION_LINK;
+            default:
+                return MetricsEvent.TEXT_SELECTION_INVOCATION_UNKNOWN;
+        }
+    }
+
     private static String getLogTypeString(int logType) {
         switch (logType) {
             case MetricsEvent.ACTION_TEXT_SELECTION_OVERTYPE:
@@ -175,6 +187,17 @@
         }
     }
 
+    private static String getLogSubTypeString(int logSubType) {
+        switch (logSubType) {
+            case MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL:
+                return "MANUAL";
+            case MetricsEvent.TEXT_SELECTION_INVOCATION_LINK:
+                return "LINK";
+            default:
+                return UNKNOWN;
+        }
+    }
+
     private static void debugLog(LogMaker log) {
         if (!DEBUG_LOG_ENABLED) return;
 
@@ -192,6 +215,7 @@
         final String model = Objects.toString(log.getTaggedData(MODEL_NAME), UNKNOWN);
         final String entity = Objects.toString(log.getTaggedData(ENTITY_TYPE), UNKNOWN);
         final String type = getLogTypeString(log.getType());
+        final String subType = getLogSubTypeString(log.getSubtype());
         final int smartStart = Integer.parseInt(
                 Objects.toString(log.getTaggedData(SMART_START), ZERO));
         final int smartEnd = Integer.parseInt(
@@ -201,8 +225,9 @@
         final int eventEnd = Integer.parseInt(
                 Objects.toString(log.getTaggedData(EVENT_END), ZERO));
 
-        Log.d(LOG_TAG, String.format("%2d: %s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
-                index, type, entity, eventStart, eventEnd, smartStart, smartEnd, widget, model));
+        Log.d(LOG_TAG, String.format("%2d: %s/%s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
+                index, type, subType, entity, eventStart, eventEnd, smartStart, smartEnd, widget,
+                model));
     }
 
     /**
@@ -210,12 +235,16 @@
      */
     public static String createSignature(
             String text, int start, int end, Context context, int modelVersion,
-            @Nullable Locale locale) {
+            List<Locale> locales) {
         Preconditions.checkNotNull(text);
         Preconditions.checkNotNull(context);
-        final String modelName = (locale != null)
-                ? String.format(Locale.US, "%s_v%d", locale.toLanguageTag(), modelVersion)
-                : "";
+        Preconditions.checkNotNull(locales);
+        final StringJoiner localesJoiner = new StringJoiner(",");
+        for (Locale locale : locales) {
+            localesJoiner.add(locale.toLanguageTag());
+        }
+        final String modelName = String.format(Locale.US, "%s_v%d", localesJoiner.toString(),
+                modelVersion);
         final int hash = Objects.hash(text, start, end, context.getPackageName());
         return SignatureParser.createSignature(CLASSIFIER_ID, modelName, hash);
     }
@@ -242,9 +271,9 @@
 
         static String getModelName(String signature) {
             Preconditions.checkNotNull(signature);
-            final int start = signature.indexOf("|");
+            final int start = signature.indexOf("|") + 1;
             final int end = signature.indexOf("|", start);
-            if (start >= 0 && end >= start) {
+            if (start >= 1 && end >= start) {
                 return signature.substring(start, end);
             }
             return "";
diff --git a/core/java/android/view/textclassifier/logging/Logger.java b/core/java/android/view/textclassifier/logging/Logger.java
index 40e4d8c..4448b2b 100644
--- a/core/java/android/view/textclassifier/logging/Logger.java
+++ b/core/java/android/view/textclassifier/logging/Logger.java
@@ -71,6 +71,7 @@
     public static final String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
     public static final String WIDGET_UNKNOWN = "unknown";
 
+    private @SelectionEvent.InvocationMethod int mInvocationMethod;
     private SelectionEvent mPrevEvent;
     private SelectionEvent mSmartEvent;
     private SelectionEvent mStartEvent;
@@ -124,16 +125,19 @@
     /**
      * Logs a "selection started" event.
      *
+     * @param invocationMethod  the way the selection was triggered
      * @param start  the token index of the selected token
      */
-    public final void logSelectionStartedEvent(int start) {
+    public final void logSelectionStartedEvent(
+            @SelectionEvent.InvocationMethod int invocationMethod, int start) {
         if (mConfig == null) {
             return;
         }
 
+        mInvocationMethod = invocationMethod;
         logEvent(new SelectionEvent(
                 start, start + 1, SelectionEvent.EVENT_SELECTION_STARTED,
-                TextClassifier.TYPE_UNKNOWN, NO_SIGNATURE, mConfig));
+                TextClassifier.TYPE_UNKNOWN, mInvocationMethod, NO_SIGNATURE, mConfig));
     }
 
     /**
@@ -152,7 +156,7 @@
 
         logEvent(new SelectionEvent(
                 start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
-                TextClassifier.TYPE_UNKNOWN, NO_SIGNATURE, mConfig));
+                TextClassifier.TYPE_UNKNOWN, mInvocationMethod, NO_SIGNATURE, mConfig));
     }
 
     /**
@@ -179,7 +183,7 @@
         final String signature = classification.getSignature();
         logEvent(new SelectionEvent(
                 start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
-                entityType, signature, mConfig));
+                entityType, mInvocationMethod, signature, mConfig));
     }
 
     /**
@@ -213,7 +217,8 @@
                 ? selection.getEntity(0)
                 : TextClassifier.TYPE_UNKNOWN;
         final String signature = selection.getSignature();
-        logEvent(new SelectionEvent(start, end, eventType, entityType, signature, mConfig));
+        logEvent(new SelectionEvent(start, end, eventType, entityType, mInvocationMethod, signature,
+                mConfig));
     }
 
     /**
@@ -234,7 +239,8 @@
         }
 
         logEvent(new SelectionEvent(
-                start, end, actionType, TextClassifier.TYPE_UNKNOWN, NO_SIGNATURE, mConfig));
+                start, end, actionType, TextClassifier.TYPE_UNKNOWN, mInvocationMethod,
+                NO_SIGNATURE, mConfig));
     }
 
     /**
@@ -265,7 +271,8 @@
                 ? classification.getEntity(0)
                 : TextClassifier.TYPE_UNKNOWN;
         final String signature = classification.getSignature();
-        logEvent(new SelectionEvent(start, end, actionType, entityType, signature, mConfig));
+        logEvent(new SelectionEvent(start, end, actionType, entityType, mInvocationMethod,
+                signature, mConfig));
     }
 
     private void logEvent(@NonNull SelectionEvent event) {
diff --git a/core/java/android/view/textclassifier/logging/SelectionEvent.java b/core/java/android/view/textclassifier/logging/SelectionEvent.java
index f40b655..a8de308 100644
--- a/core/java/android/view/textclassifier/logging/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/logging/SelectionEvent.java
@@ -98,6 +98,16 @@
     /** Something else other than User or the default TextClassifier triggered a selection. */
     public static final int EVENT_AUTO_SELECTION = 5;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({INVOCATION_MANUAL, INVOCATION_LINK})
+    public @interface InvocationMethod {}
+
+    /** Selection was invoked by the user long pressing, double tapping, or dragging to select. */
+    public static final int INVOCATION_MANUAL = 1;
+    /** Selection was invoked by the user tapping on a link. */
+    public static final int INVOCATION_LINK = 2;
+
     private final int mAbsoluteStart;
     private final int mAbsoluteEnd;
     private final @EventType int mEventType;
@@ -105,6 +115,7 @@
     @Nullable private final String mWidgetVersion;
     private final String mPackageName;
     private final String mWidgetType;
+    private final @InvocationMethod int mInvocationMethod;
 
     // These fields should only be set by creator of a SelectionEvent.
     private String mSignature;
@@ -121,7 +132,7 @@
     SelectionEvent(
             int start, int end,
             @EventType int eventType, @EntityType String entityType,
-            String signature, Logger.Config config) {
+            @InvocationMethod int invocationMethod, String signature, Logger.Config config) {
         Preconditions.checkArgument(end >= start, "end cannot be less than start");
         mAbsoluteStart = start;
         mAbsoluteEnd = end;
@@ -132,6 +143,7 @@
         mWidgetVersion = config.getWidgetVersion();
         mPackageName = Preconditions.checkNotNull(config.getPackageName());
         mWidgetType = Preconditions.checkNotNull(config.getWidgetType());
+        mInvocationMethod = invocationMethod;
     }
 
     int getAbsoluteStart() {
@@ -180,6 +192,13 @@
     }
 
     /**
+     * Returns the way the selection mode was invoked.
+     */
+    public @InvocationMethod int getInvocationMethod() {
+        return mInvocationMethod;
+    }
+
+    /**
      * Returns the signature of the text classifier result associated with this event.
      */
     public String getSignature() {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 7bb0db1..9988661 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1299,6 +1299,16 @@
             if (mSelectionModifierCursorController != null) {
                 mSelectionModifierCursorController.resetTouchOffsets();
             }
+
+            ensureNoSelectionIfNonSelectable();
+        }
+    }
+
+    private void ensureNoSelectionIfNonSelectable() {
+        // This could be the case if a TextLink has been tapped.
+        if (!mTextView.textCanBeSelected() && mTextView.hasSelection()) {
+            Selection.setSelection((Spannable) mTextView.getText(),
+                    mTextView.length(), mTextView.length());
         }
     }
 
@@ -1382,6 +1392,8 @@
 
             // Don't leave us in the middle of a batch edit. Same as in onFocusChanged
             ensureEndedBatchEdit();
+
+            ensureNoSelectionIfNonSelectable();
         }
     }
 
@@ -1745,16 +1757,19 @@
             highlight = null;
         }
 
+        if (mSelectionActionModeHelper != null) {
+            mSelectionActionModeHelper.onDraw(canvas);
+            if (mSelectionActionModeHelper.isDrawingHighlight()) {
+                highlight = null;
+            }
+        }
+
         if (mTextView.canHaveDisplayList() && canvas.isHardwareAccelerated()) {
             drawHardwareAccelerated(canvas, layout, highlight, highlightPaint,
                     cursorOffsetVertical);
         } else {
             layout.draw(canvas, highlight, highlightPaint, cursorOffsetVertical);
         }
-
-        if (mSelectionActionModeHelper != null) {
-            mSelectionActionModeHelper.onDraw(canvas);
-        }
     }
 
     private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highlight,
@@ -4171,7 +4186,7 @@
                         primaryHorizontal,
                         layout.getLineTop(line),
                         primaryHorizontal,
-                        layout.getLineBottom(line) - layout.getLineBottom(line) + mHandleHeight);
+                        layout.getLineBottom(line) + mHandleHeight);
             }
             // Take TextView's padding and scroll into account.
             int textHorizontalOffset = mTextView.viewportToContentHorizontalOffset();
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 012b918..3aae849 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -904,6 +904,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @Override
     protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
         // Apply defaults, so as to remove UNDEFINED values
@@ -919,6 +922,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @Override
     protected void onDebugDraw(Canvas canvas) {
         Paint paint = new Paint();
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 7a4c800..8836561 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -18,8 +18,10 @@
 
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
+import android.annotation.TestApi;
 import android.annotation.UiThread;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -269,4 +271,46 @@
         return mWindow.getContentView().findViewById(
                 com.android.internal.R.id.magnifier_image);
     }
+
+    /**
+     * @return the content being currently displayed in the magnifier, as bitmap
+     *
+     * @hide
+     */
+    @TestApi
+    public Bitmap getContent() {
+        return mBitmap;
+    }
+
+    /**
+     * @return the position of the magnifier window relative to the screen
+     *
+     * @hide
+     */
+    @TestApi
+    public Rect getWindowPositionOnScreen() {
+        final int[] viewLocationOnScreen = new int[2];
+        mView.getLocationOnScreen(viewLocationOnScreen);
+        final int[] viewLocationInSurface = new int[2];
+        mView.getLocationInSurface(viewLocationInSurface);
+
+        final int left = mWindowCoords.x + viewLocationOnScreen[0] - viewLocationInSurface[0];
+        final int top = mWindowCoords.y + viewLocationOnScreen[1] - viewLocationInSurface[1];
+        return new Rect(left, top, left + mWindow.getWidth(), top + mWindow.getHeight());
+    }
+
+    /**
+     * @return the size of the magnifier window in dp
+     *
+     * @hide
+     */
+    @TestApi
+    public static PointF getMagnifierDefaultSize() {
+        final Resources resources = Resources.getSystem();
+        final float density = resources.getDisplayMetrics().density;
+        final PointF size = new PointF();
+        size.x = resources.getDimension(com.android.internal.R.dimen.magnifier_width) / density;
+        size.y = resources.getDimension(com.android.internal.R.dimen.magnifier_height) / density;
+        return size;
+    }
 }
diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS
index 8f0d02f..2789bae 100644
--- a/core/java/android/widget/OWNERS
+++ b/core/java/android/widget/OWNERS
@@ -1,12 +1,9 @@
 per-file TextView.java = siyamed@google.com
 per-file TextView.java = nona@google.com
 per-file TextView.java = clarabayarri@google.com
-per-file TextView.java = toki@google.com
 per-file EditText.java = siyamed@google.com
 per-file EditText.java = nona@google.com
 per-file EditText.java = clarabayarri@google.com
-per-file EditText.java = toki@google.com
 per-file Editor.java = siyamed@google.com
 per-file Editor.java = nona@google.com
 per-file Editor.java = clarabayarri@google.com
-per-file Editor.java = toki@google.com
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 2e354c1..6ab09d6 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -93,7 +93,7 @@
 
         if (SMART_SELECT_ANIMATION_ENABLED) {
             mSmartSelectSprite = new SmartSelectSprite(mTextView.getContext(),
-                    mTextView::invalidate);
+                    editor.getTextView().mHighlightColor, mTextView::invalidate);
         } else {
             mSmartSelectSprite = null;
         }
@@ -111,7 +111,8 @@
         mSelectionTracker.onOriginalSelection(
                 getText(mTextView),
                 mTextView.getSelectionStart(),
-                mTextView.getSelectionEnd());
+                mTextView.getSelectionEnd(),
+                false /*isLink*/);
         cancelAsyncTask();
         if (skipTextClassification()) {
             startSelectionActionMode(null);
@@ -134,7 +135,11 @@
      * Starts Link ActionMode.
      */
     public void startLinkActionModeAsync(TextLinks.TextLink textLink) {
-        //TODO: tracking/logging
+        mSelectionTracker.onOriginalSelection(
+                getText(mTextView),
+                mTextView.getSelectionStart(),
+                mTextView.getSelectionEnd(),
+                true /*isLink*/);
         cancelAsyncTask();
         if (skipTextClassification()) {
             startLinkActionMode(null);
@@ -200,11 +205,15 @@
     }
 
     public void onDraw(final Canvas canvas) {
-        if (mSmartSelectSprite != null) {
+        if (isDrawingHighlight() && mSmartSelectSprite != null) {
             mSmartSelectSprite.draw(canvas);
         }
     }
 
+    public boolean isDrawingHighlight() {
+        return mSmartSelectSprite != null && mSmartSelectSprite.isAnimationActive();
+    }
+
     private void cancelAsyncTask() {
         if (mTextClassificationAsyncTask != null) {
             mTextClassificationAsyncTask.cancel(true);
@@ -483,7 +492,8 @@
         /**
          * Called when the original selection happens, before smart selection is triggered.
          */
-        public void onOriginalSelection(CharSequence text, int selectionStart, int selectionEnd) {
+        public void onOriginalSelection(
+                CharSequence text, int selectionStart, int selectionEnd, boolean isLink) {
             // If we abandoned a selection and created a new one very shortly after, we may still
             // have a pending request to log ABANDON, which we flush here.
             mDelayedLogAbandon.flush();
@@ -492,7 +502,8 @@
             mOriginalEnd = mSelectionEnd = selectionEnd;
             mAllowReset = false;
             maybeInvalidateLogger();
-            mLogger.logSelectionStarted(text, selectionStart);
+            mLogger.logSelectionStarted(text, selectionStart,
+                    isLink ? SelectionEvent.INVOCATION_LINK : SelectionEvent.INVOCATION_MANUAL);
         }
 
         /**
@@ -675,7 +686,9 @@
             return Logger.WIDGET_UNSELECTABLE_TEXTVIEW;
         }
 
-        public void logSelectionStarted(CharSequence text, int index) {
+        public void logSelectionStarted(
+                CharSequence text, int index,
+                @SelectionEvent.InvocationMethod int invocationMethod) {
             try {
                 Preconditions.checkNotNull(text);
                 Preconditions.checkArgumentInRange(index, 0, text.length(), "index");
@@ -684,7 +697,7 @@
                 }
                 mTokenIterator.setText(mText);
                 mStartIndex = index;
-                mLogger.logSelectionStartedEvent(0);
+                mLogger.logSelectionStartedEvent(invocationMethod, 0);
             } catch (Exception e) {
                 // Avoid crashes due to logging.
                 Log.d(LOG_TAG, e.getMessage());
diff --git a/core/java/android/widget/SmartSelectSprite.java b/core/java/android/widget/SmartSelectSprite.java
index a391c6e..9a84f69 100644
--- a/core/java/android/widget/SmartSelectSprite.java
+++ b/core/java/android/widget/SmartSelectSprite.java
@@ -26,7 +26,6 @@
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.content.Context;
-import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Path;
@@ -36,7 +35,6 @@
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.Shape;
 import android.text.Layout;
-import android.util.TypedValue;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
@@ -54,21 +52,15 @@
 final class SmartSelectSprite {
 
     private static final int EXPAND_DURATION = 300;
-    private static final int CORNER_DURATION = 150;
-    private static final float STROKE_WIDTH_DP = 1.5F;
-
-    // GBLUE700
-    @ColorInt
-    private static final int DEFAULT_STROKE_COLOR = 0xFF3367D6;
+    private static final int CORNER_DURATION = 50;
 
     private final Interpolator mExpandInterpolator;
     private final Interpolator mCornerInterpolator;
-    private final float mStrokeWidth;
 
     private Animator mActiveAnimator = null;
     private final Runnable mInvalidator;
     @ColorInt
-    private final int mStrokeColor;
+    private final int mFillColor;
 
     static final Comparator<RectF> RECTANGLE_COMPARATOR = Comparator
             .<RectF>comparingDouble(e -> e.bottom)
@@ -124,26 +116,11 @@
             return expansionDirection * -1;
         }
 
-        @Retention(SOURCE)
-        @IntDef({RectangleBorderType.FIT, RectangleBorderType.OVERSHOOT})
-        private @interface RectangleBorderType {
-        /** A rectangle which, fully expanded, fits inside of its bounding rectangle. */
-        int FIT = 0;
-        /**
-         * A rectangle which, when fully expanded, clips outside of its bounding rectangle so that
-         * its edges no longer appear rounded.
-         */
-        int OVERSHOOT = 1;
-        }
-
-        private final float mStrokeWidth;
         private final RectF mBoundingRectangle;
         private float mRoundRatio = 1.0f;
         private final @ExpansionDirection int mExpansionDirection;
-        private final @RectangleBorderType int mRectangleBorderType;
 
         private final RectF mDrawRect = new RectF();
-        private final RectF mClipRect = new RectF();
         private final Path mClipPath = new Path();
 
         /** How offset the left edge of the rectangle is from the left side of the bounding box. */
@@ -159,13 +136,9 @@
         private RoundedRectangleShape(
                 final RectF boundingRectangle,
                 final @ExpansionDirection int expansionDirection,
-                final @RectangleBorderType int rectangleBorderType,
-                final boolean inverted,
-                final float strokeWidth) {
+                final boolean inverted) {
             mBoundingRectangle = new RectF(boundingRectangle);
             mBoundingWidth = boundingRectangle.width();
-            mRectangleBorderType = rectangleBorderType;
-            mStrokeWidth = strokeWidth;
             mInverted = inverted && expansionDirection != ExpansionDirection.CENTER;
 
             if (inverted) {
@@ -182,14 +155,8 @@
         }
 
         /*
-         * In order to achieve the "rounded rectangle hits the wall" effect, the drawing needs to be
-         * done in two passes. In this context, the wall is the bounding rectangle and in the first
-         * pass we need to draw the rounded rectangle (expanded and with a corner radius as per
-         * object properties) clipped by the bounding box. If the rounded rectangle expands outside
-         * of the bounding box, one more pass needs to be done, as there will now be a hole in the
-         * rounded rectangle where it "flattened" against the bounding box. In order to fill just
-         * this hole, we need to draw the bounding box, but clip it with the rounded rectangle and
-         * this will connect the missing pieces.
+         * In order to achieve the "rounded rectangle hits the wall" effect, we draw an expanding
+         * rounded rectangle that is clipped by the bounding box of the selected text.
          */
         @Override
         public void draw(Canvas canvas, Paint paint) {
@@ -201,31 +168,8 @@
             final float adjustedCornerRadius = getAdjustedCornerRadius();
 
             mDrawRect.set(mBoundingRectangle);
-            mDrawRect.left = mBoundingRectangle.left + mLeftBoundary;
-            mDrawRect.right = mBoundingRectangle.left + mRightBoundary;
-
-            if (mRectangleBorderType == RectangleBorderType.OVERSHOOT) {
-                mDrawRect.left -= cornerRadius / 2;
-                mDrawRect.right += cornerRadius / 2;
-            } else {
-                switch (mExpansionDirection) {
-                    case ExpansionDirection.CENTER:
-                        break;
-                    case ExpansionDirection.LEFT:
-                        mDrawRect.right += cornerRadius;
-                        break;
-                    case ExpansionDirection.RIGHT:
-                        mDrawRect.left -= cornerRadius;
-                        break;
-                }
-            }
-
-            canvas.save();
-            mClipRect.set(mBoundingRectangle);
-            mClipRect.inset(-mStrokeWidth / 2, -mStrokeWidth / 2);
-            canvas.clipRect(mClipRect);
-            canvas.drawRoundRect(mDrawRect, adjustedCornerRadius, adjustedCornerRadius, paint);
-            canvas.restore();
+            mDrawRect.left = mBoundingRectangle.left + mLeftBoundary - cornerRadius / 2;
+            mDrawRect.right = mBoundingRectangle.left + mRightBoundary + cornerRadius / 2;
 
             canvas.save();
             mClipPath.reset();
@@ -272,11 +216,7 @@
         }
 
         private float getBoundingWidth() {
-            if (mRectangleBorderType == RectangleBorderType.OVERSHOOT) {
-                return (int) (mBoundingRectangle.width() + getCornerRadius());
-            } else {
-                return mBoundingRectangle.width();
-            }
+            return (int) (mBoundingRectangle.width() + getCornerRadius());
         }
 
     }
@@ -388,19 +328,20 @@
     }
 
     /**
-     * @param context     the {@link Context} in which the animation will run
+     * @param context the {@link Context} in which the animation will run
+     * @param highlightColor the highlight color of the underlying {@link TextView}
      * @param invalidator a {@link Runnable} which will be called every time the animation updates,
      *                    indicating that the view drawing the animation should invalidate itself
      */
-    SmartSelectSprite(final Context context, final Runnable invalidator) {
+    SmartSelectSprite(final Context context, @ColorInt int highlightColor,
+            final Runnable invalidator) {
         mExpandInterpolator = AnimationUtils.loadInterpolator(
                 context,
                 android.R.interpolator.fast_out_slow_in);
         mCornerInterpolator = AnimationUtils.loadInterpolator(
                 context,
                 android.R.interpolator.fast_out_linear_in);
-        mStrokeWidth = dpToPixel(context, STROKE_WIDTH_DP);
-        mStrokeColor = getStrokeColor(context);
+        mFillColor = highlightColor;
         mInvalidator = Preconditions.checkNotNull(invalidator);
     }
 
@@ -437,17 +378,14 @@
         RectangleWithTextSelectionLayout centerRectangle = null;
 
         int startingOffset = 0;
-        int startingRectangleIndex = 0;
-        for (int index = 0; index < rectangleCount; ++index) {
-            final RectangleWithTextSelectionLayout rectangleWithTextSelectionLayout =
-                    destinationRectangles.get(index);
+        for (RectangleWithTextSelectionLayout rectangleWithTextSelectionLayout :
+                destinationRectangles) {
             final RectF rectangle = rectangleWithTextSelectionLayout.getRectangle();
             if (contains(rectangle, start)) {
                 centerRectangle = rectangleWithTextSelectionLayout;
                 break;
             }
             startingOffset += rectangle.width();
-            ++startingRectangleIndex;
         }
 
         if (centerRectangle == null) {
@@ -459,9 +397,6 @@
         final @RoundedRectangleShape.ExpansionDirection int[] expansionDirections =
                 generateDirections(centerRectangle, destinationRectangles);
 
-        final @RoundedRectangleShape.RectangleBorderType int[] rectangleBorderTypes =
-                generateBorderTypes(rectangleCount);
-
         for (int index = 0; index < rectangleCount; ++index) {
             final RectangleWithTextSelectionLayout rectangleWithTextSelectionLayout =
                     destinationRectangles.get(index);
@@ -469,10 +404,8 @@
             final RoundedRectangleShape shape = new RoundedRectangleShape(
                     rectangle,
                     expansionDirections[index],
-                    rectangleBorderTypes[index],
                     rectangleWithTextSelectionLayout.getTextSelectionLayout()
-                            == Layout.TEXT_SELECTION_LAYOUT_RIGHT_TO_LEFT,
-                    mStrokeWidth);
+                            == Layout.TEXT_SELECTION_LAYOUT_RIGHT_TO_LEFT);
             cornerAnimators.add(createCornerAnimator(shape, updateListener));
             shapes.add(shape);
         }
@@ -480,44 +413,23 @@
         final RectangleList rectangleList = new RectangleList(shapes);
         final ShapeDrawable shapeDrawable = new ShapeDrawable(rectangleList);
 
-        final float startingOffsetLeft;
-        final float startingOffsetRight;
-
-        final RoundedRectangleShape startingRectangleShape = shapes.get(startingRectangleIndex);
-        final float cornerRadius = startingRectangleShape.getCornerRadius();
-        if (startingRectangleShape.mRectangleBorderType
-                == RoundedRectangleShape.RectangleBorderType.FIT) {
-            switch (startingRectangleShape.mExpansionDirection) {
-                case RoundedRectangleShape.ExpansionDirection.LEFT:
-                    startingOffsetLeft = startingOffsetRight = startingOffset - cornerRadius / 2;
-                    break;
-                case RoundedRectangleShape.ExpansionDirection.RIGHT:
-                    startingOffsetLeft = startingOffsetRight = startingOffset + cornerRadius / 2;
-                    break;
-                case RoundedRectangleShape.ExpansionDirection.CENTER:  // fall through
-                default:
-                    startingOffsetLeft = startingOffset - cornerRadius / 2;
-                    startingOffsetRight = startingOffset + cornerRadius / 2;
-                    break;
-            }
-        } else {
-            startingOffsetLeft = startingOffsetRight = startingOffset;
-        }
-
         final Paint paint = shapeDrawable.getPaint();
-        paint.setColor(mStrokeColor);
-        paint.setStyle(Paint.Style.STROKE);
-        paint.setStrokeWidth(mStrokeWidth);
+        paint.setColor(mFillColor);
+        paint.setStyle(Paint.Style.FILL);
 
         mExistingRectangleList = rectangleList;
         mExistingDrawable = shapeDrawable;
 
-        mActiveAnimator = createAnimator(rectangleList, startingOffsetLeft, startingOffsetRight,
-                cornerAnimators, updateListener,
-                onAnimationEnd);
+        mActiveAnimator = createAnimator(rectangleList, startingOffset, startingOffset,
+                cornerAnimators, updateListener, onAnimationEnd);
         mActiveAnimator.start();
     }
 
+    /** Returns whether the sprite is currently animating. */
+    public boolean isAnimationActive() {
+        return mActiveAnimator != null && mActiveAnimator.isRunning();
+    }
+
     private Animator createAnimator(
             final RectangleList rectangleList,
             final float startingOffsetLeft,
@@ -625,36 +537,6 @@
         return result;
     }
 
-    private static @RoundedRectangleShape.RectangleBorderType int[] generateBorderTypes(
-            final int numberOfRectangles) {
-        final @RoundedRectangleShape.RectangleBorderType int[] result = new int[numberOfRectangles];
-
-        for (int i = 1; i < result.length - 1; ++i) {
-            result[i] = RoundedRectangleShape.RectangleBorderType.OVERSHOOT;
-        }
-
-        result[0] = RoundedRectangleShape.RectangleBorderType.FIT;
-        result[result.length - 1] = RoundedRectangleShape.RectangleBorderType.FIT;
-        return result;
-    }
-
-    private static float dpToPixel(final Context context, final float dp) {
-        return TypedValue.applyDimension(
-                TypedValue.COMPLEX_UNIT_DIP,
-                dp,
-                context.getResources().getDisplayMetrics());
-    }
-
-    @ColorInt
-    private static int getStrokeColor(final Context context) {
-        final TypedValue typedValue = new TypedValue();
-        final TypedArray array = context.obtainStyledAttributes(typedValue.data, new int[]{
-                android.R.attr.colorControlActivated});
-        final int result = array.getColor(0, DEFAULT_STROKE_COLOR);
-        array.recycle();
-        return result;
-    }
-
     /**
      * A variant of {@link RectF#contains(float, float)} that also allows the point to reside on
      * the right boundary of the rectangle.
diff --git a/core/java/android/widget/TextInputTimePickerView.java b/core/java/android/widget/TextInputTimePickerView.java
index 0cf8faa..e0261ad 100644
--- a/core/java/android/widget/TextInputTimePickerView.java
+++ b/core/java/android/widget/TextInputTimePickerView.java
@@ -174,7 +174,8 @@
      */
     void updateTextInputValues(int localizedHour, int minute, int amOrPm, boolean is24Hour,
             boolean hourFormatStartsAtZero) {
-        final String format = "%d";
+        final String hourFormat = "%d";
+        final String minuteFormat = "%02d";
 
         mIs24Hour = is24Hour;
         mHourFormatStartsAtZero = hourFormatStartsAtZero;
@@ -187,8 +188,8 @@
             mAmPmSpinner.setSelection(1);
         }
 
-        mHourEditText.setText(String.format(format, localizedHour));
-        mMinuteEditText.setText(String.format(format, minute));
+        mHourEditText.setText(String.format(hourFormat, localizedHour));
+        mMinuteEditText.setText(String.format(minuteFormat, minute));
 
         if (mErrorShowing) {
             validateInput();
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index b22ce5e..f6a69d9 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,157 +16,214 @@
 
 package com.android.internal.app;
 
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.annotation.Nullable;
+import android.animation.TimeAnimator;
 import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
-import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.RippleDrawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.OvalShape;
 import android.os.Bundle;
-import android.provider.Settings;
-import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.MathUtils;
-import android.view.Gravity;
-import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 
 public class PlatLogoActivity extends Activity {
-    public static final boolean FINISH = true;
+    FrameLayout layout;
+    TimeAnimator anim;
+    PBackground bg;
 
-    FrameLayout mLayout;
-    int mTapCount;
-    int mKeyCount;
-    PathInterpolator mInterpolator = new PathInterpolator(0f, 0f, 0.5f, 1f);
+    private class PBackground extends Drawable {
+        private float maxRadius, radius, x, y, dp;
+        private int[] palette;
+        private int darkest;
+        private float offset;
+
+        public PBackground() {
+            randomizePalette();
+        }
+
+        /**
+         * set inner radius of "p" logo
+         */
+        public void setRadius(float r) {
+            this.radius = Math.max(48*dp, r);
+        }
+
+        /**
+         * move the "p"
+         */
+        public void setPosition(float x, float y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        /**
+         * for animating the "p"
+         */
+        public void setOffset(float o) {
+            this.offset = o;
+        }
+
+        /**
+         * rough luminance calculation
+         * https://www.w3.org/TR/AERT/#color-contrast
+         */
+        public float lum(int rgb) {
+            return ((Color.red(rgb) * 299f) + (Color.green(rgb) * 587f) + (Color.blue(rgb) * 114f)) / 1000f;
+        }
+
+        /**
+         * create a random evenly-spaced color palette
+         * guaranteed to contrast!
+         */
+        public void randomizePalette() {
+            final int slots = 2 + (int)(Math.random() * 2);
+            float[] color = new float[] { (float) Math.random() * 360f, 1f, 1f };
+            palette = new int[slots];
+            darkest = 0;
+            for (int i=0; i<slots; i++) {
+                palette[i] = Color.HSVToColor(color);
+                color[0] += 360f/slots;
+                if (lum(palette[i]) < lum(palette[darkest])) darkest = i;
+            }
+
+            final StringBuilder str = new StringBuilder();
+            for (int c : palette) {
+                str.append(String.format("#%08x ", c));
+            }
+            Log.v("PlatLogoActivity", "color palette: " + str);
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            if (dp == 0) dp = getResources().getDisplayMetrics().density;
+            final float width = canvas.getWidth();
+            final float height = canvas.getHeight();
+            if (radius == 0) {
+                setPosition(width / 2, height / 2);
+                setRadius(width / 6);
+            }
+            final float inner_w = radius * 0.667f;
+
+            final Paint paint = new Paint();
+            paint.setStrokeCap(Paint.Cap.BUTT);
+            canvas.translate(x, y);
+
+            Path p = new Path();
+            p.moveTo(-radius, height);
+            p.lineTo(-radius, 0);
+            p.arcTo(-radius, -radius, radius, radius, -180, 270, false);
+            p.lineTo(-radius, radius);
+
+            float w = Math.max(canvas.getWidth(), canvas.getHeight())  * 1.414f;
+            paint.setStyle(Paint.Style.FILL);
+
+            int i=0;
+            while (w > radius*2 + inner_w*2) {
+                paint.setColor(0xFF000000 | palette[i % palette.length]);
+                // for a slower but more complete version:
+                // paint.setStrokeWidth(w);
+                // canvas.drawPath(p, paint);
+                canvas.drawOval(-w/2, -w/2, w/2, w/2, paint);
+                w -= inner_w * (1.1f + Math.sin((i/20f + offset) * 3.14159f));
+                i++;
+            }
+
+            // the innermost circle needs to be a constant color to avoid rapid flashing
+            paint.setColor(0xFF000000 | palette[(darkest+1) % palette.length]);
+            canvas.drawOval(-radius, -radius, radius, radius, paint);
+
+            p.reset();
+            p.moveTo(-radius, height);
+            p.lineTo(-radius, 0);
+            p.arcTo(-radius, -radius, radius, radius, -180, 270, false);
+            p.lineTo(-radius + inner_w, radius);
+
+            paint.setStyle(Paint.Style.STROKE);
+            paint.setStrokeWidth(inner_w*2);
+            paint.setColor(palette[darkest]);
+            canvas.drawPath(p, paint);
+            paint.setStrokeWidth(inner_w);
+            paint.setColor(0xFFFFFFFF);
+            canvas.drawPath(p, paint);
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter colorFilter) {
+
+        }
+
+        @Override
+        public int getOpacity() {
+            return 0;
+        }
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mLayout = new FrameLayout(this);
-        setContentView(mLayout);
+        layout = new FrameLayout(this);
+        setContentView(layout);
+
+        bg = new PBackground();
+        layout.setBackground(bg);
+
+        layout.setOnTouchListener(new View.OnTouchListener() {
+            final PointerCoords pc0 = new PointerCoords();
+            final PointerCoords pc1 = new PointerCoords();
+
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                switch (event.getActionMasked()) {
+                    case MotionEvent.ACTION_DOWN:
+                    case MotionEvent.ACTION_MOVE:
+                        if (event.getPointerCount() > 1) {
+                            event.getPointerCoords(0, pc0);
+                            event.getPointerCoords(1, pc1);
+                            bg.setRadius((float) Math.hypot(pc0.x - pc1.x, pc0.y - pc1.y) / 2f);
+                        }
+                        break;
+                }
+                return true;
+            }
+        });
     }
 
     @Override
-    public void onAttachedToWindow() {
-        final DisplayMetrics dm = getResources().getDisplayMetrics();
-        final float dp = dm.density;
-        final int size = (int)
-                (Math.min(Math.min(dm.widthPixels, dm.heightPixels), 600*dp) - 100*dp);
+    public void onStart() {
+        super.onStart();
 
-        final ImageView im = new ImageView(this);
-        final int pad = (int)(40*dp);
-        im.setPadding(pad, pad, pad, pad);
-        im.setTranslationZ(20);
-        im.setScaleX(0.5f);
-        im.setScaleY(0.5f);
-        im.setAlpha(0f);
+        bg.randomizePalette();
 
-        im.setBackground(new RippleDrawable(
-                ColorStateList.valueOf(0xFF776677),
-                getDrawable(com.android.internal.R.drawable.platlogo),
-                null));
-        im.setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                final int w = view.getWidth();
-                final int h = view.getHeight();
-                outline.setOval((int)(w*.125), (int)(h*.125), (int)(w*.96), (int)(h*.96));
-            }
-        });
-        im.setElevation(12f*dp);
-        im.setClickable(true);
-        im.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                im.setOnLongClickListener(new View.OnLongClickListener() {
+        anim = new TimeAnimator();
+        anim.setTimeListener(
+                new TimeAnimator.TimeListener() {
                     @Override
-                    public boolean onLongClick(View v) {
-                        if (mTapCount < 5) return false;
-
-                        final ContentResolver cr = getContentResolver();
-                        if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0)
-                                == 0) {
-                            // For posterity: the moment this user unlocked the easter egg
-                            try {
-                                Settings.System.putLong(cr,
-                                        Settings.System.EGG_MODE,
-                                        System.currentTimeMillis());
-                            } catch (RuntimeException e) {
-                                Log.e("PlatLogoActivity", "Can't write settings", e);
-                            }
-                        }
-                        im.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                try {
-                                    startActivity(new Intent(Intent.ACTION_MAIN)
-                                            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                                                    | Intent.FLAG_ACTIVITY_CLEAR_TASK
-                                                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
-                                            .addCategory("com.android.internal.category.PLATLOGO"));
-                                } catch (ActivityNotFoundException ex) {
-                                    Log.e("PlatLogoActivity", "No more eggs.");
-                                }
-                                if (FINISH) finish();
-                            }
-                        });
-                        return true;
+                    public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
+                        bg.setOffset((float) totalTime / 60000f);
+                        bg.invalidateSelf();
                     }
                 });
-                mTapCount++;
-            }
-        });
 
-        // Enable hardware keyboard input for TV compatibility.
-        im.setFocusable(true);
-        im.requestFocus();
-        im.setOnKeyListener(new View.OnKeyListener() {
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode != KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
-                    ++mKeyCount;
-                    if (mKeyCount > 2) {
-                        if (mTapCount > 5) {
-                            im.performLongClick();
-                        } else {
-                            im.performClick();
-                        }
-                    }
-                    return true;
-                } else {
-                    return false;
-                }
-            }
-        });
+        anim.start();
+    }
 
-        mLayout.addView(im, new FrameLayout.LayoutParams(size, size, Gravity.CENTER));
-
-        im.animate().scaleX(1f).scaleY(1f).alpha(1f)
-                .setInterpolator(mInterpolator)
-                .setDuration(500)
-                .setStartDelay(800)
-                .start();
+    @Override
+    public void onStop() {
+        if (anim != null) {
+            anim.cancel();
+            anim = null;
+        }
+        super.onStop();
     }
 }
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 1dfff5e..6bd6930 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -106,7 +106,7 @@
             int flags = PackageManager.MATCH_DEFAULT_ONLY
                     | (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
                     | (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0);
-            if (intent.isBrowsableWebIntent()
+            if (intent.isWebIntent()
                         || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
                 flags |= PackageManager.MATCH_INSTANT;
             }
diff --git a/core/java/com/android/internal/car/ICarServiceHelper.aidl b/core/java/com/android/internal/car/ICarServiceHelper.aidl
deleted file mode 100644
index 9ee330b..0000000
--- a/core/java/com/android/internal/car/ICarServiceHelper.aidl
+++ /dev/null
@@ -1,24 +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.internal.car;
-
-/**
- * Helper API for car service. Only for itneraction between system server and car service.
- * @hide
- */
-interface ICarServiceHelper {
-}
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index 9b7383f..7b25a06 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -405,12 +405,13 @@
         return v - (float) Math.floor(v);
     }
 
-    static class TonalPalette {
-        final float[] h;
-        final float[] s;
-        final float[] l;
-        final float minHue;
-        final float maxHue;
+    @VisibleForTesting
+    public static class TonalPalette {
+        public final float[] h;
+        public final float[] s;
+        public final float[] l;
+        public final float minHue;
+        public final float maxHue;
 
         TonalPalette(float[] h, float[] s, float[] l) {
             if (h.length != s.length || s.length != l.length) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 40dcf25b..eb58b09 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -678,7 +678,8 @@
     StopwatchTimer mCameraOnTimer;
 
     int mGpsSignalQualityBin = -1;
-    final StopwatchTimer[] mGpsSignalQualityTimer =
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    protected final StopwatchTimer[] mGpsSignalQualityTimer =
         new StopwatchTimer[GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS];
 
     int mPhoneSignalStrengthBin = -1;
@@ -760,6 +761,8 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     protected StopwatchTimer mBluetoothScanTimer;
 
+    boolean mIsCellularTxPowerHigh = false;
+
     int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
     long mMobileRadioActiveStartTime;
     StopwatchTimer mMobileRadioActiveTimer;
@@ -3522,7 +3525,7 @@
         mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
     }
 
-    void addHistoryBufferLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
+    void addHistoryBufferLocked(long elapsedRealtimeMs, HistoryItem cur) {
         if (!mHaveBatteryLevel || !mRecordingHistory) {
             return;
         }
@@ -3603,8 +3606,8 @@
         } else if (dataSize >= MAX_HISTORY_BUFFER) {
             if (!mHistoryOverflow) {
                 mHistoryOverflow = true;
-                addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_UPDATE, cur);
-                addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_OVERFLOW, cur);
+                addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, cur);
+                addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_OVERFLOW, cur);
                 return;
             }
 
@@ -3642,7 +3645,7 @@
                 return;
             }
 
-            addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_UPDATE, cur);
+            addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, cur);
             return;
         }
 
@@ -3650,15 +3653,14 @@
             // The history is currently empty; we need it to start with a time stamp.
             cur.currentTime = System.currentTimeMillis();
             if (recordResetDueToOverflow) {
-                addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_OVERFLOW, cur);
+                addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_OVERFLOW, cur);
             }
-            addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_RESET, cur);
+            addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_RESET, cur);
         }
-        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_UPDATE, cur);
+        addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, cur);
     }
 
-    private void addHistoryBufferLocked(long elapsedRealtimeMs, long uptimeMs, byte cmd,
-            HistoryItem cur) {
+    private void addHistoryBufferLocked(long elapsedRealtimeMs, byte cmd, HistoryItem cur) {
         if (mIteratingHistory) {
             throw new IllegalStateException("Can't do this while iterating history!");
         }
@@ -3692,17 +3694,17 @@
                 mHistoryAddTmp.wakeReasonTag = null;
                 mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
                 mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
-                addHistoryRecordInnerLocked(wakeElapsedTime, uptimeMs, mHistoryAddTmp);
+                addHistoryRecordInnerLocked(wakeElapsedTime, mHistoryAddTmp);
             }
         }
         mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
         mTrackRunningHistoryElapsedRealtime = elapsedRealtimeMs;
         mTrackRunningHistoryUptime = uptimeMs;
-        addHistoryRecordInnerLocked(elapsedRealtimeMs, uptimeMs, mHistoryCur);
+        addHistoryRecordInnerLocked(elapsedRealtimeMs, mHistoryCur);
     }
 
-    void addHistoryRecordInnerLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
-        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, cur);
+    void addHistoryRecordInnerLocked(long elapsedRealtimeMs, HistoryItem cur) {
+        addHistoryBufferLocked(elapsedRealtimeMs, cur);
 
         if (!USE_OLD_HISTORY) {
             return;
@@ -3743,7 +3745,7 @@
 
         if (mNumHistoryItems == MAX_HISTORY_ITEMS
                 || mNumHistoryItems == MAX_MAX_HISTORY_ITEMS) {
-            addHistoryRecordLocked(elapsedRealtimeMs, HistoryItem.CMD_OVERFLOW);
+            addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_OVERFLOW, cur);
         }
 
         if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
@@ -3760,7 +3762,7 @@
             }
         }
 
-        addHistoryRecordLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE);
+        addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, cur);
     }
 
     public void addHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code,
@@ -3826,6 +3828,7 @@
         mActiveHistoryStates2 = 0xffffffff;
     }
 
+    @GuardedBy("this")
     public void updateTimeBasesLocked(boolean unplugged, int screenState, long uptime,
             long realtime) {
         final boolean screenOff = !isScreenOn(screenState);
@@ -3903,6 +3906,7 @@
      * This should only be called after the cpu times have been read.
      * @see #scheduleRemoveIsolatedUidLocked(int, int)
      */
+    @GuardedBy("this")
     public void removeIsolatedUidLocked(int isolatedUid) {
         StatsLog.write(
                 StatsLog.ISOLATED_UID_CHANGED, mIsolatedUids.get(isolatedUid, -1),
@@ -4732,6 +4736,7 @@
         return;
     }
 
+    @GuardedBy("this")
     public void noteScreenStateLocked(int state) {
         state = mPretendScreenOff ? Display.STATE_OFF : state;
 
@@ -9648,6 +9653,7 @@
             return ps;
         }
 
+        @GuardedBy("mBsi")
         public void updateUidProcessStateLocked(int procState) {
             int uidRunningState;
             // Make special note of Foreground Services
@@ -9931,8 +9937,6 @@
             if (wl != null) {
                 StopwatchTimer wlt = getWakelockTimerLocked(wl, type);
                 wlt.stopRunningLocked(elapsedRealtimeMs);
-                if (!wlt.isRunningLocked()) { // only tell statsd if truly stopped
-                }
             }
             if (type == WAKE_TYPE_PARTIAL) {
                 if (mAggregatedPartialWakelockTimer != null) {
@@ -11214,6 +11218,9 @@
             Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
         }
 
+        // Add modem tx power to history.
+        addModemTxPowerToHistory(activityInfo);
+
         // Grab a separate lock to acquire the network stats, which may do I/O.
         NetworkStats delta = null;
         synchronized (mModemNetworkLock) {
@@ -11388,6 +11395,44 @@
             new BluetoothActivityEnergyInfo(0, 0, 0, 0, 0, 0);
 
     /**
+     * Add modem tx power to history
+     * Device is said to be in high cellular transmit power when it has spent most of the transmit
+     * time at the highest power level.
+     * @param activityInfo
+     */
+    private void addModemTxPowerToHistory(final ModemActivityInfo activityInfo) {
+        if (activityInfo == null) {
+            return;
+        }
+        int[] txTimeMs = activityInfo.getTxTimeMillis();
+        if (txTimeMs == null || txTimeMs.length != ModemActivityInfo.TX_POWER_LEVELS) {
+            return;
+        }
+        final long elapsedRealtime = mClocks.elapsedRealtime();
+        final long uptime = mClocks.uptimeMillis();
+        int levelMaxTimeSpent = 0;
+        for (int i = 1; i < txTimeMs.length; i++) {
+            if (txTimeMs[i] > txTimeMs[levelMaxTimeSpent]) {
+                levelMaxTimeSpent = i;
+            }
+        }
+        if (levelMaxTimeSpent == ModemActivityInfo.TX_POWER_LEVELS - 1) {
+            if (!mIsCellularTxPowerHigh) {
+                mHistoryCur.states2 |= HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG;
+                addHistoryRecordLocked(elapsedRealtime, uptime);
+                mIsCellularTxPowerHigh = true;
+            }
+            return;
+        }
+        if (mIsCellularTxPowerHigh) {
+            mHistoryCur.states2 &= ~HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG;
+            addHistoryRecordLocked(elapsedRealtime, uptime);
+            mIsCellularTxPowerHigh = false;
+        }
+        return;
+    }
+
+    /**
      * Distribute Bluetooth energy info and network traffic to apps.
      * @param info The energy information from the bluetooth controller.
      */
@@ -11721,6 +11766,7 @@
      * and we are on battery with screen off, we give more of the cpu time to those apps holding
      * wakelocks. If the screen is on, we just assign the actual cpu time an app used.
      */
+    @GuardedBy("this")
     public void updateCpuTimeLocked() {
         if (mPowerProfile == null) {
             return;
@@ -12166,6 +12212,7 @@
         return false;
     }
 
+    @GuardedBy("this")
     protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime,
             final boolean onBattery, final int oldStatus, final int level, final int chargeUAh) {
         boolean doWrite = false;
@@ -12307,7 +12354,7 @@
             boolean reset) {
         mRecordingHistory = true;
         mHistoryCur.currentTime = System.currentTimeMillis();
-        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs,
+        addHistoryBufferLocked(elapsedRealtimeMs,
                 reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME,
                 mHistoryCur);
         mHistoryCur.currentTime = 0;
@@ -12320,8 +12367,7 @@
             final long uptimeMs) {
         if (mRecordingHistory) {
             mHistoryCur.currentTime = currentTime;
-            addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_CURRENT_TIME,
-                    mHistoryCur);
+            addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_CURRENT_TIME, mHistoryCur);
             mHistoryCur.currentTime = 0;
         }
     }
@@ -12329,8 +12375,7 @@
     private void recordShutdownLocked(final long elapsedRealtimeMs, final long uptimeMs) {
         if (mRecordingHistory) {
             mHistoryCur.currentTime = System.currentTimeMillis();
-            addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_SHUTDOWN,
-                    mHistoryCur);
+            addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_SHUTDOWN, mHistoryCur);
             mHistoryCur.currentTime = 0;
         }
     }
@@ -12344,6 +12389,7 @@
     // This should probably be exposed in the API, though it's not critical
     public static final int BATTERY_PLUGGED_NONE = OsProtoEnums.BATTERY_PLUGGED_NONE; // = 0
 
+    @GuardedBy("this")
     public void setBatteryStateLocked(final int status, final int health, final int plugType,
             final int level, /* not final */ int temp, final int volt, final int chargeUAh,
             final int chargeFullUAh) {
@@ -13159,6 +13205,7 @@
         }
     }
 
+    @GuardedBy("this")
     public void dumpConstantsLocked(PrintWriter pw) {
         mConstants.dumpLocked(pw);
     }
@@ -13274,7 +13321,7 @@
             if (USE_OLD_HISTORY) {
                 addHistoryRecordLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
             }
-            addHistoryBufferLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
+            addHistoryBufferLocked(elapsedRealtime, HistoryItem.CMD_START, mHistoryCur);
             startRecordingHistory(elapsedRealtime, uptime, false);
         }
 
@@ -13542,6 +13589,7 @@
         mCameraOnTimer.readSummaryFromParcelLocked(in);
         mBluetoothScanNesting = 0;
         mBluetoothScanTimer.readSummaryFromParcelLocked(in);
+        mIsCellularTxPowerHigh = false;
 
         int NRPMS = in.readInt();
         if (NRPMS > 10000) {
@@ -14478,6 +14526,7 @@
         mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase, in);
         mBluetoothScanNesting = 0;
         mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase, in);
+        mIsCellularTxPowerHigh = false;
         mDischargeUnplugLevel = in.readInt();
         mDischargePlugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index 088e726..12405eb 100644
--- a/core/java/com/android/internal/os/FuseAppLoop.java
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -283,6 +283,7 @@
         return -OsConstants.EBADF;
     }
 
+    @GuardedBy("mLock")
     private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException {
         final CallbackEntry entry = mCallbackMap.get(checkInode(inode));
         if (entry == null) {
@@ -291,12 +292,14 @@
         return entry;
     }
 
+    @GuardedBy("mLock")
     private void recycleLocked(Args args) {
         if (mArgsPool.size() < ARGS_POOL_SIZE) {
             mArgsPool.add(args);
         }
     }
 
+    @GuardedBy("mLock")
     private void replySimpleLocked(long unique, int result) {
         if (mInstance != 0) {
             native_replySimple(mInstance, unique, result);
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index f70d3c2..221bf88 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -35,7 +35,7 @@
     void animateCollapsePanels();
     void togglePanel();
 
-    void showChargingAnimation(int batteryLevel);
+    void showWirelessChargingAnimation(int batteryLevel);
 
     /**
      * Notifies the status bar of a System UI visibility flag change.
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index 74dbaba..f05bd32 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -139,6 +139,10 @@
          * @see com.android.server.wm.WindowManagerService#inputMethodClientHasFocus(IInputMethodClient)
          */
         int ERROR_NOT_IME_TARGET_WINDOW = 11;
+        /**
+         * Indicates that focused view in the current window is not an editor.
+         */
+        int ERROR_NO_EDITOR = 12;
     }
 
     @ResultCode
@@ -258,6 +262,8 @@
                 return "ERROR_NULL";
             case ResultCode.ERROR_NO_IME:
                 return "ERROR_NO_IME";
+            case ResultCode.ERROR_NO_EDITOR:
+                return "ERROR_NO_EDITOR";
             case ResultCode.ERROR_INVALID_PACKAGE_NAME:
                 return "ERROR_INVALID_PACKAGE_NAME";
             case ResultCode.ERROR_SYSTEM_NOT_READY:
@@ -288,6 +294,10 @@
      */
     public static final InputBindResult NO_IME = error(ResultCode.ERROR_NO_IME);
     /**
+     * Predefined error object for {@link ResultCode#NO_EDITOR}.
+     */
+    public static final InputBindResult NO_EDITOR = error(ResultCode.ERROR_NO_EDITOR);
+    /**
      * Predefined error object for {@link ResultCode#ERROR_INVALID_PACKAGE_NAME}.
      */
     public static final InputBindResult INVALID_PACKAGE_NAME =
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index b53459e..67dc81a 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -551,6 +551,7 @@
         mPreventDispatchingItemsChanged = true;
         clear();
         clearHeader();
+        mPresenters.clear();
         mPreventDispatchingItemsChanged = false;
         mItemsChangedWhileDispatchPrevented = false;
         onItemsChanged(true);
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
new file mode 100644
index 0000000..71d3bb5
--- /dev/null
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A class to extract Bitmaps from a MessagingStyle message.
+ */
+public class LocalImageResolver {
+
+    private static final int MAX_SAFE_ICON_SIZE_PX = 480;
+
+    @Nullable
+    public static Drawable resolveImage(Uri uri, Context context) throws IOException {
+        BitmapFactory.Options onlyBoundsOptions = getBoundsOptionsForImage(uri, context);
+        if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
+            return null;
+        }
+
+        int originalSize =
+                (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth)
+                        ? onlyBoundsOptions.outHeight
+                        : onlyBoundsOptions.outWidth;
+
+        double ratio = (originalSize > MAX_SAFE_ICON_SIZE_PX)
+                        ? (originalSize / MAX_SAFE_ICON_SIZE_PX)
+                        : 1.0;
+
+        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
+        bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
+        InputStream input = context.getContentResolver().openInputStream(uri);
+        Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
+        input.close();
+        return new BitmapDrawable(context.getResources(), bitmap);
+    }
+
+    private static BitmapFactory.Options getBoundsOptionsForImage(Uri uri, Context context)
+            throws IOException {
+        InputStream input = context.getContentResolver().openInputStream(uri);
+        BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
+        onlyBoundsOptions.inJustDecodeBounds = true;
+        BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
+        input.close();
+        return onlyBoundsOptions;
+    }
+
+    private static int getPowerOfTwoForSampleRatio(double ratio) {
+        int k = Integer.highestOneBit((int) Math.floor(ratio));
+        return Math.max(1, k);
+    }
+}
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 5577d6e..239beaa 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -22,9 +22,12 @@
 import android.annotation.StyleRes;
 import android.app.Notification;
 import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.drawable.Icon;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
 import android.util.Pools;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -61,6 +64,11 @@
     private boolean mIsHidingAnimated;
     private boolean mNeedsGeneratedAvatar;
     private Notification.Person mSender;
+    private boolean mAvatarsAtEnd;
+    private ViewGroup mImageContainer;
+    private MessagingImageMessage mIsolatedMessage;
+    private boolean mTransformingImages;
+    private Point mDisplaySize = new Point();
 
     public MessagingGroup(@NonNull Context context) {
         super(context);
@@ -87,6 +95,35 @@
         mSenderName = findViewById(R.id.message_name);
         mSenderName.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
         mAvatarView = findViewById(R.id.message_icon);
+        mImageContainer = findViewById(R.id.messaging_group_icon_container);
+        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+        mDisplaySize.x = displayMetrics.widthPixels;
+        mDisplaySize.y = displayMetrics.heightPixels;
+    }
+
+    public void updateClipRect() {
+        // We want to clip to the senderName if it's available, otherwise our images will come
+        // from a weird position
+        Rect clipRect;
+        if (mSenderName.getVisibility() != View.GONE && !mTransformingImages) {
+            ViewGroup parent = (ViewGroup) mSenderName.getParent();
+            int top = getDistanceFromParent(mSenderName, parent) - getDistanceFromParent(
+                    mMessageContainer, parent) + mSenderName.getHeight();
+            clipRect = new Rect(0, top, mDisplaySize.x, mDisplaySize.y);
+        } else {
+            clipRect = null;
+        }
+        mMessageContainer.setClipBounds(clipRect);
+    }
+
+    private int getDistanceFromParent(View searchedView, ViewGroup parent) {
+        int position = 0;
+        View view = searchedView;
+        while(view != parent) {
+            position += view.getTop() + view.getTranslationY();
+            view = (View) view.getParent();
+        }
+        return position;
     }
 
     public void setSender(Notification.Person sender, CharSequence nameOverride) {
@@ -129,12 +166,14 @@
     }
 
     public void removeMessage(MessagingMessage messagingMessage) {
-        mMessageContainer.removeView(messagingMessage);
+        ViewGroup messageParent = (ViewGroup) messagingMessage.getView().getParent();
+        messageParent.removeView(messagingMessage.getView());
         Runnable recycleRunnable = () -> {
-            mMessageContainer.removeTransientView(messagingMessage);
+            messageParent.removeTransientView(messagingMessage.getView());
             messagingMessage.recycle();
             if (mMessageContainer.getChildCount() == 0
-                    && mMessageContainer.getTransientViewCount() == 0) {
+                    && mMessageContainer.getTransientViewCount() == 0
+                    && mImageContainer.getChildCount() == 0) {
                 ViewParent parent = getParent();
                 if (parent instanceof ViewGroup) {
                     ((ViewGroup) parent).removeView(MessagingGroup.this);
@@ -148,9 +187,10 @@
             }
         };
         if (isShown()) {
-            mMessageContainer.addTransientView(messagingMessage, 0);
-            performRemoveAnimation(messagingMessage, recycleRunnable);
-            if (mMessageContainer.getChildCount() == 0) {
+            messageParent.addTransientView(messagingMessage.getView(), 0);
+            performRemoveAnimation(messagingMessage.getView(), recycleRunnable);
+            if (mMessageContainer.getChildCount() == 0
+                    && mImageContainer.getChildCount() == 0) {
                 removeGroupAnimated(null);
             }
         } else {
@@ -160,12 +200,8 @@
     }
 
     private void removeGroupAnimated(Runnable endAction) {
-        MessagingPropertyAnimator.fadeOut(mAvatarView, null);
-        MessagingPropertyAnimator.startLocalTranslationTo(mAvatarView,
-                (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
-        MessagingPropertyAnimator.fadeOut(mSenderName, null);
-        MessagingPropertyAnimator.startLocalTranslationTo(mSenderName,
-                (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
+        performRemoveAnimation(mAvatarView, null);
+        performRemoveAnimation(mSenderName, null);
         boolean endActionTriggered = false;
         for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
             View child = mMessageContainer.getChildAt(i);
@@ -182,14 +218,17 @@
             performRemoveAnimation(child, childEndAction);
             endActionTriggered = true;
         }
+        if (mIsolatedMessage != null) {
+            performRemoveAnimation(mIsolatedMessage, !endActionTriggered ? endAction : null);
+            endActionTriggered = true;
+        }
         if (!endActionTriggered && endAction != null) {
             endAction.run();
         }
     }
 
-    public void performRemoveAnimation(View message,
-            Runnable recycleRunnable) {
-        MessagingPropertyAnimator.fadeOut(message, recycleRunnable);
+    public void performRemoveAnimation(View message, Runnable endAction) {
+        MessagingPropertyAnimator.fadeOut(message, endAction);
         MessagingPropertyAnimator.startLocalTranslationTo(message,
                 (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
     }
@@ -222,6 +261,9 @@
                 }
             }
         }
+        if (mMessageContainer.getChildCount() == 0 && mIsolatedMessage != null) {
+            return mIsolatedMessage.getMeasuredType();
+        }
         return MEASURED_NORMAL;
     }
 
@@ -234,6 +276,7 @@
                 result += ((MessagingLinearLayout.MessagingChild) child).getConsumedLines();
             }
         }
+        result = mIsolatedMessage != null ? Math.max(result, 1) : result;
         // A group is usually taking up quite some space with the padding and the name, let's add 1
         return result + 1;
     }
@@ -289,26 +332,67 @@
 
     public void setMessages(List<MessagingMessage> group) {
         // Let's now make sure all children are added and in the correct order
+        int textMessageIndex = 0;
+        MessagingImageMessage isolatedMessage = null;
         for (int messageIndex = 0; messageIndex < group.size(); messageIndex++) {
             MessagingMessage message = group.get(messageIndex);
+            message.setColor(mTextColor);
             if (message.getGroup() != this) {
                 message.setMessagingGroup(this);
-                ViewParent parent = mMessageContainer.getParent();
-                if (parent instanceof ViewGroup) {
-                    ((ViewGroup) parent).removeView(message);
-                }
-                mMessageContainer.addView(message, messageIndex);
                 mAddedMessages.add(message);
             }
-            if (messageIndex != mMessageContainer.indexOfChild(message)) {
-                mMessageContainer.removeView(message);
-                mMessageContainer.addView(message, messageIndex);
+            boolean isImage = message instanceof MessagingImageMessage;
+            if (mAvatarsAtEnd && isImage) {
+                isolatedMessage = (MessagingImageMessage) message;
+            } else {
+                if (removeFromParentIfDifferent(message, mMessageContainer)) {
+                    ViewGroup.LayoutParams layoutParams = message.getView().getLayoutParams();
+                    if (layoutParams != null
+                            && !(layoutParams instanceof MessagingLinearLayout.LayoutParams)) {
+                        message.getView().setLayoutParams(
+                                mMessageContainer.generateDefaultLayoutParams());
+                    }
+                    mMessageContainer.addView(message.getView(), textMessageIndex);
+                }
+                if (isImage) {
+                    ((MessagingImageMessage) message).setIsolated(false);
+                }
+                // Let's sort them properly
+                if (textMessageIndex != mMessageContainer.indexOfChild(message.getView())) {
+                    mMessageContainer.removeView(message.getView());
+                    mMessageContainer.addView(message.getView(), textMessageIndex);
+                }
+                textMessageIndex++;
             }
-            message.setTextColor(mTextColor);
         }
+        if (isolatedMessage != null) {
+            if (removeFromParentIfDifferent(isolatedMessage, mImageContainer)) {
+                mImageContainer.removeAllViews();
+                mImageContainer.addView(isolatedMessage.getView());
+            }
+            isolatedMessage.setIsolated(true);
+        } else if (mIsolatedMessage != null) {
+            mImageContainer.removeAllViews();
+        }
+        mIsolatedMessage = isolatedMessage;
         mMessages = group;
     }
 
+    /**
+     * Remove the message from the parent if the parent isn't the one provided
+     * @return whether the message was removed
+     */
+    private boolean removeFromParentIfDifferent(MessagingMessage message, ViewGroup newParent) {
+        ViewParent parent = message.getView().getParent();
+        if (parent != newParent) {
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).removeView(message.getView());
+            }
+            return true;
+        }
+        return false;
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
@@ -317,13 +401,14 @@
                 @Override
                 public boolean onPreDraw() {
                     for (MessagingMessage message : mAddedMessages) {
-                        if (!message.isShown()) {
+                        if (!message.getView().isShown()) {
                             continue;
                         }
-                        MessagingPropertyAnimator.fadeIn(message);
+                        MessagingPropertyAnimator.fadeIn(message.getView());
                         if (!mFirstLayout) {
-                            MessagingPropertyAnimator.startLocalTranslationFrom(message,
-                                    message.getHeight(), MessagingLayout.LINEAR_OUT_SLOW_IN);
+                            MessagingPropertyAnimator.startLocalTranslationFrom(message.getView(),
+                                    message.getView().getHeight(),
+                                    MessagingLayout.LINEAR_OUT_SLOW_IN);
                         }
                     }
                     mAddedMessages.clear();
@@ -333,6 +418,7 @@
             });
         }
         mFirstLayout = false;
+        updateClipRect();
     }
 
     /**
@@ -372,6 +458,10 @@
         return mMessageContainer;
     }
 
+    public MessagingImageMessage getIsolatedMessage() {
+        return mIsolatedMessage;
+    }
+
     public boolean needsGeneratedAvatar() {
         return mNeedsGeneratedAvatar;
     }
@@ -379,4 +469,19 @@
     public Notification.Person getSender() {
         return mSender;
     }
+
+    public void setTransformingImages(boolean transformingImages) {
+        mTransformingImages = transformingImages;
+    }
+
+    public void setDisplayAvatarsAtEnd(boolean atEnd) {
+        if (mAvatarsAtEnd != atEnd) {
+            mAvatarsAtEnd = atEnd;
+            mImageContainer.setVisibility(atEnd ? View.VISIBLE : View.GONE);
+        }
+    }
+
+    public List<MessagingMessage> getMessages() {
+        return mMessages;
+    }
 }
diff --git a/core/java/com/android/internal/widget/MessagingImageMessage.java b/core/java/com/android/internal/widget/MessagingImageMessage.java
new file mode 100644
index 0000000..961f90a
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingImageMessage.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Pools;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.RemoteViews;
+
+import com.android.internal.R;
+
+import java.io.IOException;
+
+/**
+ * A message of a {@link MessagingLayout} that is an image.
+ */
+@RemoteViews.RemoteView
+public class MessagingImageMessage extends ImageView implements MessagingMessage {
+    private static final String TAG = "MessagingImageMessage";
+    private static Pools.SimplePool<MessagingImageMessage> sInstancePool
+            = new Pools.SynchronizedPool<>(10);
+    private final MessagingMessageState mState = new MessagingMessageState(this);
+    private final int mMinImageHeight;
+    private final Path mPath = new Path();
+    private final int mImageRounding;
+    private final int mMaxImageHeight;
+    private final int mIsolatedSize;
+    private final int mExtraSpacing;
+    private Drawable mDrawable;
+    private float mAspectRatio;
+    private int mActualWidth;
+    private int mActualHeight;
+    private boolean mIsIsolated;
+
+    public MessagingImageMessage(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public MessagingImageMessage(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public MessagingImageMessage(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public MessagingImageMessage(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mMinImageHeight = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.messaging_image_min_size);
+        mMaxImageHeight = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.messaging_image_max_height);
+        mImageRounding = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.messaging_image_rounding);
+        mExtraSpacing = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.messaging_image_extra_spacing);
+        setMaxHeight(mMaxImageHeight);
+        mIsolatedSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size);
+    }
+
+    @Override
+    public MessagingMessageState getState() {
+        return mState;
+    }
+
+    @Override
+    public boolean setMessage(Notification.MessagingStyle.Message message) {
+        MessagingMessage.super.setMessage(message);
+        Drawable drawable;
+        try {
+            drawable = LocalImageResolver.resolveImage(message.getDataUri(), getContext());
+        } catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
+        int intrinsicHeight = drawable.getIntrinsicHeight();
+        if (intrinsicHeight == 0) {
+            Log.w(TAG, "Drawable with 0 intrinsic height was returned");
+            return false;
+        }
+        mDrawable = drawable;
+        mAspectRatio = ((float) mDrawable.getIntrinsicWidth()) / intrinsicHeight;
+        setImageDrawable(drawable);
+        setContentDescription(message.getText());
+        return true;
+    }
+
+    static MessagingMessage createMessage(MessagingLayout layout,
+            Notification.MessagingStyle.Message m) {
+        MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
+        MessagingImageMessage createdMessage = sInstancePool.acquire();
+        if (createdMessage == null) {
+            createdMessage = (MessagingImageMessage) LayoutInflater.from(
+                    layout.getContext()).inflate(
+                            R.layout.notification_template_messaging_image_message,
+                            messagingLinearLayout,
+                            false);
+            createdMessage.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
+        }
+        boolean created = createdMessage.setMessage(m);
+        if (!created) {
+            createdMessage.recycle();
+            return MessagingTextMessage.createMessage(layout, m);
+        }
+        return createdMessage;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        canvas.save();
+        canvas.clipPath(getRoundedRectPath());
+        int width = (int) Math.max(getActualWidth(), getActualHeight() * mAspectRatio);
+        int height = (int) (width / mAspectRatio);
+        int left = (int) ((getActualWidth() - width) / 2.0f);
+        mDrawable.setBounds(left, 0, left + width, height);
+        mDrawable.draw(canvas);
+        canvas.restore();
+    }
+
+    public Path getRoundedRectPath() {
+        int left = 0;
+        int right = getActualWidth();
+        int top = 0;
+        int bottom = getActualHeight();
+        mPath.reset();
+        int width = right - left;
+        float roundnessX = mImageRounding;
+        float roundnessY = mImageRounding;
+        roundnessX = Math.min(width / 2, roundnessX);
+        roundnessY = Math.min((bottom - top) / 2, roundnessY);
+        mPath.moveTo(left, top + roundnessY);
+        mPath.quadTo(left, top, left + roundnessX, top);
+        mPath.lineTo(right - roundnessX, top);
+        mPath.quadTo(right, top, right, top + roundnessY);
+        mPath.lineTo(right, bottom - roundnessY);
+        mPath.quadTo(right, bottom, right - roundnessX, bottom);
+        mPath.lineTo(left + roundnessX, bottom);
+        mPath.quadTo(left, bottom, left, bottom - roundnessY);
+        mPath.close();
+        return mPath;
+    }
+
+    public void recycle() {
+        MessagingMessage.super.recycle();
+        setAlpha(1.0f);
+        setTranslationY(0);
+        setImageBitmap(null);
+        mDrawable = null;
+        sInstancePool.release(this);
+    }
+
+    public static void dropCache() {
+        sInstancePool = new Pools.SynchronizedPool<>(10);
+    }
+
+    @Override
+    public int getMeasuredType() {
+        int measuredHeight = getMeasuredHeight();
+        int minImageHeight;
+        if (mIsIsolated) {
+            minImageHeight = mIsolatedSize;
+        } else {
+            minImageHeight = mMinImageHeight;
+        }
+        boolean measuredTooSmall = measuredHeight < minImageHeight
+                && measuredHeight != mDrawable.getIntrinsicHeight();
+        if (measuredTooSmall) {
+            return MEASURED_TOO_SMALL;
+        } else {
+            if (!mIsIsolated && measuredHeight != mDrawable.getIntrinsicHeight()) {
+                return MEASURED_SHORTENED;
+            } else {
+                return MEASURED_NORMAL;
+            }
+        }
+    }
+
+    @Override
+    public void setMaxDisplayedLines(int lines) {
+        // Nothing to do, this should be handled automatically.
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        if (mIsIsolated) {
+            setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
+                    MeasureSpec.getSize(heightMeasureSpec));
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        // TODO: ensure that this isn't called when transforming
+        setActualWidth(getStaticWidth());
+        setActualHeight(getHeight());
+    }
+
+    @Override
+    public int getConsumedLines() {
+        return 3;
+    }
+
+    public void setActualWidth(int actualWidth) {
+        mActualWidth = actualWidth;
+        invalidate();
+    }
+
+    public int getActualWidth() {
+        return mActualWidth;
+    }
+
+    public void setActualHeight(int actualHeight) {
+        mActualHeight = actualHeight;
+        invalidate();
+    }
+
+    public int getActualHeight() {
+        return mActualHeight;
+    }
+
+    public int getStaticWidth() {
+        if (mIsIsolated) {
+            return getWidth();
+        }
+        return (int) (getHeight() * mAspectRatio);
+    }
+
+    public void setIsolated(boolean isolated) {
+        if (mIsIsolated != isolated) {
+            mIsIsolated = isolated;
+            // update the layout params not to have margins
+            ViewGroup.MarginLayoutParams layoutParams =
+                    (ViewGroup.MarginLayoutParams) getLayoutParams();
+            layoutParams.topMargin = isolated ? 0 : mExtraSpacing;
+            setLayoutParams(layoutParams);
+        }
+    }
+
+    @Override
+    public int getExtraSpacing() {
+        return mExtraSpacing;
+    }
+}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index d45c086..5279636 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -81,6 +81,7 @@
     private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
     private Notification.Person mUser;
     private CharSequence mNameReplacement;
+    private boolean mIsCollapsed;
 
     public MessagingLayout(@NonNull Context context) {
         super(context);
@@ -127,6 +128,11 @@
     }
 
     @RemotableViewMethod
+    public void setIsCollapsed(boolean isCollapsed) {
+        mIsCollapsed = isCollapsed;
+    }
+
+    @RemotableViewMethod
     public void setData(Bundle extras) {
         Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
         List<Notification.MessagingStyle.Message> newMessages
@@ -331,6 +337,7 @@
                 newGroup = MessagingGroup.createGroup(mMessagingLinearLayout);
                 mAddedGroups.add(newGroup);
             }
+            newGroup.setDisplayAvatarsAtEnd(mIsCollapsed);
             newGroup.setLayoutColor(mLayoutColor);
             Notification.Person sender = senders.get(groupIndex);
             CharSequence nameOverride = null;
@@ -392,7 +399,6 @@
             MessagingMessage message = findAndRemoveMatchingMessage(m);
             if (message == null) {
                 message = MessagingMessage.createMessage(this, m);
-                message.addOnLayoutChangeListener(MESSAGING_PROPERTY_ANIMATOR);
             }
             message.setIsHistoric(historic);
             result.add(message);
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index f0ef370..991e3e7 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -75,7 +75,6 @@
                 targetHeight = Integer.MAX_VALUE;
                 break;
         }
-        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
 
         // Now that we know which views to take, fix up the indents and see what width we get.
         int measuredWidth = mPaddingLeft + mPaddingRight;
@@ -90,7 +89,6 @@
         totalHeight = mPaddingTop + mPaddingBottom;
         boolean first = true;
         int linesRemaining = mMaxDisplayedLines;
-
         // Starting from the bottom: we measure every view as if it were the only one. If it still
         // fits, we take it, otherwise we stop there.
         for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) {
@@ -100,11 +98,13 @@
             final View child = getChildAt(i);
             LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
             MessagingChild messagingChild = null;
+            int spacing = mSpacing;
             if (child instanceof MessagingChild) {
                 messagingChild = (MessagingChild) child;
                 messagingChild.setMaxDisplayedLines(linesRemaining);
+                spacing += messagingChild.getExtraSpacing();
             }
-            int spacing = first ? 0 : mSpacing;
+            spacing = first ? 0 : spacing;
             measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight
                     - mPaddingTop - mPaddingBottom + spacing);
 
@@ -254,6 +254,9 @@
         void setMaxDisplayedLines(int lines);
         void hideAnimated();
         boolean isHidingAnimated();
+        default int getExtraSpacing() {
+            return 0;
+        }
     }
 
     public static class LayoutParams extends MarginLayoutParams {
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index f09621f..bf1c5ca 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -16,182 +16,125 @@
 
 package com.android.internal.widget;
 
-import android.annotation.AttrRes;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StyleRes;
 import android.app.Notification;
-import android.content.Context;
-import android.text.Layout;
-import android.util.AttributeSet;
-import android.util.Pools;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.widget.RemoteViews;
-
-import com.android.internal.R;
+import android.view.View;
 
 import java.util.Objects;
 
 /**
  * A message of a {@link MessagingLayout}.
  */
-@RemoteViews.RemoteView
-public class MessagingMessage extends ImageFloatingTextView implements
-        MessagingLinearLayout.MessagingChild {
+public interface MessagingMessage extends MessagingLinearLayout.MessagingChild {
 
-    private static Pools.SimplePool<MessagingMessage> sInstancePool
-            = new Pools.SynchronizedPool<>(10);
-    private Notification.MessagingStyle.Message mMessage;
-    private MessagingGroup mGroup;
-    private boolean mIsHistoric;
-    private boolean mIsHidingAnimated;
+    /**
+     * Prefix for supported image MIME types
+     **/
+    String IMAGE_MIME_TYPE_PREFIX = "image/";
 
-    public MessagingMessage(@NonNull Context context) {
-        super(context);
+    static MessagingMessage createMessage(MessagingLayout layout,
+            Notification.MessagingStyle.Message m) {
+        if (hasImage(m)) {
+            return MessagingImageMessage.createMessage(layout, m);
+        } else {
+            return MessagingTextMessage.createMessage(layout, m);
+        }
     }
 
-    public MessagingMessage(@NonNull Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
+    static void dropCache() {
+        MessagingTextMessage.dropCache();
+        MessagingImageMessage.dropCache();
     }
 
-    public MessagingMessage(@NonNull Context context, @Nullable AttributeSet attrs,
-            @AttrRes int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
+    static boolean hasImage(Notification.MessagingStyle.Message m) {
+        return m.getDataUri() != null
+                && m.getDataMimeType() != null
+                && m.getDataMimeType().startsWith(IMAGE_MIME_TYPE_PREFIX);
     }
 
-    public MessagingMessage(@NonNull Context context, @Nullable AttributeSet attrs,
-            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
+    /**
+     * Set a message for this view.
+     * @return true if setting the message worked
+     */
+    default boolean setMessage(Notification.MessagingStyle.Message message) {
+        getState().setMessage(message);
+        return true;
     }
 
-    private void setMessage(Notification.MessagingStyle.Message message) {
-        mMessage = message;
-        setText(message.getText());
+    default Notification.MessagingStyle.Message getMessage() {
+        return getState().getMessage();
     }
 
-    public Notification.MessagingStyle.Message getMessage() {
-        return mMessage;
-    }
-
-    boolean sameAs(Notification.MessagingStyle.Message message) {
-        if (!Objects.equals(message.getText(), mMessage.getText())) {
+    default boolean sameAs(Notification.MessagingStyle.Message message) {
+        Notification.MessagingStyle.Message ownMessage = getMessage();
+        if (!Objects.equals(message.getText(), ownMessage.getText())) {
             return false;
         }
-        if (!Objects.equals(message.getSender(), mMessage.getSender())) {
+        if (!Objects.equals(message.getSender(), ownMessage.getSender())) {
             return false;
         }
-        if (!Objects.equals(message.getTimestamp(), mMessage.getTimestamp())) {
+        if (!Objects.equals(message.getTimestamp(), ownMessage.getTimestamp())) {
+            return false;
+        }
+        if (!Objects.equals(message.getDataMimeType(), ownMessage.getDataMimeType())) {
+            return false;
+        }
+        if (!Objects.equals(message.getDataUri(), ownMessage.getDataUri())) {
             return false;
         }
         return true;
     }
 
-    boolean sameAs(MessagingMessage message) {
+    default boolean sameAs(MessagingMessage message) {
         return sameAs(message.getMessage());
     }
 
-    static MessagingMessage createMessage(MessagingLayout layout,
-            Notification.MessagingStyle.Message m) {
-        MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
-        MessagingMessage createdMessage = sInstancePool.acquire();
-        if (createdMessage == null) {
-            createdMessage = (MessagingMessage) LayoutInflater.from(layout.getContext()).inflate(
-                    R.layout.notification_template_messaging_message, messagingLinearLayout,
-                    false);
-        }
-        createdMessage.setMessage(m);
-        return createdMessage;
+    default void removeMessage() {
+        getGroup().removeMessage(this);
     }
 
-    public void removeMessage() {
-        mGroup.removeMessage(this);
+    default void setMessagingGroup(MessagingGroup group) {
+        getState().setGroup(group);
     }
 
-    public void recycle() {
-        mGroup = null;
-        mMessage = null;
-        setAlpha(1.0f);
-        setTranslationY(0);
-        sInstancePool.release(this);
+    default void setIsHistoric(boolean isHistoric) {
+        getState().setIsHistoric(isHistoric);
     }
 
-    public void setMessagingGroup(MessagingGroup group) {
-        mGroup = group;
+    default MessagingGroup getGroup() {
+        return getState().getGroup();
     }
 
-    public static void dropCache() {
-        sInstancePool = new Pools.SynchronizedPool<>(10);
-    }
-
-    public void setIsHistoric(boolean isHistoric) {
-        mIsHistoric = isHistoric;
-    }
-
-    public MessagingGroup getGroup() {
-        return mGroup;
+    default void setIsHidingAnimated(boolean isHiding) {
+        getState().setIsHidingAnimated(isHiding);
     }
 
     @Override
-    public int getMeasuredType() {
-        boolean measuredTooSmall = getMeasuredHeight()
-                < getLayoutHeight() + getPaddingTop() + getPaddingBottom();
-        if (measuredTooSmall) {
-            return MEASURED_TOO_SMALL;
-        } else {
-            Layout layout = getLayout();
-            if (layout == null) {
-                return MEASURED_TOO_SMALL;
-            }
-            if (layout.getEllipsisCount(layout.getLineCount() - 1) > 0) {
-                return MEASURED_SHORTENED;
-            } else {
-                return MEASURED_NORMAL;
-            }
-        }
+    default boolean isHidingAnimated() {
+        return getState().isHidingAnimated();
     }
 
     @Override
-    public void hideAnimated() {
+    default void hideAnimated() {
         setIsHidingAnimated(true);
-        mGroup.performRemoveAnimation(this, () -> setIsHidingAnimated(false));
+        getGroup().performRemoveAnimation(getState().getHostView(),
+                () -> setIsHidingAnimated(false));
     }
 
-    private void setIsHidingAnimated(boolean isHiding) {
-        ViewParent parent = getParent();
-        mIsHidingAnimated = isHiding;
-        invalidate();
-        if (parent instanceof ViewGroup) {
-            ((ViewGroup) parent).invalidate();
-        }
-    }
-
-    @Override
-    public boolean isHidingAnimated() {
-        return mIsHidingAnimated;
-    }
-
-    @Override
-    public void setMaxDisplayedLines(int lines) {
-        setMaxLines(lines);
-    }
-
-    @Override
-    public int getConsumedLines() {
-        return getLineCount();
-    }
-
-    public int getLayoutHeight() {
-        Layout layout = getLayout();
-        if (layout == null) {
-            return 0;
-        }
-        return layout.getHeight();
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
+    default boolean hasOverlappingRendering() {
         return false;
     }
+
+    default void recycle() {
+        getState().reset();
+    }
+
+    default View getView() {
+        return (View) this;
+    }
+
+    default void setColor(int textColor) {}
+
+    MessagingMessageState getState();
+
+    void setVisibility(int visibility);
 }
diff --git a/core/java/com/android/internal/widget/MessagingMessageState.java b/core/java/com/android/internal/widget/MessagingMessageState.java
new file mode 100644
index 0000000..ac62472
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingMessageState.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.widget;
+
+import android.app.Notification;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+
+/**
+ * Shared state and implementation for MessagingMessages. Used to share common implementations.
+ */
+public class MessagingMessageState {
+    private final View mHostView;
+    private Notification.MessagingStyle.Message mMessage;
+    private MessagingGroup mGroup;
+    private boolean mIsHistoric;
+    private boolean mIsHidingAnimated;
+
+    MessagingMessageState(View hostView) {
+        mHostView = hostView;
+    }
+
+    public void setMessage(Notification.MessagingStyle.Message message) {
+        mMessage = message;
+    }
+
+    public Notification.MessagingStyle.Message getMessage() {
+        return mMessage;
+    }
+
+    public void setGroup(MessagingGroup group) {
+        mGroup = group;
+    }
+
+    public MessagingGroup getGroup() {
+        return mGroup;
+    }
+
+    public void setIsHistoric(boolean isHistoric) {
+        mIsHistoric = isHistoric;
+    }
+
+    public void setIsHidingAnimated(boolean isHiding) {
+        ViewParent parent = mHostView.getParent();
+        mIsHidingAnimated = isHiding;
+        mHostView.invalidate();
+        if (parent instanceof ViewGroup) {
+            ((ViewGroup) parent).invalidate();
+        }
+    }
+
+    public boolean isHidingAnimated() {
+        return mIsHidingAnimated;
+    }
+
+    public View getHostView() {
+        return mHostView;
+    }
+
+    public void reset() {
+        mIsHidingAnimated = false;
+        mIsHistoric = false;
+        mGroup = null;
+        mMessage = null;
+    }
+}
diff --git a/core/java/com/android/internal/widget/MessagingTextMessage.java b/core/java/com/android/internal/widget/MessagingTextMessage.java
new file mode 100644
index 0000000..794cc1d
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingTextMessage.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
+import android.app.Notification;
+import android.content.Context;
+import android.text.Layout;
+import android.util.AttributeSet;
+import android.util.Pools;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.RemoteViews;
+
+import com.android.internal.R;
+
+import java.util.Objects;
+
+/**
+ * A message of a {@link MessagingLayout}.
+ */
+@RemoteViews.RemoteView
+public class MessagingTextMessage extends ImageFloatingTextView implements MessagingMessage {
+
+    private static Pools.SimplePool<MessagingTextMessage> sInstancePool
+            = new Pools.SynchronizedPool<>(20);
+    private final MessagingMessageState mState = new MessagingMessageState(this);
+
+    public MessagingTextMessage(@NonNull Context context) {
+        super(context);
+    }
+
+    public MessagingTextMessage(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public MessagingTextMessage(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public MessagingTextMessage(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    public MessagingMessageState getState() {
+        return mState;
+    }
+
+    @Override
+    public boolean setMessage(Notification.MessagingStyle.Message message) {
+        MessagingMessage.super.setMessage(message);
+        setText(message.getText());
+        return true;
+    }
+
+    static MessagingMessage createMessage(MessagingLayout layout,
+            Notification.MessagingStyle.Message m) {
+        MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
+        MessagingTextMessage createdMessage = sInstancePool.acquire();
+        if (createdMessage == null) {
+            createdMessage = (MessagingTextMessage) LayoutInflater.from(
+                    layout.getContext()).inflate(
+                            R.layout.notification_template_messaging_text_message,
+                            messagingLinearLayout,
+                            false);
+            createdMessage.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
+        }
+        createdMessage.setMessage(m);
+        return createdMessage;
+    }
+
+    public void recycle() {
+        MessagingMessage.super.recycle();
+        setAlpha(1.0f);
+        setTranslationY(0);
+        sInstancePool.release(this);
+    }
+
+    public static void dropCache() {
+        sInstancePool = new Pools.SynchronizedPool<>(10);
+    }
+
+    @Override
+    public int getMeasuredType() {
+        boolean measuredTooSmall = getMeasuredHeight()
+                < getLayoutHeight() + getPaddingTop() + getPaddingBottom();
+        if (measuredTooSmall) {
+            return MEASURED_TOO_SMALL;
+        } else {
+            Layout layout = getLayout();
+            if (layout == null) {
+                return MEASURED_TOO_SMALL;
+            }
+            if (layout.getEllipsisCount(layout.getLineCount() - 1) > 0) {
+                return MEASURED_SHORTENED;
+            } else {
+                return MEASURED_NORMAL;
+            }
+        }
+    }
+
+    @Override
+    public void setMaxDisplayedLines(int lines) {
+        setMaxLines(lines);
+    }
+
+    @Override
+    public int getConsumedLines() {
+        return getLineCount();
+    }
+
+    public int getLayoutHeight() {
+        Layout layout = getLayout();
+        if (layout == null) {
+            return 0;
+        }
+        return layout.getHeight();
+    }
+
+    @Override
+    public void setColor(int color) {
+        setTextColor(color);
+    }
+}
diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
index ad6020c..7d1c706 100644
--- a/core/java/com/android/internal/widget/VerifyCredentialResponse.java
+++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
@@ -98,6 +98,8 @@
             if (mPayload != null) {
                 dest.writeInt(mPayload.length);
                 dest.writeByteArray(mPayload);
+            } else {
+                dest.writeInt(0);
             }
         }
     }
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index d5b6def..64bdc6e 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -31,6 +31,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.MathUtils;
+import android.view.AbsSavedState;
 import android.view.FocusFinder;
 import android.view.Gravity;
 import android.view.KeyEvent;
@@ -1198,16 +1199,12 @@
      * state, in which case it should implement a subclass of this which
      * contains that state.
      */
-    public static class SavedState extends BaseSavedState {
+    public static class SavedState extends AbsSavedState {
         int position;
         Parcelable adapterState;
         ClassLoader loader;
 
-        public SavedState(Parcel source) {
-            super(source);
-        }
-
-        public SavedState(Parcelable superState) {
+        public SavedState(@NonNull Parcelable superState) {
             super(superState);
         }
 
@@ -1225,10 +1222,15 @@
                     + " position=" + position + "}";
         }
 
-        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
+
             @Override
             public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
+                return new SavedState(in, null);
             }
             @Override
             public SavedState[] newArray(int size) {
@@ -1237,7 +1239,7 @@
         };
 
         SavedState(Parcel in, ClassLoader loader) {
-            super(in);
+            super(in, loader);
             if (loader == null) {
                 loader = getClass().getClassLoader();
             }
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index fb18669..95534e2 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -72,6 +72,7 @@
         SystemProperties.getInt("ro.debuggable", 0) == 1 ? 98304 : 65536;
 
     private static final File TOMBSTONE_DIR = new File("/data/tombstones");
+    private static final String TAG_TOMBSTONE = "SYSTEM_TOMBSTONE";
 
     // The pre-froyo package and class of the system updater, which
     // ran in the system process.  We need to remove its packages here
@@ -164,7 +165,7 @@
             .append("Revision: ")
             .append(SystemProperties.get("ro.revision", "")).append("\n")
             .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
-            .append("Radio: ").append(Build.RADIO).append("\n")
+            .append("Radio: ").append(Build.getRadioVersion()).append("\n")
             .append("Kernel: ")
             .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
             .append("\n").toString();
@@ -265,7 +266,7 @@
                     File file = new File(TOMBSTONE_DIR, path);
                     if (file.isFile()) {
                         addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE,
-                                "SYSTEM_TOMBSTONE");
+                                TAG_TOMBSTONE);
                     }
                 } catch (IOException e) {
                     Slog.e(TAG, "Can't log tombstone", e);
@@ -299,9 +300,20 @@
 
         timestamps.put(filename, fileTime);
 
+
+        String fileContents = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
+        String text = headers + fileContents + footers;
+        // Create an additional report for system server native crashes, with a special tag.
+        if (tag.equals(TAG_TOMBSTONE) && fileContents.contains(">>> system_server <<<")) {
+            addTextToDropBox(db, "system_server_native_crash", text, filename, maxSize);
+        }
+        addTextToDropBox(db, tag, text, filename, maxSize);
+    }
+
+    private static void addTextToDropBox(DropBoxManager db, String tag, String text,
+            String filename, int maxSize) {
         Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
-        db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") +
-                footers);
+        db.addText(tag, text);
         EventLog.writeEvent(DropboxLogTags.DROPBOX_FILE_COPY, filename, maxSize, tag);
     }
 
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 937b3ff..48aef4a 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -90,7 +90,7 @@
 }
 
 static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
-        jint givenWeight, jint givenItalic) {
+        jint weight, jint italic) {
     uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
     for (const auto& axis : builder->axes) {
         skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
@@ -114,27 +114,15 @@
     std::shared_ptr<minikin::MinikinFont> minikinFont =
             std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
                     builder->axes);
+    minikin::Font::Builder fontBuilder(minikinFont);
 
-    int weight = givenWeight;
-    bool italic = givenItalic == 1;
-    if (givenWeight == RESOLVE_BY_FONT_TABLE || givenItalic == RESOLVE_BY_FONT_TABLE) {
-        int os2Weight;
-        bool os2Italic;
-        if (!minikin::FontFamily::analyzeStyle(minikinFont, &os2Weight, &os2Italic)) {
-            ALOGE("analyzeStyle failed. Using default style");
-            os2Weight = 400;
-            os2Italic = false;
-        }
-        if (givenWeight == RESOLVE_BY_FONT_TABLE) {
-            weight = os2Weight;
-        }
-        if (givenItalic == RESOLVE_BY_FONT_TABLE) {
-            italic = os2Italic;
-        }
+    if (weight != RESOLVE_BY_FONT_TABLE) {
+        fontBuilder.setWeight(weight);
     }
-
-    builder->fonts.push_back(minikin::Font(minikinFont,
-            minikin::FontStyle(weight, static_cast<minikin::FontStyle::Slant>(italic))));
+    if (italic != RESOLVE_BY_FONT_TABLE) {
+        fontBuilder.setSlant(static_cast<minikin::FontStyle::Slant>(italic != 0));
+    }
+    builder->fonts.push_back(fontBuilder.build());
     builder->axes.clear();
     return true;
 }
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 115d0d5..482d028 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -576,7 +576,7 @@
         minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
         float saveSkewX = paint->getTextSkewX();
         bool savefakeBold = paint->isFakeBoldText();
-        MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
+        MinikinFontSkia::populateSkPaint(paint, baseFont.font->typeface().get(), baseFont.fakery);
         SkScalar spacing = paint->getFontMetrics(metrics);
         // The populateSkPaint call may have changed fake bold / text skew
         // because we want to measure with those effects applied, so now
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 6b961f5..06de5da 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -573,6 +573,11 @@
     minikin::Layout::purgeCaches();
 }
 
+static void setCompatibilityVersion(JNIEnv* env, jobject, jint apiLevel) {
+    Canvas::setCompatibilityVersion(apiLevel);
+}
+
+
 }; // namespace CanvasJNI
 
 static const JNINativeMethod gMethods[] = {
@@ -580,6 +585,7 @@
     {"nInitRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
     {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches},
     {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
+    {"nSetCompatibilityVersion", "(I)V", (void*) CanvasJNI::setCompatibilityVersion},
 
     // ------------ @FastNative ----------------
     {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 1659168..e8ef349 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -32,10 +32,13 @@
 static jclass gHashMapClazz;
 static jmethodID gHashMapInit;
 static jmethodID gHashMapPut;
+static jclass gLongClazz;
+static jmethodID gLongValueOf;
 
 namespace android {
 
 using vintf::HalManifest;
+using vintf::Level;
 using vintf::SchemaType;
 using vintf::VintfObject;
 using vintf::XmlConverter;
@@ -154,6 +157,14 @@
     return jMap;
 }
 
+static jobject android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion(JNIEnv* env, jclass) {
+    std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest();
+    if (manifest == nullptr || manifest->level() == Level::UNSPECIFIED) {
+        return nullptr;
+    }
+    return env->CallStaticObjectMethod(gLongClazz, gLongValueOf, static_cast<jlong>(manifest->level()));
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gVintfObjectMethods[] = {
@@ -163,6 +174,7 @@
     {"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions},
     {"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion},
     {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots},
+    {"getTargetFrameworkCompatibilityMatrixVersion", "()Ljava/lang/Long;", (void*)android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion},
 };
 
 const char* const kVintfObjectPathName = "android/os/VintfObject";
@@ -175,6 +187,8 @@
     gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V");
     gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz,
             "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+    gLongClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/Long"));
+    gLongValueOf = GetStaticMethodIDOrDie(env, gLongClazz, "valueOf", "(J)Ljava/lang/Long;");
 
     return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods,
             NELEM(gVintfObjectMethods));
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 1350f3f..5b788a6 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -673,7 +673,7 @@
         nativeData->mObject = val;
         gNativeDataCache = nullptr;
         ++gNumProxies;
-        if (++gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) {
+        if (gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) {
             ALOGW("Unexpectedly many live BinderProxies: %d\n", gNumProxies);
             gProxiesWarned = gNumProxies;
         }
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 0b0ed83..698f394 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -204,7 +204,10 @@
         (section).args = "power --proto"
     ];
 
-    optional android.service.print.PrintServiceDumpProto print = 3010;
+    optional android.service.print.PrintServiceDumpProto print = 3010 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "print --proto"
+    ];
 
     optional android.service.procstats.ProcessStatsServiceDumpProto procstats = 3011 [
         (section).type = SECTION_DUMPSYS,
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index ff0f4fd..f2b7ab2 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -422,7 +422,7 @@
     optional SettingProto notification_snooze_options = 341 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto enable_gnss_raw_meas_full_tracking = 346 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto zram_enabled = 347 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_smart_replies_in_notifications = 348 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto smart_replies_in_notifications_flags = 348 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto show_first_crash_dialog = 349 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto show_restart_in_crash_dialog = 351 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
index 0342c9c..d1c5db6 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -104,11 +104,6 @@
 
   repeated InFlightProto outstanding_deliveries = 34;
 
-  // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling. It
-  // should be either CosntantsProto.allow_while_idle_short_duration_ms or
-  // ConstantsProto.allow_while_idle_long_duration_ms.
-  optional int64 allow_while_idle_min_duration_ms = 35;
-
   message LastAllowWhileIdleDispatch {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -121,7 +116,7 @@
   }
 
   // Whether the short or long while-idle timeout should be used for each UID.
-  repeated int32 use_allow_while_idle_short_time = 42;
+  repeated int32 use_allow_while_idle_short_time = 35;
 
   // For each uid, this is the last time we dispatched an "allow while idle"
   // alarm, used to determine the earliest we can dispatch the next such alarm.
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index b5c3ac0..5cb5319 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -227,7 +227,6 @@
         optional int32 setting_minimum = 1;
         optional int32 setting_maximum = 2;
         optional int32 setting_default = 3;
-        optional int32 setting_for_vr_default = 4;
     }
 
     // True to decouple auto-suspend mode from the display state.
@@ -293,44 +292,27 @@
     // The stay on while plugged in setting.
     // A set of battery conditions under which to make the screen stay on.
     optional StayOnWhilePluggedInProto stay_on_while_plugged_in = 29;
-    // The screen brightness setting, from 0 to 255.
-    // Use -1 if no value has been set.
-    optional sint32 screen_brightness_setting = 30;
-    // The screen auto-brightness adjustment setting, from -1 to 1.
-    // Use 0 if there is no adjustment.
-    optional float screen_auto_brightness_adjustment_setting = 31;
     // The screen brightness mode.
-    optional .android.providers.settings.SettingsProto.ScreenBrightnessMode screen_brightness_mode_setting = 32;
+    optional .android.providers.settings.SettingsProto.ScreenBrightnessMode screen_brightness_mode_setting = 30;
     // The screen brightness setting override from the window manager
     // to allow the current foreground activity to override the brightness.
     // Use -1 to disable.
-    optional sint32 screen_brightness_override_from_window_manager = 33;
+    optional sint32 screen_brightness_override_from_window_manager = 31;
     // The user activity timeout override from the window manager
     // to allow the current foreground activity to override the user activity
     // timeout. Use -1 to disable.
-    optional sint64 user_activity_timeout_override_from_window_manager_ms = 34;
+    optional sint64 user_activity_timeout_override_from_window_manager_ms = 32;
     // The window manager has determined the user to be inactive via other means.
     // Set this to false to disable.
-    optional bool is_user_inactive_override_from_window_manager = 35;
-    // The screen brightness setting override from the settings application
-    // to temporarily adjust the brightness until next updated,
-    // Use -1 to disable.
-    optional sint32 temporary_screen_brightness_setting_override = 36;
-    // The screen brightness adjustment setting override from the settings
-    // application to temporarily adjust the auto-brightness adjustment factor
-    // until next updated, in the range -1..1.
-    // Use NaN to disable.
-    optional float temporary_screen_auto_brightness_adjustment_setting_override = 37;
+    optional bool is_user_inactive_override_from_window_manager = 33;
     // The screen state to use while dozing.
-    optional .android.view.DisplayStateEnum doze_screen_state_override_from_dream_manager = 38;
+    optional .android.view.DisplayStateEnum doze_screen_state_override_from_dream_manager = 34;
     // The screen brightness to use while dozing.
-    optional float dozed_screen_brightness_override_from_dream_manager = 39;
+    optional float dozed_screen_brightness_override_from_dream_manager = 35;
     // Screen brightness settings limits.
-    optional ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 40;
-    // The screen brightness setting, from 0 to 255, to be used while in VR Mode.
-    optional int32 screen_brightness_for_vr_setting = 41;
+    optional ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 36;
     // True if double tap to wake is enabled
-    optional bool is_double_tap_wake_enabled = 42;
+    optional bool is_double_tap_wake_enabled = 37;
     // True if we are currently in VR Mode.
-    optional bool is_vr_mode_enabled = 43;
+    optional bool is_vr_mode_enabled = 38;
 }
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 449e546..c11058a 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -295,6 +295,7 @@
   optional bool animating_exit = 14;
   repeated WindowStateProto child_windows = 15;
   optional .android.graphics.RectProto surface_position = 16;
+  optional .android.graphics.RectProto shown_position = 17;
   optional int32 requested_width = 18;
   optional int32 requested_height = 19;
   optional int32 view_visibility = 20;
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index ef777de..f8050a1 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -49,7 +49,8 @@
         option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
         optional int32 user_id = 1;
-        optional string name = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
+        // Name of the shared UID. eg: android.uid.bluetooth
+        optional string name = 2;
     }
 
     // Installed packages.
diff --git a/core/proto/android/service/print.proto b/core/proto/android/service/print.proto
index c2be7f1..f783b86 100644
--- a/core/proto/android/service/print.proto
+++ b/core/proto/android/service/print.proto
@@ -21,13 +21,18 @@
 option java_outer_classname = "PrintServiceProto";
 
 import "frameworks/base/core/proto/android/content/component_name.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message PrintServiceDumpProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Each user has a separate printer state
     repeated PrintUserStateProto userStates = 1;
 }
 
 message PrintUserStateProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Should be 0, 10, 11, 12, etc. where 0 is the owner.
     optional int32 user_id = 1;
 
@@ -51,6 +56,8 @@
 }
 
 message PrintSpoolerStateProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Is the print spooler destroyed?
     optional bool is_destroyed = 1;
 
@@ -62,6 +69,8 @@
 }
 
 message PrintSpoolerInternalStateProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Print jobs
     repeated PrintJobInfoProto print_jobs = 1;
 
@@ -73,6 +82,8 @@
 }
 
 message PrinterCapabilitiesProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Minimum margins of the printer
     optional MarginsProto min_margins = 1;
 
@@ -90,6 +101,8 @@
 }
 
 message PrinterInfoProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // The id of the printer
     optional PrinterIdProto id = 1;
 
@@ -120,6 +133,8 @@
 }
 
 message PrinterDiscoverySessionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Is this session destroyed?
     optional bool is_destroyed = 1;
 
@@ -140,6 +155,8 @@
 }
 
 message InstalledPrintServiceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Component name of the service
     optional android.content.ComponentNameProto component_name = 1;
 
@@ -154,14 +171,18 @@
 }
 
 message PrinterIdProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Component name of the service that reported the printer
     optional android.content.ComponentNameProto service_name = 1;
 
     // Local id of the printer
-    optional string local_id = 2;
+    optional string local_id = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
 }
 
 message ActivePrintServiceProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Component name of the service
     optional android.content.ComponentNameProto component_name = 1;
 
@@ -185,6 +206,8 @@
 }
 
 message MediaSizeProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Id of this media size
     optional string id = 1;
 
@@ -199,6 +222,8 @@
 }
 
 message ResolutionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Id of this resolution
     optional string id = 1;
 
@@ -213,6 +238,8 @@
 }
 
 message MarginsProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Space at the top
     optional int32 top_mils = 1;
 
@@ -227,6 +254,8 @@
 }
 
 message PrintAttributesProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Media to use
     optional ResolutionProto media_size = 1;
 
@@ -270,8 +299,10 @@
 }
 
 message PrintDocumentInfoProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Name of the document to print
-    optional string name = 1;
+    optional string name = 1 [ (android.privacy).dest = DEST_EXPLICIT ];
 
     // Number of pages in the doc
     optional int32 page_count = 2;
@@ -284,6 +315,8 @@
 }
 
 message PageRangeProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Start of the range
     optional int32 start = 1;
 
@@ -292,8 +325,10 @@
 }
 
 message PrintJobInfoProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Label of the job
-    optional string label = 1;
+    optional string label = 1 [ (android.privacy).dest = DEST_EXPLICIT ];
 
     // Id of the job
     optional string print_job_id = 2;
@@ -359,6 +394,8 @@
 }
 
 message CachedPrintJobProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // The id of the app the job belongs to
     optional int32 app_id = 1;
 
diff --git a/core/proto/android/telecomm/enums.proto b/core/proto/android/telecomm/enums.proto
new file mode 100644
index 0000000..7a2ba62
--- /dev/null
+++ b/core/proto/android/telecomm/enums.proto
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.telecom;
+
+option java_outer_classname = "TelecomProtoEnums";
+option java_multiple_files = true;
+
+/**
+ * Call states, primarily used in CallState.java,
+ * Call.java, and CallsManager.java in packages/services.
+ */
+enum CallStateEnum {
+    /**
+     * Indicates that a call is new and not connected. This is used as the default state internally
+     * within Telecom and should not be used between Telecom and call services. Call services are
+     * not expected to ever interact with NEW calls, but {@link android.telecom.InCallService}s will
+     * see calls in this state.
+     */
+    NEW = 0;
+
+    /**
+     * The initial state of an outgoing {@code Call}.
+     * Common transitions are to {@link #DIALING} state for a successful call or
+     * {@link #DISCONNECTED} if it failed.
+     */
+    CONNECTING = 1;
+
+    /**
+     * The state of an outgoing {@code Call} when waiting on user to select a
+     * {@link android.telecom.PhoneAccount} through which to place the call.
+     */
+    SELECT_PHONE_ACCOUNT = 2;
+
+    /**
+     * Indicates that a call is outgoing and in the dialing state. A call transitions to this state
+     * once an outgoing call has begun (e.g., user presses the dial button in Dialer). Calls in this
+     * state usually transition to {@link #ACTIVE} if the call was answered or {@link #DISCONNECTED}
+     * if the call was disconnected somehow (e.g., failure or cancellation of the call by the user).
+     */
+    DIALING = 3;
+
+    /**
+     * Indicates that a call is incoming and the user still has the option of answering, rejecting,
+     * or doing nothing with the call. This state is usually associated with some type of audible
+     * ringtone. Normal transitions are to {@link #ACTIVE} if answered or {@link #DISCONNECTED}
+     * otherwise.
+     */
+    RINGING = 4;
+
+    /**
+     * Indicates that a call is currently connected to another party and a communication channel is
+     * open between them. The normal transition to this state is by the user answering a
+     * {@link #DIALING} call or a {@link #RINGING} call being answered by the other party.
+     */
+    ACTIVE = 5;
+
+    /**
+     * Indicates that the call is currently on hold. In this state, the call is not terminated
+     * but no communication is allowed until the call is no longer on hold. The typical transition
+     * to this state is by the user putting an {@link #ACTIVE} call on hold by explicitly performing
+     * an action, such as clicking the hold button.
+     */
+    ON_HOLD = 6;
+
+    /**
+     * Indicates that a call is currently disconnected. All states can transition to this state
+     * by the call service giving notice that the connection has been severed. When the user
+     * explicitly ends a call, it will not transition to this state until the call service confirms
+     * the disconnection or communication was lost to the call service currently responsible for
+     * this call (e.g., call service crashes).
+     */
+    DISCONNECTED = 7;
+
+    /**
+     * Indicates that the call was attempted (mostly in the context of outgoing, at least at the
+     * time of writing) but cancelled before it was successfully connected.
+     */
+    ABORTED = 8;
+
+    /**
+     * Indicates that the call is in the process of being disconnected and will transition next
+     * to a {@link #DISCONNECTED} state.
+     * <p>
+     * This state is not expected to be communicated from the Telephony layer, but will be reported
+     * to the InCall UI for calls where disconnection has been initiated by the user but the
+     * ConnectionService has confirmed the call as disconnected.
+     */
+    DISCONNECTING = 9;
+
+    /**
+     * Indicates that the call is in the process of being pulled to the local device.
+     * <p>
+     * This state should only be set on a call with
+     * {@link android.telecom.Connection#PROPERTY_IS_EXTERNAL_CALL} and
+     * {@link android.telecom.Connection#CAPABILITY_CAN_PULL_CALL}.
+     */
+    PULLING = 10;
+}
+
+// Disconnect causes for a call. Primarily used by android/telecom/DisconnectCause.java
+enum DisconnectCauseEnum {
+    /**
+     * Disconnected because of an unknown or unspecified reason.
+     */
+    UNKNOWN = 0;
+
+    /**
+     * Disconnected because there was an error, such as a problem with the network.
+     */
+    ERROR = 1;
+
+    /**
+     * Disconnected because of a local user-initiated action, such as hanging up.
+     */
+    LOCAL = 2;
+
+    /**
+     * Disconnected because of a remote user-initiated action, such as the other party hanging up
+     * up.
+     */
+    REMOTE = 3;
+
+    /**
+     * Disconnected because it has been canceled.
+     */
+    CANCELED = 4;
+
+    /**
+     * Disconnected because there was no response to an incoming call.
+     */
+    MISSED = 5;
+
+    /**
+     * Disconnected because the user rejected an incoming call.
+     */
+    REJECTED = 6;
+
+    /**
+     * Disconnected because the other party was busy.
+     */
+    BUSY = 7;
+
+    /**
+     * Disconnected because of a restriction on placing the call, such as dialing in airplane
+     * mode.
+     */
+    RESTRICTED = 8;
+
+    /**
+     * Disconnected for reason not described by other disconnect codes.
+     */
+    OTHER = 9;
+
+    /**
+     * Disconnected because the connection manager did not support the call. The call will be tried
+     * again without a connection manager. See {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}.
+     */
+    CONNECTION_MANAGER_NOT_SUPPORTED = 10;
+
+    /**
+     * Disconnected because the user did not locally answer the incoming call, but it was answered
+     * on another device where the call was ringing.
+     */
+    ANSWERED_ELSEWHERE = 11;
+
+    /**
+     * Disconnected because the call was pulled from the current device to another device.
+     */
+    CALL_PULLED = 12;
+}
diff --git a/core/proto/android/view/displayinfo.proto b/core/proto/android/view/displayinfo.proto
index 3ac8f3b..cbd06fd 100644
--- a/core/proto/android/view/displayinfo.proto
+++ b/core/proto/android/view/displayinfo.proto
@@ -29,4 +29,5 @@
   optional int32 logical_height = 2;
   optional int32 app_width = 3;
   optional int32 app_height = 4;
+  optional string name = 5;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f627aaa..8612916 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -53,6 +53,7 @@
     <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
     <protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
     <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.SPLIT_CONFIGURATION_CHANGED" />
     <protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BATTERY_LOW" />
@@ -572,6 +573,10 @@
     <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" />
     <protected-broadcast android:name="com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" />
 
+    <!-- Time zone rules update intents fired by the system server -->
+    <protected-broadcast android:name="com.android.intent.action.timezone.RULES_UPDATE_OPERATION" />
+    <protected-broadcast android:name="com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK" />
+
     <!-- Made protected in P (was introduced in JB-MR2) -->
     <protected-broadcast android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
     <protected-broadcast android:name="android.telephony.euicc.action.OTA_STATUS_CHANGED" />
@@ -1411,6 +1416,12 @@
     <permission android:name="android.permission.MANAGE_LOWPAN_INTERFACES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide Allows internal management of Wi-Fi connectivity state when on
+         permission review mode.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_WIFI_WHEN_PERMISSION_REVIEW_REQUIRED"
+        android:protectionLevel="signature" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
@@ -1494,6 +1505,11 @@
     <permission android:name="android.permission.NFC_HANDOVER_STATUS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide Allows internal management of Bluetooth state when on permission review mode.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED"
+        android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
     <!-- ================================== -->
@@ -2954,11 +2970,16 @@
     <permission android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi Allows an application to delete cache files.
-    <p>Not for use by third-party applications. -->
+    <!-- @SystemApi 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. -->
     <permission android:name="android.permission.DELETE_CACHE_FILES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to delete cache files.
+         @hide -->
+    <permission android:name="android.permission.INTERNAL_DELETE_CACHE_FILES"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to delete packages.
          <p>Not for use by third-party applications.
          <p>Starting in {@link android.os.Build.VERSION_CODES#N}, user confirmation is requested
@@ -3861,6 +3882,7 @@
                 android:excludeFromRecents="true"
                 android:label="@string/user_owner_label"
                 android:exported="true"
+                android:visibleToInstantApps="true"
                 >
         </activity>
         <activity-alias android:name="com.android.internal.app.ForwardIntentToParent"
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index a6dee8a..f5bbadc 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2017 The Android Open Source Project
+Copyright (C) 2018 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,36 +13,21 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="48dp"
-    android:height="48dp"
-    android:viewportWidth="48"
-    android:viewportHeight="48">
-    <group>
-        <path
-            android:fillColor="#2C292A"
-            android:fillType="evenOdd"
-            android:pathData="M6,26a20,20 0 0,1 40,0a20,20 0 0,1 -40,0z"/>
-        <path
-            android:fillColor="#FAFAFA"
-            android:fillType="evenOdd"
-            android:pathData="M4,24a20,20 0 0,1 40,0a20,20 0 0,1 -40,0z"/>
-        <path
-            android:fillColor="#2C292A"
-            android:fillType="evenOdd"
-            android:pathData="M2,22a20,20 0 0,1 40,0a20,20 0 0,1 -40,0z"/>
-        <path
-            android:fillColor="#00000000"
-            android:strokeColor="#453F41"
-            android:strokeWidth="1"
-            android:fillType="evenOdd"
-            android:pathData="M26.5 29.5v3c0 1.13-.87 2-2 2s-2-.87-2-2v-3h-1v3c0 1.13-.87 2-2 2s-2-.87-2-2v-3H17a1.5 1.5 0 0 1-1.5-1.5V17.5h13V28a1.5 1.5 0 0 1-1.5 1.5h-.5zM13.5 17.5c1.13 0 2 .87 2 2v7c0 1.13-.87 2-2 2s-2-.87-2-2v-7c0-1.13.87-2 2-2zM30.5 17.5c1.13 0 2 .87 2 2v7c0 1.13-.87 2-2 2s-2-.87-2-2v-7c0-1.13.87-2 2-2zM26.3 12.11A6.46 6.46 0 0 1 28.5 17v.5h-13V17a6.46 6.46 0 0 1 2.2-4.89l-.9-.9a.98.98 0 0 1 0-1.41.98.98 0 0 1 1.4 0l1.26 1.25A6.33 6.33 0 0 1 22 10.5c.87 0 1.73.2 2.54.55L25.8 9.8a.98.98 0 0 1 1.4 0 .98.98 0 0 1 0 1.4l-.9.91z"/>
-        <path
-            android:fillColor="#453F41"
-            android:fillType="evenOdd"
-            android:pathData="M20.16 14.5a.66.66 0 1 1-1.31 0c0-.36.29-.65.65-.65.36 0 .65.29.65.65zM25.16 14.5c0 .36-.3.66-.66.66a.65.65 0 1 1 .66-.66z"/>
-        <path
-            android:fillColor="#453F41"
-            android:pathData="M22 40.5c0.36 0 0.73-0.01 1.09-0.03l-0.18-3A15.77 15.77 0 0 1 22 37.5v3zm2.17-0.13a18.48 18.48 0 0 0 1.08-0.15l-0.53-2.96c-0.3 0.05-0.6 0.1-0.9 0.13l0.35 2.98zM26.32 40a18.37 18.37 0 0 0 1.05-0.28l-0.87-2.87a15.37 15.37 0 0 1-0.88 0.23l0.7 2.92zm2.1-0.64l-1.03-2.81a15.39 15.39 0 0 0 0.84-0.34l1.2 2.74a18.39 18.39 0 0 1-1 0.41zm1.99-0.87l-1.37-2.67a15.46 15.46 0 0 0 0.8-0.44l1.52 2.59a18.46 18.46 0 0 1-0.95 0.52zm1.89-1.11l-1.67-2.5a15.55 15.55 0 0 0 0.74-0.52l1.81 2.39a18.55 18.55 0 0 1-0.88 0.63zm1.75-1.33l-1.95-2.28a15.6 15.6 0 0 0 0.67-0.61l2.09 2.15a18.6 18.6 0 0 1-0.8 0.74zm1.6-1.55l-2.22-2.02a15.6 15.6 0 0 0 0.6-0.7l2.33 1.9a18.6 18.6 0 0 1-0.72 0.82zM37 32.82l-2.43-1.76a15.53 15.53 0 0 0 0.5-0.75l2.54 1.6c-0.2 0.31-0.4 0.61-0.61 0.9zm1.15-1.8l-2.62-1.47a15.45 15.45 0 0 0 0.42-0.8l2.7 1.3a18.45 18.45 0 0 1-0.5 0.97zm0.95-1.98l-2.77-1.14a15.38 15.38 0 0 0 0.32-0.86l2.84 0.98a18.38 18.38 0 0 1-0.39 1.02zm0.72-2.09c0.1-0.34 0.18-0.7 0.26-1.05l-2.93-0.63a15.38 15.38 0 0 1-0.22 0.88l2.89 0.8zm0.46-2.15a18.52 18.52 0 0 0 0.13-1.08l-2.99-0.28a15.52 15.52 0 0 1-0.1 0.9l2.96 0.46zm0.2-2.2a18.81 18.81 0 0 0 0-1.1l-3 0.08a16 16 0 0 1 0 0.92l3 0.1zm-0.06-2.2a18.54 18.54 0 0 0-0.12-1.07l-2.97 0.43c0.04 0.3 0.08 0.6 0.1 0.9l3-0.25zm-0.31-2.15a18.39 18.39 0 0 0-0.25-1.06l-2.9 0.78a15.39 15.39 0 0 1 0.21 0.89l2.94-0.6zm-0.57-2.12l-2.85 0.95a15.37 15.37 0 0 0-0.31-0.85l2.78-1.12a18.37 18.37 0 0 1 0.38 1.02zm-0.83-2.06l-2.71 1.29a15.44 15.44 0 0 0-0.42-0.81l2.63-1.45a18.44 18.44 0 0 1 0.5 0.97zm-1.03-1.88l-2.54 1.6a15.53 15.53 0 0 0-0.5-0.76l2.44-1.74 0.6 0.9zm-1.28-1.79l-2.33 1.88a15.6 15.6 0 0 0-0.6-0.69l2.23-2.02a18.6 18.6 0 0 1 0.7 0.83zm-1.48-1.63l-2.1 2.14a15.6 15.6 0 0 0-0.67-0.62l1.97-2.26a18.6 18.6 0 0 1 0.8 0.74zM33.24 7.3l-1.82 2.38a15.55 15.55 0 0 0-0.74-0.53l1.68-2.49c0.3 0.2 0.6 0.42 0.88 0.64zm-1.71-1.17L29.98 8.7a15.47 15.47 0 0 0-0.8-0.45l1.4-2.66a18.47 18.47 0 0 1 0.95 0.54zm-1.95-1.02l-1.23 2.74A15.4 15.4 0 0 0 27.5 7.5l1.06-2.8a18.4 18.4 0 0 1 1.01 0.4zm-2.06-0.78l-0.9 2.86a15.37 15.37 0 0 0-0.87-0.24l0.72-2.92a18.37 18.37 0 0 1 1.05 0.3zM25.38 3.8a18.47 18.47 0 0 0-1.08-0.17l-0.37 2.98c0.3 0.04 0.6 0.08 0.9 0.14l0.55-2.95zm-2.2-0.27A18.75 18.75 0 0 0 22.1 3.5l-0.02 3L23 6.53l0.19-3zM21 3.53a18.6 18.6 0 0 0-1.08 0.09l0.33 2.98a15.6 15.6 0 0 1 0.91-0.08l-0.16-3zm-2.16 0.24A18.4 18.4 0 0 0 17.76 4l0.68 2.92a15.4 15.4 0 0 1 0.9-0.18l-0.51-2.96zm-2.14 0.5l0.86 2.88a15.37 15.37 0 0 0-0.86 0.28l-1.03-2.81a18.37 18.37 0 0 1 1.03-0.35zm-2.07 0.76l1.2 2.75a15.42 15.42 0 0 0-0.83 0.4L13.63 5.5a18.42 18.42 0 0 1 0.99-0.47zM12.7 6l1.5 2.6a15.5 15.5 0 0 0-0.76 0.48l-1.66-2.5A18.5 18.5 0 0 1 12.7 6zm-1.83 1.22l1.8 2.4a15.58 15.58 0 0 0-0.7 0.57L10.01 7.9a18.58 18.58 0 0 1 0.85-0.68zM9.19 8.66l2.07 2.16a15.6 15.6 0 0 0-0.63 0.65l-2.2-2.04a18.6 18.6 0 0 1 0.76-0.77zm-1.51 1.63l2.32 1.9a15.57 15.57 0 0 0-0.56 0.72l-2.42-1.76a18.57 18.57 0 0 1 0.66-0.86zm-1.23 1.69l2.52 1.62a15.5 15.5 0 0 0-0.47 0.78l-2.61-1.47a18.5 18.5 0 0 1 0.56-0.93zm-1.08 1.9l2.7 1.32a15.41 15.41 0 0 0-0.38 0.83l-2.77-1.15a18.41 18.41 0 0 1 0.45-1zm-0.85 2.04l2.84 0.98a15.37 15.37 0 0 0-0.28 0.87L4.2 16.96c0.1-0.35 0.2-0.7 0.32-1.04zm-0.6 2.12a18.43 18.43 0 0 0-0.2 1.07l2.97 0.47c0.05-0.3 0.1-0.6 0.17-0.9l-2.93-0.64zm-0.34 2.18a18.65 18.65 0 0 0-0.07 1.09l3 0.11 0.06-0.91-2.99-0.29zm-0.08 2.2a18.7 18.7 0 0 0 0.06 1.1l3-0.25a15.7 15.7 0 0 1-0.06-0.91l-3 0.07zm0.18 2.18a18.44 18.44 0 0 0 0.18 1.07l2.95-0.6a15.44 15.44 0 0 1-0.16-0.9L3.68 24.6zm0.43 2.14l2.9-0.77a15.37 15.37 0 0 0 0.26 0.88l-2.85 0.94a18.37 18.37 0 0 1-0.3-1.05zm0.7 2.1l2.78-1.11a15.4 15.4 0 0 0 0.36 0.83l-2.71 1.27a18.4 18.4 0 0 1-0.44-1zm0.9 1.95l2.65-1.43a15.48 15.48 0 0 0 0.45 0.8l-2.55 1.57a18.48 18.48 0 0 1-0.54-0.94zm1.17 1.87l2.45-1.73a15.56 15.56 0 0 0 0.54 0.73l-2.34 1.87a18.56 18.56 0 0 1-0.65-0.87zm1.37 1.72l2.23-2a15.6 15.6 0 0 0 0.63 0.65l-2.1 2.14a18.6 18.6 0 0 1-0.76-0.79zm1.58 1.56l1.98-2.26c0.22 0.2 0.46 0.39 0.7 0.58l-1.84 2.37a18.59 18.59 0 0 1-0.84-0.7zm1.66 1.28l1.7-2.46a15.52 15.52 0 0 0 0.77 0.5l-1.56 2.56a18.52 18.52 0 0 1-0.91-0.6zm1.87 1.14l1.4-2.65a15.43 15.43 0 0 0 0.82 0.4l-1.24 2.73a18.43 18.43 0 0 1-0.98-0.48zm2 0.91l1.08-2.8a15.37 15.37 0 0 0 0.86 0.3l-0.9 2.86a18.37 18.37 0 0 1-1.04-0.36zm2.1 0.67a18.4 18.4 0 0 0 1.07 0.23l0.56-2.94a15.4 15.4 0 0 1-0.9-0.2l-0.72 2.91zm2.18 0.41a18.57 18.57 0 0 0 1.08 0.1l0.2-2.99a15.57 15.57 0 0 1-0.9-0.09l-0.38 2.98zm2.2 0.15H22v-3h-0.13l-0.03 3z"/>
-    </group>
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="vector"
+    android:width="640dp"
+    android:height="640dp"
+    android:viewportWidth="64"
+    android:viewportHeight="64">
+    <path
+        android:name="bg"
+        android:pathData="M 27 43 L 32 43 C 38.075 43 43 38.075 43 32 C 43 25.925 38.075 21 32 21 C 25.925 21 21 25.925 21 32 L 21 64"
+        android:strokeColor="#6823a1"
+        android:strokeWidth="16"/>
+    <path
+        android:name="fg"
+        android:pathData="M 29 43 L 32 43 C 38.075 43 43 38.075 43 32 C 43 25.925 38.075 21 32 21 C 25.925 21 21 25.925 21 32 L 21 64"
+        android:strokeColor="#ff0000"
+        android:strokeWidth="8"/>
 </vector>
diff --git a/core/res/res/drawable-nodpi/platlogo_m.xml b/core/res/res/drawable-nodpi/platlogo_m.xml
index aacf674..8e43638 100644
--- a/core/res/res/drawable-nodpi/platlogo_m.xml
+++ b/core/res/res/drawable-nodpi/platlogo_m.xml
@@ -18,23 +18,4 @@
         android:height="480dp"
         android:viewportWidth="48.0"
         android:viewportHeight="48.0">
-    <!--<path
-        android:pathData="M25.0,25.0m-20.5,0.0a20.5,20.5,0,1,1,41.0,0.0a20.5,20.5,0,1,1,-41.0,0.0"
-        android:fillAlpha="0.066"
-        android:fillColor="#000000"/>-->
-    <path
-        android:pathData="M24.0,24.0m-20.0,0.0a20.0,20.0,0,1,1,40.0,0.0a20.0,20.0,0,1,1,-40.0,0.0"
-        android:fillColor="#FFC107"/>
-    <path
-        android:pathData="M44,24.2010101 L33.9004889,14.101499 L14.101499,33.9004889 L24.2010101,44 C29.2525804,43.9497929 34.2887564,41.9975027 38.1431296,38.1431296 C41.9975027,34.2887564 43.9497929,29.2525804 44,24.2010101 Z"
-        android:fillColor="#FE9F00"/>
-    <path
-        android:pathData="M24.0,24.0m-14.0,0.0a14.0,14.0,0,1,1,28.0,0.0a14.0,14.0,0,1,1,-28.0,0.0"
-        android:fillColor="#FED44F"/>
-    <path
-        android:pathData="M37.7829445,26.469236 L29.6578482,18.3441397 L18.3441397,29.6578482 L26.469236,37.7829445 C29.1911841,37.2979273 31.7972024,36.0037754 33.9004889,33.9004889 C36.0037754,31.7972024 37.2979273,29.1911841 37.7829445,26.469236 Z"
-        android:fillColor="#FFC107"/>
-    <path
-        android:pathData="M24.0,24.0m-8.0,0.0a8.0,8.0,0,1,1,16.0,0.0a8.0,8.0,0,1,1,-16.0,0.0"
-        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 2e2b395..0fde2cc 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright (C) 2017 The Android Open Source Project
+Copyright (C) 2018 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,24 +13,24 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <group>
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="vector"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+    <group android:name="stat_sys_adb">
         <path
-            android:fillColor="#FFFFFF"
-            android:fillAlpha=".33"
-            android:fillType="evenOdd"
-            android:pathData="M5.71 18.29A8.99 8.99 0 0 0 22 13c0-3-1.46-5.65-3.71-7.29A8.99 8.99 0 0 0 2 11c0 3 1.46 5.65 3.71 7.29z"/>
+            android:name="outer"
+            android:pathData="M 18 30 L 24 30 C 29.523 30 34 25.523 34 20 C 34 14.477 29.523 10 24 10 C 18.477 10 14 14.477 14 20 L 14 44"
+            android:strokeColor="#000000"
+            android:strokeWidth="10"/>
         <path
-            android:fillColor="#FFFFFF"
-            android:fillType="evenOdd"
-            android:pathData="M7.25 19.18A8.5 8.5 0 0 0 19.19 7.24 9 9 0 0 1 7.24 19.19z"/>
-        <path
-            android:fillColor="#FFFFFF"
-            android:fillAlpha=".33"
-            android:pathData="M10.5 3a0.5 0.5 0 1 1 1 0v2.05a0.5 0.5 0 1 1-1 0V3zm3.1 0.42a0.5 0.5 0 0 1 0.93 0.39l-0.8 1.88A0.5 0.5 0 1 1 12.8 5.3l0.8-1.88zm2.7 1.57a0.5 0.5 0 1 1 0.71 0.7l-1.45 1.46a0.5 0.5 0 0 1-0.7-0.71l1.44-1.45zm1.9 2.5a0.5 0.5 0 0 1 0.38 0.92l-1.9 0.77a0.5 0.5 0 0 1-0.37-0.93l1.9-0.77zM19 10.5a0.5 0.5 0 1 1 0 1h-2.05a0.5 0.5 0 0 1 0-1H19zm-0.42 3.1a0.5 0.5 0 0 1-0.39 0.93l-1.88-0.8a0.5 0.5 0 1 1 0.39-0.92l1.88 0.8zm-1.57 2.7a0.5 0.5 0 1 1-0.7 0.71l-1.46-1.45a0.5 0.5 0 0 1 0.71-0.7l1.45 1.44zm-2.5 1.9a0.5 0.5 0 1 1-0.92 0.38l-0.77-1.9a0.5 0.5 0 0 1 0.93-0.37l0.77 1.9zM11.5 19a0.5 0.5 0 1 1-1 0v-2.05a0.5 0.5 0 0 1 1 0V19zm-3.1-0.42a0.5 0.5 0 0 1-0.93-0.39l0.8-1.88A0.5 0.5 0 0 1 9.2 16.7l-0.8 1.88zm-2.7-1.57a0.5 0.5 0 1 1-0.71-0.7l1.45-1.46a0.5 0.5 0 0 1 0.7 0.71L5.7 17.01zm-1.9-2.48a0.5 0.5 0 0 1-0.38-0.92l1.88-0.8a0.5 0.5 0 0 1 0.4 0.92l-1.9 0.8zM3 11.5a0.5 0.5 0 1 1 0-1h2.05a0.5 0.5 0 1 1 0 1H3zm0.42-3.1A0.5 0.5 0 0 1 3.8 7.46l1.88 0.8A0.5 0.5 0 1 1 5.3 9.2L3.42 8.4zm1.57-2.7a0.5 0.5 0 1 1 0.7-0.71l1.46 1.45a0.5 0.5 0 0 1-0.71 0.7L4.99 5.7zm2.5-1.9A0.5 0.5 0 0 1 8.4 3.41l0.77 1.9a0.5 0.5 0 0 1-0.93 0.37L7.48 3.8z"/>
+            android:name="inner"
+            android:pathData="M 19 30 L 24 30 C 29.523 30 34 25.523 34 20 C 34 14.477 29.523 10 24 10 C 18.477 10 14 14.477 14 20 L 14 44"
+            android:strokeColor="#000000"
+            android:strokeAlpha="0"
+            android:strokeWidth="6"/>
     </group>
-</vector>
\ No newline at end of file
+</vector>
diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml
index 4ac308a..bd1030e 100644
--- a/core/res/res/layout/notification_template_messaging_group.xml
+++ b/core/res/res/layout/notification_template_messaging_group.xml
@@ -28,9 +28,9 @@
         android:scaleType="centerCrop"
         android:importantForAccessibility="no" />
     <com.android.internal.widget.RemeasuringLinearLayout
-        android:id="@+id/message_group_and_sender_container"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_weight="1"
         android:orientation="vertical">
         <com.android.internal.widget.ImageFloatingTextView
             android:id="@+id/message_name"
@@ -44,4 +44,10 @@
             android:spacing="2dp"
             android:layout_weight="1"/>
     </com.android.internal.widget.RemeasuringLinearLayout>
+    <FrameLayout
+        android:id="@+id/messaging_group_icon_container"
+        android:layout_width="@dimen/messaging_avatar_size"
+        android:layout_height="@dimen/messaging_avatar_size"
+        android:layout_marginStart="12dp"
+        android:visibility="gone"/>
 </com.android.internal.widget.MessagingGroup>
diff --git a/core/res/res/layout/notification_template_messaging_message.xml b/core/res/res/layout/notification_template_messaging_image_message.xml
similarity index 71%
copy from core/res/res/layout/notification_template_messaging_message.xml
copy to core/res/res/layout/notification_template_messaging_image_message.xml
index ab6466c..6ca4dcd 100644
--- a/core/res/res/layout/notification_template_messaging_message.xml
+++ b/core/res/res/layout/notification_template_messaging_image_message.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2017 The Android Open Source Project
+  ~ Copyright (C) 2018 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -14,8 +14,11 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<com.android.internal.widget.MessagingMessage
+<com.android.internal.widget.MessagingImageMessage
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/message_text"
-    style="@style/Widget.Material.Notification.MessagingText"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginTop="@dimen/messaging_image_extra_spacing"
+    android:scaleType="fitStart"
 />
diff --git a/core/res/res/layout/notification_template_messaging_message.xml b/core/res/res/layout/notification_template_messaging_text_message.xml
similarity index 94%
rename from core/res/res/layout/notification_template_messaging_message.xml
rename to core/res/res/layout/notification_template_messaging_text_message.xml
index ab6466c..e728e69 100644
--- a/core/res/res/layout/notification_template_messaging_message.xml
+++ b/core/res/res/layout/notification_template_messaging_text_message.xml
@@ -14,7 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<com.android.internal.widget.MessagingMessage
+<com.android.internal.widget.MessagingTextMessage
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/message_text"
     style="@style/Widget.Material.Notification.MessagingText"
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index ce4ac61..e80f16c 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -79,8 +79,8 @@
     <item name="secondary_content_alpha_material_light" format="float" type="dimen">0.54</item>
 
     <item name="highlight_alpha_material_light" format="float" type="dimen">0.16</item>
-    <item name="highlight_alpha_material_dark" format="float" type="dimen">0.32</item>
-    <item name="highlight_alpha_material_colored" format="float" type="dimen">0.48</item>
+    <item name="highlight_alpha_material_dark" format="float" type="dimen">0.16</item>
+    <item name="highlight_alpha_material_colored" format="float" type="dimen">0.16</item>
 
     <!-- Primary & accent colors -->
     <eat-comment />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c8032a2..d2194ba 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1075,6 +1075,14 @@
         <item>10</item>
     </integer-array>
 
+    <!-- The URI to associate with each ringtone effect constant, intended to be used with the
+         android.os.VibrationEffect#get(Uri, Context) API.
+         The position of the string in the string-array determines which ringtone effect is chosen.
+         For example, if the URI passed into get match the third string in the string-array, then
+         RINGTONE_3 will be the returned effect -->
+    <string-array translatable="false" name="config_ringtoneEffectUris">
+    </string-array>
+
     <bool name="config_use_strict_phone_number_comparation">false</bool>
 
     <!-- Display low battery warning when battery level dips to this value.
@@ -2486,9 +2494,9 @@
     <string-array translatable="false" name="config_globalActionsList">
         <item>power</item>
         <item>restart</item>
-        <item>screenshot</item>
-        <item>logout</item>
         <item>lockdown</item>
+        <item>logout</item>
+        <item>screenshot</item>
         <item>bugreport</item>
         <item>users</item>
     </string-array>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index e610efd..0411c6e 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -262,6 +262,18 @@
     <!-- The spacing between messages in Notification.MessagingStyle -->
     <dimen name="notification_messaging_spacing">6dp</dimen>
 
+    <!-- The rounding for messaging images -->
+    <dimen name="messaging_image_rounding">4dp</dimen>
+
+    <!-- The minimum size for any image in messaging style in order to be displayed -->
+    <dimen name="messaging_image_min_size">44dp</dimen>
+
+    <!-- The maximum size for any image in messaging style in order to be displayed -->
+    <dimen name="messaging_image_max_height">136dp</dimen>
+
+    <!-- Extra spacing before and after images in messaging style -->
+    <dimen name="messaging_image_extra_spacing">8dp</dimen>
+
     <!-- Preferred width and height of the search view. -->
     <dimen name="search_view_preferred_width">320dip</dimen>
     <dimen name="search_view_preferred_height">48dip</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 29b09b5..ca698ef 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3168,7 +3168,8 @@
   <java-symbol type="dimen" name="chooser_service_spacing" />
   <java-symbol type="bool" name="config_showSysuiShutdown" />
 
-  <java-symbol type="layout" name="notification_template_messaging_message" />
+  <java-symbol type="layout" name="notification_template_messaging_text_message" />
+  <java-symbol type="layout" name="notification_template_messaging_image_message" />
   <java-symbol type="layout" name="notification_template_messaging_group" />
   <java-symbol type="id" name="message_text" />
   <java-symbol type="id" name="message_name" />
@@ -3183,6 +3184,11 @@
   <java-symbol type="id" name="clip_children_tag" />
   <java-symbol type="drawable" name="ic_reply_notification_large" />
   <java-symbol type="dimen" name="messaging_avatar_size" />
+  <java-symbol type="dimen" name="messaging_image_rounding" />
+  <java-symbol type="dimen" name="messaging_image_min_size" />
+  <java-symbol type="dimen" name="messaging_image_max_height" />
+  <java-symbol type="dimen" name="messaging_image_extra_spacing" />
+  <java-symbol type="id" name="messaging_group_icon_container" />
 
   <java-symbol type="integer" name="config_stableDeviceDisplayWidth" />
   <java-symbol type="integer" name="config_stableDeviceDisplayHeight" />
@@ -3246,4 +3252,6 @@
   <java-symbol type="string" name="screenshot_edit" />
 
   <java-symbol type="bool" name="config_keepRestrictedProfilesInBackground" />
+
+  <java-symbol type="array" name="config_ringtoneEffectUris" />
 </resources>
diff --git a/core/res/res/xml/color_extraction.xml b/core/res/res/xml/color_extraction.xml
index 7d52b20..93ab0ff 100644
--- a/core/res/res/xml/color_extraction.xml
+++ b/core/res/res/xml/color_extraction.xml
@@ -257,52 +257,58 @@
         <!-- Red Orange -->
         <range h="20, 40"
                s="0.7, 1"
-               l="0.28, 0.643"/>
+               l="0.2, 0.643"/>
         <range h="20, 40"
                s="0.3, 0.7"
                l="0.414, 0.561"/>
         <range h="20, 40"
-               s="0, 3"
+               s="0, 0.3"
                l="0.343, 0.584"/>
         <!-- Orange -->
         <range h="40, 60"
                s="0.7, 1"
-               l="0.173, 0.349"/>
+               l="0.173, 0.38"/>
         <range h="40, 60"
                s="0.3, 0.7"
                l="0.233, 0.427"/>
         <range h="40, 60"
                s="0, 0.3"
-               l="0.231, 0.484"/>
+               l="0.231, 0.48"/>
         <!-- Yellow 60 -->
         <range h="60, 80"
                s="0.7, 1"
-               l="0.488, 0.737"/>
+               l="0.15, 0.40"/>
         <range h="60, 80"
                s="0.3, 0.7"
-               l="0.673, 0.837"/>
+               l="0.15, 0.42"/>
+        <range h="60, 80"
+               s="0, 0.3"
+               l="0.35, 0.57"/>
         <!-- Yellow Green 80 -->
         <range h="80, 100"
                s="0.7, 1"
-               l="0.469, 0.61"/>
+               l="0.36, 0.65"/>
+        <range h="80, 100"
+               s="0.3, 0.7"
+               l="0.48, 0.57"/>
         <!-- Yellow green 100 -->
         <range h="100, 120"
                s="0.7, 1"
-               l="0.388, 0.612"/>
+               l="0.388, 0.67"/>
         <range h="100, 120"
                s="0.3, 0.7"
-               l="0.424, 0.541"/>
+               l="0.424, 0.58"/>
         <!-- Green -->
         <range h="120, 140"
                s="0.7, 1"
-               l="0.375, 0.52"/>
+               l="0.37, 0.65"/>
         <range h="120, 140"
                s="0.3, 0.7"
-               l="0.435, 0.524"/>
+               l="0.435, 0.58"/>
         <!-- Green Blue 140 -->
         <range h="140, 160"
                s="0.7, 1"
-               l="0.496, 0.641"/>
+               l="0.43, 0.641"/>
         <!-- Seaoam -->
         <range h="160, 180"
                s="0.7, 1"
diff --git a/core/tests/coretests/res/layout/activity_text_view.xml b/core/tests/coretests/res/layout/activity_text_view.xml
index dca1656..d5be87d 100644
--- a/core/tests/coretests/res/layout/activity_text_view.xml
+++ b/core/tests/coretests/res/layout/activity_text_view.xml
@@ -24,6 +24,9 @@
             android:id="@+id/textview"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
+    <Space
+        android:layout_width="1dp"
+        android:layout_height="60dp"/>
 
     <TextView
         android:id="@+id/nonselectable_textview"
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index aefc47e..fb0f534 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -17,6 +17,7 @@
 package android.app.servertransaction;
 
 import static android.app.servertransaction.TestUtils.config;
+import static android.app.servertransaction.TestUtils.mergedConfig;
 import static android.app.servertransaction.TestUtils.referrerIntentList;
 import static android.app.servertransaction.TestUtils.resultInfoList;
 
@@ -151,6 +152,25 @@
     }
 
     @Test
+    public void testRecycleActivityRelaunchItem() {
+        ActivityRelaunchItem emptyItem = ActivityRelaunchItem.obtain(null, null, 0, null, false);
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.assetsSeq = 5;
+        ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(),
+                referrerIntentList(), 42, mergedConfig(), true);
+        assertNotSame(item, emptyItem);
+        assertFalse(item.equals(emptyItem));
+
+        item.recycle();
+        assertEquals(item, emptyItem);
+
+        ActivityRelaunchItem item2 = ActivityRelaunchItem.obtain(resultInfoList(),
+                referrerIntentList(), 42, mergedConfig(), true);
+        assertSame(item, item2);
+        assertFalse(item2.equals(emptyItem));
+    }
+
+    @Test
     public void testRecycleMoveToDisplayItem() {
         MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain(0, null);
         MoveToDisplayItem item = MoveToDisplayItem.obtain(4, config());
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index e923516..d125fe7 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -21,6 +21,7 @@
 import android.app.ResultInfo;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.util.MergedConfiguration;
 
 import com.android.internal.content.ReferrerIntent;
 
@@ -38,6 +39,15 @@
         return config;
     }
 
+    static MergedConfiguration mergedConfig() {
+        Configuration config = config();
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.densityDpi = 30;
+        overrideConfig.screenWidthDp = 40;
+        overrideConfig.smallestScreenWidthDp = 15;
+        return new MergedConfiguration(config, overrideConfig);
+    }
+
     static List<ResultInfo> resultInfoList() {
         String resultWho1 = "resultWho1";
         int requestCode1 = 7;
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 77aaa2d..0906435 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -17,6 +17,7 @@
 package android.app.servertransaction;
 
 import static android.app.servertransaction.TestUtils.config;
+import static android.app.servertransaction.TestUtils.mergedConfig;
 import static android.app.servertransaction.TestUtils.referrerIntentList;
 import static android.app.servertransaction.TestUtils.resultInfoList;
 
@@ -27,7 +28,6 @@
 import android.app.IInstrumentationWatcher;
 import android.app.IUiAutomationConnection;
 import android.app.ProfilerInfo;
-import android.app.ResultInfo;
 import android.content.ComponentName;
 import android.content.IIntentReceiver;
 import android.content.Intent;
@@ -53,7 +53,6 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.content.ReferrerIntent;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -243,6 +242,22 @@
     }
 
     @Test
+    public void testRelaunch() {
+        // Write to parcel
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.assetsSeq = 5;
+        ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(),
+                referrerIntentList(), 35, mergedConfig(), true);
+        writeAndPrepareForReading(item);
+
+        // Read from parcel and assert
+        ActivityRelaunchItem result = ActivityRelaunchItem.CREATOR.createFromParcel(mParcel);
+
+        assertEquals(item.hashCode(), result.hashCode());
+        assertTrue(item.equals(result));
+    }
+
+    @Test
     public void testPause() {
         // Write to parcel
         PauseActivityItem item = PauseActivityItem.obtain(true /* finished */,
@@ -435,12 +450,6 @@
         }
 
         @Override
-        public void scheduleRelaunchActivity(IBinder iBinder, List<ResultInfo> list,
-                List<ReferrerIntent> list1, int i, boolean b, Configuration configuration,
-                Configuration configuration1, boolean b1) throws RemoteException {
-        }
-
-        @Override
         public void scheduleSleeping(IBinder iBinder, boolean b) throws RemoteException {
         }
 
diff --git a/core/tests/coretests/src/android/os/VibrationEffectTest.java b/core/tests/coretests/src/android/os/VibrationEffectTest.java
new file mode 100644
index 0000000..c7fdf0f
--- /dev/null
+++ b/core/tests/coretests/src/android/os/VibrationEffectTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
+
+import com.android.internal.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class VibrationEffectTest {
+    private static final String RINGTONE_URI_1 = "content://test/system/ringtone_1";
+    private static final String RINGTONE_URI_2 = "content://test/system/ringtone_2";
+    private static final String RINGTONE_URI_3 = "content://test/system/ringtone_3";
+    private static final String UNKNOWN_URI = "content://test/system/other_audio";
+
+    @Test
+    public void getRingtones_noPrebakedRingtones() {
+        Resources r = mockRingtoneResources(new String[0]);
+        Context context = mockContext(r);
+        VibrationEffect effect = VibrationEffect.get(Uri.parse(RINGTONE_URI_1), context);
+        assertNull(effect);
+    }
+
+    @Test
+    public void getRingtones_noPrebakedRingtoneForUri() {
+        Resources r = mockRingtoneResources();
+        Context context = mockContext(r);
+        VibrationEffect effect = VibrationEffect.get(Uri.parse(UNKNOWN_URI), context);
+        assertNull(effect);
+    }
+
+    @Test
+    public void getRingtones_getPrebakedRingtone() {
+        Resources r = mockRingtoneResources();
+        Context context = mockContext(r);
+        VibrationEffect effect = VibrationEffect.get(Uri.parse(RINGTONE_URI_2), context);
+        VibrationEffect expectedEffect = VibrationEffect.get(VibrationEffect.RINGTONES[1]);
+        assertNotNull(expectedEffect);
+        assertEquals(expectedEffect, effect);
+    }
+
+
+    private Resources mockRingtoneResources() {
+        return mockRingtoneResources(new String[] {
+                RINGTONE_URI_1,
+                RINGTONE_URI_2,
+                RINGTONE_URI_3
+        });
+    }
+
+    private Resources mockRingtoneResources(String[] ringtoneUris) {
+        Resources mockResources = mock(Resources.class);
+        when(mockResources.getStringArray(R.array.config_ringtoneEffectUris))
+                .thenReturn(ringtoneUris);
+        return mockResources;
+    }
+
+    private Context mockContext(Resources r) {
+        Context ctx = mock(Context.class);
+        when(ctx.getResources()).thenReturn(r);
+        return ctx;
+    }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 6602bf6..5bb9abe 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -109,6 +109,8 @@
                     Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS,
                     Settings.Global.ANIMATOR_DURATION_SCALE,
                     Settings.Global.ANOMALY_DETECTION_CONSTANTS,
+                    Settings.Global.ANOMALY_CONFIG,
+                    Settings.Global.ANOMALY_CONFIG_VERSION,
                     Settings.Global.APN_DB_UPDATE_CONTENT_URL,
                     Settings.Global.APN_DB_UPDATE_METADATA_URL,
                     Settings.Global.APP_IDLE_CONSTANTS,
@@ -194,6 +196,7 @@
                     Settings.Global.DEVICE_PROVISIONED,
                     Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED,
                     Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
+                    Settings.Global.DISPLAY_PANEL_LPM,
                     Settings.Global.DISPLAY_SCALING_FORCE,
                     Settings.Global.DISPLAY_SIZE_FORCED,
                     Settings.Global.DNS_RESOLVER_MAX_SAMPLES,
@@ -217,7 +220,7 @@
                     Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
                     Settings.Global.ENABLE_DISKSTATS_LOGGING,
                     Settings.Global.ENABLE_EPHEMERAL_FEATURE,
-                    Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS,
+                    Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
                     Settings.Global.ENHANCED_4G_MODE_ENABLED,
                     Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
                     Settings.Global.ERROR_LOGCAT_PREFIX,
@@ -440,7 +443,7 @@
                     Settings.Global.WIFI_WATCHDOG_ON,
                     Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON,
                     Settings.Global.WINDOW_ANIMATION_SCALE,
-                    Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
+                    Settings.Global.CHARGING_STARTED_SOUND,
                     Settings.Global.WTF_IS_FATAL,
                     Settings.Global.ZEN_MODE,
                     Settings.Global.ZEN_MODE_CONFIG_ETAG,
diff --git a/core/tests/coretests/src/android/text/OWNERS b/core/tests/coretests/src/android/text/OWNERS
index 0f85e1f..9f2182e 100644
--- a/core/tests/coretests/src/android/text/OWNERS
+++ b/core/tests/coretests/src/android/text/OWNERS
@@ -1,4 +1,3 @@
 siyamed@google.com
 nona@google.com
 clarabayarri@google.com
-toki@google.com
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
index 59d4e55..657a7fc 100644
--- a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -41,6 +41,13 @@
         testMenuPosition(getActivity().getTargetRtl());
     }
 
+    public void testContextMenuPositionRepetitive() throws InterruptedException {
+        // Regression test for b/72507876
+        testMenuPosition(getActivity().getTargetLtr());
+        testMenuPosition(getActivity().getTargetRtl());
+        testMenuPosition(getActivity().getTargetLtr());
+    }
+
     private void testMenuPosition(View target) throws InterruptedException {
         final int minScreenDimension = getMinScreenDimension();
         if (minScreenDimension < 320) {
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index cf41eb8..ada19fc 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.content.Intent;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
@@ -47,7 +48,7 @@
             colors[i] = colorValue;
         }
         final Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
-        final BitmapDrawable drawable = new BitmapDrawable(null, bitmap);
+        final BitmapDrawable drawable = new BitmapDrawable(Resources.getSystem(), bitmap);
         drawable.setTargetDensity(bitmap.getDensity());
         return drawable;
     }
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 69e5670..7f4f9f7 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -66,6 +66,7 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
 import android.test.suitebuilder.annotation.Suppress;
 import android.text.InputType;
 import android.text.Selection;
@@ -311,15 +312,69 @@
 
     @Test
     public void testToolbarAppearsAfterLinkClicked() throws Throwable {
-        runToolbarAppearsAfterLinkClickedTest(R.id.textview);
+        TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.textview);
+        int position = (textLink.getStart() + textLink.getEnd()) / 2;
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(position));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+
     }
 
     @Test
     public void testToolbarAppearsAfterLinkClickedNonselectable() throws Throwable {
-        runToolbarAppearsAfterLinkClickedTest(R.id.nonselectable_textview);
+        TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
+        int position = (textLink.getStart() + textLink.getEnd()) / 2;
+        onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
     }
 
-    private void runToolbarAppearsAfterLinkClickedTest(int id) throws Throwable {
+    @Test
+    public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable {
+        // Add a link to both selectable and nonselectable TextViews:
+        TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.textview);
+        int selectablePosition = (textLink.getStart() + textLink.getEnd()) / 2;
+        textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
+        int nonselectablePosition = (textLink.getStart() + textLink.getEnd()) / 2;
+        TextView selectableTextView = mActivity.findViewById(R.id.textview);
+        TextView nonselectableTextView = mActivity.findViewById(R.id.nonselectable_textview);
+
+        onView(withId(R.id.nonselectable_textview))
+                .perform(clickOnTextAtIndex(nonselectablePosition));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+        assertTrue(nonselectableTextView.hasSelection());
+
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(selectablePosition));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+
+        assertTrue(selectableTextView.hasSelection());
+        assertFalse(nonselectableTextView.hasSelection());
+    }
+
+    @Test
+    public void testSelectionRemovedFromNonselectableTextWhenWindowLosesFocus() throws Throwable {
+        TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
+        int nonselectablePosition = (textLink.getStart() + textLink.getEnd()) / 2;
+        TextView nonselectableTextView = mActivity.findViewById(R.id.nonselectable_textview);
+
+        onView(withId(R.id.nonselectable_textview))
+                .perform(clickOnTextAtIndex(nonselectablePosition));
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+        assertTrue(nonselectableTextView.hasSelection());
+
+        UiDevice device = UiDevice.getInstance(mInstrumentation);
+        device.openNotification();
+        Thread.sleep(2000);
+        device.pressBack();
+        Thread.sleep(2000);
+
+        assertFalse(nonselectableTextView.hasSelection());
+    }
+
+    private TextLinks.TextLink addLinkifiedTextToTextView(int id) throws Throwable {
         TextView textView = mActivity.findViewById(id);
         useSystemDefaultTextClassifier();
         TextClassificationManager textClassificationManager =
@@ -338,11 +393,7 @@
         // Wait for the UI thread to refresh
         Thread.sleep(1000);
 
-        TextLinks.TextLink textLink = links.getLinks().iterator().next();
-        int position = (textLink.getStart() + textLink.getEnd()) / 2;
-        onView(withId(id)).perform(clickOnTextAtIndex(position));
-        sleepForFloatingToolbarPopup();
-        assertFloatingToolbarIsDisplayed();
+        return links.getLinks().iterator().next();
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index ce3ffb9..d425dcc 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -59,6 +59,7 @@
 import android.util.DebugUtils;
 import android.util.Log;
 
+import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
@@ -118,6 +119,11 @@
         checkCpuTimesAvailability();
     }
 
+    @AfterClass
+    public static void tearDownOnce() throws Exception {
+        batteryReset();
+    }
+
     // Checks cpu freq times of system uid as an indication of whether /proc/uid_time_in_state
     // and /proc/uid/<uid>/time_in_state kernel nodes are available.
     private static void checkCpuTimesAvailability() throws Exception {
@@ -127,7 +133,7 @@
         final long[] totalCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID);
         sCpuFreqTimesAvailable = totalCpuTimes != null;
         final long[] fgSvcCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
-                PROCESS_STATE_FOREGROUND_SERVICE);
+                PROCESS_STATE_FOREGROUND);
         sPerProcStateTimesAvailable = fgSvcCpuTimes != null;
     }
 
@@ -868,12 +874,16 @@
 
     private static void batteryOn() throws Exception {
         executeCmd("dumpsys battery unplug");
-        assertBatteryState(false);
+        assertBatteryState(false /* pluggedIn */);
     }
 
     private static void batteryOff() throws Exception {
+        executeCmd("dumpsys battery set ac " + BatteryManager.BATTERY_PLUGGED_AC);
+        assertBatteryState(true /* pluggedIn */);
+    }
+
+    private static void batteryReset() throws Exception {
         executeCmd("dumpsys battery reset");
-        assertBatteryState(true);
     }
 
     private void screenOn() throws Exception {
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 660c744..7b239f0 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -20,6 +20,7 @@
 import android.os.Looper;
 import android.util.SparseIntArray;
 
+import com.android.internal.location.gnssmetrics.GnssMetrics;
 import java.util.ArrayList;
 import java.util.concurrent.Future;
 
@@ -40,6 +41,11 @@
         mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
         setExternalStatsSyncLocked(new DummyExternalStatsSync());
 
+        for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+            mGpsSignalQualityTimer[i] = new StopwatchTimer(clocks, null, -1000-i, null,
+                mOnBatteryTimeBase);
+        }
+
         // A no-op handler.
         mHandler = new Handler(Looper.getMainLooper()) {};
     }
diff --git a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
index 3919fdd..41082b7 100644
--- a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
@@ -127,7 +127,7 @@
         assertEquals(355, mView.getMeasuredHeight());;
     }
 
-    private class FakeImageFloatingTextView extends MessagingMessage {
+    private class FakeImageFloatingTextView extends MessagingTextMessage {
 
         public static final int LINE_HEIGHT = 50;
         private final int mNumLines;
diff --git a/core/tests/overlaytests/host/Android.mk b/core/tests/overlaytests/host/Android.mk
index d8e1fc1..b48a46b 100644
--- a/core/tests/overlaytests/host/Android.mk
+++ b/core/tests/overlaytests/host/Android.mk
@@ -24,7 +24,11 @@
     OverlayHostTests_BadSignatureOverlay \
     OverlayHostTests_PlatformSignatureStaticOverlay \
     OverlayHostTests_PlatformSignatureOverlay \
-    OverlayHostTests_PlatformSignatureOverlayV2
+    OverlayHostTests_UpdateOverlay \
+    OverlayHostTests_FrameworkOverlayV1 \
+    OverlayHostTests_FrameworkOverlayV2 \
+    OverlayHostTests_AppOverlayV1 \
+    OverlayHostTests_AppOverlayV2
 include $(BUILD_HOST_JAVA_LIBRARY)
 
 # Include to build test-apps.
diff --git a/core/tests/overlaytests/host/AndroidTest.xml b/core/tests/overlaytests/host/AndroidTest.xml
index 6884623..1f750a8 100644
--- a/core/tests/overlaytests/host/AndroidTest.xml
+++ b/core/tests/overlaytests/host/AndroidTest.xml
@@ -18,6 +18,11 @@
     <option name="test-tag" value="OverlayHostTests" />
     <option name="test-suite-tag" value="apct" />
 
+    <!-- Install the device tests that will be used to verify things on device. -->
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="OverlayHostTests_UpdateOverlay.apk" />
+    </target_preparer>
+
     <test class="com.android.tradefed.testtype.HostTest">
         <option name="class" value="com.android.server.om.hosttest.InstallOverlayTests" />
     </test>
diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
index 5093710..bf91a16 100644
--- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
+++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
@@ -23,14 +23,48 @@
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class InstallOverlayTests extends BaseHostJUnit4Test {
-
-    private static final String OVERLAY_PACKAGE_NAME =
+    private static final String SIG_OVERLAY_PACKAGE_NAME =
             "com.android.server.om.hosttest.signature_overlay";
+    private static final String APP_OVERLAY_PACKAGE_NAME =
+            "com.android.server.om.hosttest.app_overlay";
+    private static final String FRAMEWORK_OVERLAY_PACKAGE_NAME =
+            "com.android.server.om.hosttest.framework_overlay";
+    private static final String[] ALL_PACKAGES = new String[] {
+            SIG_OVERLAY_PACKAGE_NAME, APP_OVERLAY_PACKAGE_NAME, FRAMEWORK_OVERLAY_PACKAGE_NAME
+    };
+
+    private static final String DEVICE_TEST_PKG =
+            "com.android.server.om.hosttest.update_overlay_test";
+    private static final String DEVICE_TEST_CLS = DEVICE_TEST_PKG + ".UpdateOverlayTest";
+
+    @Before
+    public void ensureNoOverlays() throws Exception {
+        // Make sure we're starting with a clean slate.
+        for (String pkg : ALL_PACKAGES) {
+            assertFalse(pkg + " should not be installed", isPackageInstalled(pkg));
+            assertFalse(pkg + " should not be registered with overlay manager service",
+                    overlayManagerContainsPackage(pkg));
+        }
+    }
+
+    /*
+    For some reason, SuiteApkInstaller is *not* uninstalling overlays, even though #installPackage()
+    claims it will auto-clean.
+    TODO(b/72877546): Remove when auto-clean is fixed.
+     */
+    @After
+    public void uninstallOverlays() throws Exception {
+        for (String pkg : ALL_PACKAGES) {
+            uninstallPackage(pkg);
+        }
+    }
 
     @Test
     public void failToInstallNonPlatformSignedOverlay() throws Exception {
@@ -40,7 +74,7 @@
         } catch (Exception e) {
             // Expected.
         }
-        assertFalse(overlayManagerContainsPackage());
+        assertFalse(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME));
     }
 
     @Test
@@ -51,28 +85,64 @@
         } catch (Exception e) {
             // Expected.
         }
-        assertFalse(overlayManagerContainsPackage());
+        assertFalse(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME));
     }
 
     @Test
-    public void succeedToInstallPlatformSignedOverlay() throws Exception {
+    public void installPlatformSignedOverlay() throws Exception {
         installPackage("OverlayHostTests_PlatformSignatureOverlay.apk");
-        assertTrue(overlayManagerContainsPackage());
+        assertTrue(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME));
     }
 
     @Test
-    public void succeedToInstallPlatformSignedOverlayAndUpdate() throws Exception {
-        installPackage("OverlayHostTests_PlatformSignatureOverlay.apk");
-        assertTrue(overlayManagerContainsPackage());
-        assertEquals("v1", getDevice().getAppPackageInfo(OVERLAY_PACKAGE_NAME).getVersionName());
+    public void installPlatformSignedAppOverlayAndUpdate() throws Exception {
+        assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS, "expectAppResource"));
 
-        installPackage("OverlayHostTests_PlatformSignatureOverlayV2.apk");
-        assertTrue(overlayManagerContainsPackage());
-        assertEquals("v2", getDevice().getAppPackageInfo(OVERLAY_PACKAGE_NAME).getVersionName());
+        installPackage("OverlayHostTests_AppOverlayV1.apk");
+        setOverlayEnabled(APP_OVERLAY_PACKAGE_NAME, true);
+        assertTrue(overlayManagerContainsPackage(APP_OVERLAY_PACKAGE_NAME));
+        assertEquals("v1", getDevice()
+                .getAppPackageInfo(APP_OVERLAY_PACKAGE_NAME)
+                .getVersionName());
+        assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS,
+                "expectAppOverlayV1Resource"));
+
+        installPackage("OverlayHostTests_AppOverlayV2.apk");
+        assertTrue(overlayManagerContainsPackage(APP_OVERLAY_PACKAGE_NAME));
+        assertEquals("v2", getDevice()
+                .getAppPackageInfo(APP_OVERLAY_PACKAGE_NAME)
+                .getVersionName());
+        assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS,
+                "expectAppOverlayV2Resource"));
     }
 
-    private boolean overlayManagerContainsPackage() throws Exception {
-        return getDevice().executeShellCommand("cmd overlay list")
-                .contains(OVERLAY_PACKAGE_NAME);
+    @Test
+    public void installPlatformSignedFrameworkOverlayAndUpdate() throws Exception {
+        assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS, "expectAppResource"));
+
+        installPackage("OverlayHostTests_FrameworkOverlayV1.apk");
+        setOverlayEnabled(FRAMEWORK_OVERLAY_PACKAGE_NAME, true);
+        assertTrue(overlayManagerContainsPackage(FRAMEWORK_OVERLAY_PACKAGE_NAME));
+        assertEquals("v1", getDevice()
+                .getAppPackageInfo(FRAMEWORK_OVERLAY_PACKAGE_NAME)
+                .getVersionName());
+        assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS,
+                "expectFrameworkOverlayV1Resource"));
+
+        installPackage("OverlayHostTests_FrameworkOverlayV2.apk");
+        assertTrue(overlayManagerContainsPackage(FRAMEWORK_OVERLAY_PACKAGE_NAME));
+        assertEquals("v2", getDevice()
+                .getAppPackageInfo(FRAMEWORK_OVERLAY_PACKAGE_NAME)
+                .getVersionName());
+        assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS,
+                "expectFrameworkOverlayV2Resource"));
+    }
+
+    private void setOverlayEnabled(String pkg, boolean enabled) throws Exception {
+        getDevice().executeShellCommand("cmd overlay " + (enabled ? "enable " : "disable ") + pkg);
+    }
+
+    private boolean overlayManagerContainsPackage(String pkg) throws Exception {
+        return getDevice().executeShellCommand("cmd overlay list").contains(pkg);
     }
 }
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
index b051a82..4249549 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
@@ -40,13 +40,4 @@
 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
 include $(BUILD_PACKAGE)
 
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureOverlayV2
-LOCAL_COMPATIBILITY_SUITE := general-tests
-LOCAL_CERTIFICATE := platform
-LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
-LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
-include $(BUILD_PACKAGE)
-
 my_package_prefix :=
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
new file mode 100644
index 0000000..bd6d73d
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
@@ -0,0 +1,73 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+include $(BUILD_PACKAGE)
+
+my_package_prefix := com.android.server.om.hosttest.framework_overlay
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV1
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
+LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/framework/v1/res
+LOCAL_MANIFEST_FILE := framework/AndroidManifest.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV2
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
+LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/framework/v2/res
+LOCAL_MANIFEST_FILE := framework/AndroidManifest.xml
+include $(BUILD_PACKAGE)
+
+my_package_prefix := com.android.server.om.hosttest.app_overlay
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
+LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res
+LOCAL_MANIFEST_FILE := app/AndroidManifest.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
+LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res
+LOCAL_MANIFEST_FILE := app/AndroidManifest.xml
+include $(BUILD_PACKAGE)
+
+my_package_prefix :=
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..06077a7
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.server.om.hosttest.update_overlay_test">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.server.om.hosttest.update_overlay_test"
+        android:label="Update Overlay Test"/>
+</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/AndroidManifest.xml
new file mode 100644
index 0000000..73804eb
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.server.om.hosttest.app_overlay">
+    <overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test" />
+</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/res/values/values.xml
new file mode 100644
index 0000000..63f85c2
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="app_resource">App Resource Overlay V1</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/res/values/values.xml
new file mode 100644
index 0000000..fa4a697
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="app_resource">App Resource Overlay V2</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
new file mode 100644
index 0000000..8c8fe94
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.server.om.hosttest.framework_overlay">
+    <overlay android:targetPackage="android" />
+</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v1/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v1/res/values/values.xml
new file mode 100644
index 0000000..fedb2c6
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v1/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="ok">Framework Overlay V1</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v2/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v2/res/values/values.xml
new file mode 100644
index 0000000..8aebf483
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v2/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="ok">Framework Overlay V2</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/res/values/values.xml
new file mode 100644
index 0000000..7393166
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="app_resource">App Resource</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java b/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java
new file mode 100644
index 0000000..d46bb37
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.android.server.om.hosttest.update_overlay_test;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UpdateOverlayTest {
+    private Resources mResources;
+
+    @Before
+    public void setUp() throws Exception {
+        final Configuration defaultLocaleConfiguration = new Configuration();
+        defaultLocaleConfiguration.setLocale(Locale.US);
+        mResources = InstrumentationRegistry
+                .getInstrumentation()
+                .getContext()
+                .createConfigurationContext(defaultLocaleConfiguration)
+                .getResources();
+    }
+
+    @Test
+    public void expectAppResource() throws Exception {
+        assertEquals("App Resource", mResources.getString(R.string.app_resource));
+    }
+
+    @Test
+    public void expectAppOverlayV1Resource() throws Exception {
+        assertEquals("App Resource Overlay V1", mResources.getString(R.string.app_resource));
+    }
+
+    @Test
+    public void expectAppOverlayV2Resource() throws Exception {
+        assertEquals("App Resource Overlay V2", mResources.getString(R.string.app_resource));
+    }
+
+    @Test
+    public void expectFrameworkOverlayResource() throws Exception {
+        assertEquals("OK", mResources.getString(android.R.string.ok));
+    }
+
+    @Test
+    public void expectFrameworkOverlayV1Resource() throws Exception {
+        assertEquals("Framework Overlay V1", mResources.getString(android.R.string.ok));
+    }
+
+    @Test
+    public void expectFrameworkOverlayV2Resource() throws Exception {
+        assertEquals("Framework Overlay V2", mResources.getString(android.R.string.ok));
+    }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index bb9b89b..3495b84 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -158,7 +158,6 @@
         <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
-        <permission name="android.permission.PACKAGE_USAGE_STATS"/>
         <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
         <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index 1ef74ba..d0565ca 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -472,11 +472,15 @@
 ### Non-printing keys ###
 
 key ESCAPE {
-    base:                               fallback BACK
+    base:                               none
     alt, meta:                          fallback HOME
     ctrl:                               fallback MENU
 }
 
+key DEL {
+    ctrl+alt:                           fallback BACK
+}
+
 ### Gamepad buttons ###
 
 key BUTTON_A {
diff --git a/data/keyboards/Virtual.kcm b/data/keyboards/Virtual.kcm
index c4647e0..c763cc09 100644
--- a/data/keyboards/Virtual.kcm
+++ b/data/keyboards/Virtual.kcm
@@ -469,11 +469,15 @@
 ### Non-printing keys ###
 
 key ESCAPE {
-    base:                               fallback BACK
+    base:                               none
     alt, meta:                          fallback HOME
     ctrl:                               fallback MENU
 }
 
+key DEL {
+    ctrl+alt:                           fallback BACK
+}
+
 ### Gamepad buttons ###
 
 key BUTTON_A {
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 69a5874..eacb727 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -22,7 +22,6 @@
 import android.annotation.Size;
 import android.graphics.Canvas.VertexMode;
 import android.text.GraphicsOperations;
-import android.text.MeasuredParagraph;
 import android.text.MeasuredText;
 import android.text.SpannableString;
 import android.text.SpannedString;
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index f5bf754..7ea35e7 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -18,6 +18,8 @@
 
 import static android.graphics.BitmapFactory.Options.validate;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.os.Trace;
@@ -518,8 +520,9 @@
      *         is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
      *         function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
      */
-    public static Bitmap decodeResourceStream(Resources res, TypedValue value,
-            InputStream is, Rect pad, Options opts) {
+    @Nullable
+    public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
+            @Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
         validate(opts);
         if (opts == null) {
             opts = new Options();
@@ -707,7 +710,9 @@
      * <code>is.mark(1024)</code> would be called. As of
      * {@link android.os.Build.VERSION_CODES#KITKAT}, this is no longer the case.</p>
      */
-    public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
+    @Nullable
+    public static Bitmap decodeStream(@Nullable InputStream is, @Nullable Rect outPadding,
+            @Nullable Options opts) {
         // we don't throw in this case, thus allowing the caller to only check
         // the cache, and not force the image to be decoded.
         if (is == null) {
@@ -742,7 +747,8 @@
      * Private helper function for decoding an InputStream natively. Buffers the input enough to
      * do a rewind as needed, and supplies temporary storage if necessary. is MUST NOT be null.
      */
-    private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
+    private static Bitmap decodeStreamInternal(@NonNull InputStream is,
+            @Nullable Rect outPadding, @Nullable Options opts) {
         // ASSERT(is != null);
         byte [] tempStorage = null;
         if (opts != null) tempStorage = opts.inTempStorage;
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index f5e8633..d925441 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1219,10 +1219,14 @@
         nFreeTextLayoutCaches();
     }
 
+    /** @hide */
+    public static void setCompatibilityVersion(int apiLevel) { nSetCompatibilityVersion(apiLevel); }
+
     private static native void nFreeCaches();
     private static native void nFreeTextLayoutCaches();
     private static native long nInitRaster(Bitmap bitmap);
     private static native long nGetNativeFinalizer();
+    private static native void nSetCompatibilityVersion(int apiLevel);
 
     // ---------------- @FastNative -------------------
 
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index fe2b523..e7cfcfd 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -19,9 +19,9 @@
 import android.annotation.Nullable;
 import android.content.res.AssetManager;
 import android.graphics.fonts.FontVariationAxis;
-import android.text.FontConfig;
 import android.text.TextUtils;
 import android.util.Log;
+
 import dalvik.annotation.optimization.CriticalNative;
 
 import java.io.FileInputStream;
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 9f672e3..431d0e0 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -16,16 +16,13 @@
 
 package android.graphics;
 
-import android.text.FontConfig;
 import android.graphics.fonts.FontVariationAxis;
+import android.text.FontConfig;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.annotation.Nullable;
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 5a80ee2..ed147e9 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -19,10 +19,8 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Size;
-import android.graphics.FontListParser;
 import android.graphics.fonts.FontVariationAxis;
 import android.os.LocaleList;
-import android.text.FontConfig;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
 import android.text.SpannedString;
@@ -33,14 +31,13 @@
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
+import libcore.util.NativeAllocationRegistry;
+
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
 
-import libcore.util.NativeAllocationRegistry;
-
 /**
  * The Paint class holds the style and color information about how to draw
  * geometries, text and bitmaps.
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 04c5295..8595165 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -16,25 +16,17 @@
 
 package android.graphics;
 
-import static android.content.res.FontResourcesParser.ProviderResourceEntry;
-import static android.content.res.FontResourcesParser.FontFileResourceEntry;
-import static android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry;
 import static android.content.res.FontResourcesParser.FamilyResourceEntry;
+import static android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry;
+import static android.content.res.FontResourcesParser.FontFileResourceEntry;
+import static android.content.res.FontResourcesParser.ProviderResourceEntry;
 
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.AssetManager;
-import android.graphics.FontListParser;
 import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ParcelFileDescriptor;
-import android.os.ResultReceiver;
 import android.provider.FontRequest;
 import android.provider.FontsContract;
 import android.text.FontConfig;
@@ -49,8 +41,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
-import libcore.io.IoUtils;
-
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
@@ -58,18 +48,15 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
-import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * The Typeface class specifies the typeface and intrinsic style of a font.
@@ -394,7 +381,7 @@
          * weight and italic information, so {@link #setWeight} and {@link #setItalic} are used
          * for style matching during font selection.
          *
-         * @param results The array of {@link FontsContract.FontInfo}
+         * @param fonts The array of {@link FontsContract.FontInfo}
          * @param buffers The mapping from URI to buffers to be used during building.
          * @hide
          */
@@ -801,36 +788,18 @@
      * @return The new typeface.
      */
     public static Typeface createFromAsset(AssetManager mgr, String path) {
-        if (path == null) {
-            throw new NullPointerException();  // for backward compatibility
-        }
-        synchronized (sDynamicCacheLock) {
-            Typeface typeface = new Builder(mgr, path).build();
-            if (typeface != null) return typeface;
+        Preconditions.checkNotNull(path); // for backward compatibility
+        Preconditions.checkNotNull(mgr);
 
-            final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
-                    null /* axes */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE,
-                    DEFAULT_FAMILY);
-            typeface = sDynamicTypefaceCache.get(key);
-            if (typeface != null) return typeface;
-
-            final FontFamily fontFamily = new FontFamily();
-            if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */,
-                    0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE,
-                    null /* axes */)) {
-                if (!fontFamily.freeze()) {
-                    return Typeface.DEFAULT;
-                }
-                final FontFamily[] families = { fontFamily };
-                typeface = createFromFamiliesWithDefault(families, DEFAULT_FAMILY,
-                        RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
-                sDynamicTypefaceCache.put(key, typeface);
-                return typeface;
-            } else {
-                fontFamily.abortCreation();
-            }
+        Typeface typeface = new Builder(mgr, path).build();
+        if (typeface != null) return typeface;
+        // check if the file exists, and throw an exception for backward compatibility
+        try (InputStream inputStream = mgr.open(path)) {
+        } catch (IOException e) {
+            throw new RuntimeException("Font asset not found " + path);
         }
-        throw new RuntimeException("Font asset not found " + path);
+
+        return Typeface.DEFAULT;
     }
 
     /**
@@ -848,13 +817,22 @@
     /**
      * Create a new typeface from the specified font file.
      *
-     * @param path The path to the font data.
+     * @param file The path to the font data.
      * @return The new typeface.
      */
-    public static Typeface createFromFile(@Nullable File path) {
+    public static Typeface createFromFile(@Nullable File file) {
         // For the compatibility reasons, leaving possible NPE here.
         // See android.graphics.cts.TypefaceTest#testCreateFromFileByFileReferenceNull
-        return createFromFile(path.getAbsolutePath());
+
+        Typeface typeface = new Builder(file).build();
+        if (typeface != null) return typeface;
+
+        // check if the file exists, and throw an exception for backward compatibility
+        if (!file.exists()) {
+            throw new RuntimeException("Font asset not found " + file.getAbsolutePath());
+        }
+
+        return Typeface.DEFAULT;
     }
 
     /**
@@ -864,19 +842,8 @@
      * @return The new typeface.
      */
     public static Typeface createFromFile(@Nullable String path) {
-        final FontFamily fontFamily = new FontFamily();
-        if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */,
-                  RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) {
-            if (!fontFamily.freeze()) {
-                return Typeface.DEFAULT;
-            }
-            FontFamily[] families = { fontFamily };
-            return createFromFamiliesWithDefault(families, DEFAULT_FAMILY,
-                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
-        } else {
-            fontFamily.abortCreation();
-        }
-        throw new RuntimeException("Font not found " + path);
+        Preconditions.checkNotNull(path); // for backward compatibility
+        return createFromFile(new File(path));
     }
 
     /**
@@ -898,14 +865,12 @@
      * also the font families in the fallback list.
      * @param fallbackName the family name. If given families don't support characters, the
      *               characters will be rendered with this family.
-     * @param weight the weight for this family. {@link RESOLVE_BY_FONT_TABLE} can be used. In that
-     *               case, the table information in the first family's font is used. If the first
-     *               family has multiple fonts, the closest to the regular weight and upright font
-     *               is used.
-     * @param italic the italic information for this family. {@link RESOLVE_BY_FONT_TABLE} can be
-     *               used. In that case, the table information in the first family's font is used.
-     *               If the first family has multiple fonts, the closest to the regular weight and
-     *               upright font is used.
+     * @param weight the weight for this family. In that case, the table information in the first
+     *               family's font is used. If the first family has multiple fonts, the closest to
+     *               the regular weight and upright font is used.
+     * @param italic the italic information for this family. In that case, the table information in
+     *               the first family's font is used. If the first family has multiple fonts, the
+     *               closest to the regular weight and upright font is used.
      * @param families array of font families
      */
     private static Typeface createFromFamiliesWithDefault(FontFamily[] families,
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index 27c8fda..86e6fa8 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -81,12 +81,7 @@
 
     private State mState;
 
-    private Runnable mRunnable = new Runnable() {
-        @Override
-        public void run() {
-            invalidateSelf();
-        }
-    };
+    private Runnable mRunnable;
 
     /**
      *  Pass this to {@link #setLoopCount} to loop infinitely.
@@ -242,6 +237,9 @@
         // a value <= 0 indicates that the drawable is stopped or that renderThread
         // will manage the animation
         if (nextUpdate > 0) {
+            if (mRunnable == null) {
+                mRunnable = this::invalidateSelf;
+            }
             scheduleSelf(mRunnable, nextUpdate);
         } else if (nextUpdate == FINISHED) {
             // This means the animation was drawn in software mode and ended.
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 36a4d26..8af2fd8 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1171,9 +1171,13 @@
     /**
      * Create a drawable from an inputstream, using the given resources and
      * value to determine density information.
+     *
+     * @deprecated Prefer the version without an Options object.
      */
-    public static Drawable createFromResourceStream(Resources res, TypedValue value,
-            InputStream is, String srcName, BitmapFactory.Options opts) {
+    @Nullable
+    public static Drawable createFromResourceStream(@Nullable Resources res,
+            @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName,
+            @Nullable BitmapFactory.Options opts) {
         if (is == null) {
             return null;
         }
@@ -1197,7 +1201,6 @@
         // an application in compatibility mode, without scaling those down
         // to the compatibility density only to have them scaled back up when
         // drawn to the screen.
-        if (opts == null) opts = new BitmapFactory.Options();
         opts.inScreenDensity = Drawable.resolveDensity(res, 0);
         Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
         if (bm != null) {
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index f5a6f49..8b5114c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -825,6 +825,14 @@
         mFillPaint.setXfermode(mode);
     }
 
+    /**
+     * @param aa to draw this drawable with
+     * @hide
+     */
+    public void setAntiAlias(boolean aa) {
+        mFillPaint.setAntiAlias(aa);
+    }
+
     private void buildPathIfDirty() {
         final GradientState st = mGradientState;
         if (mPathIsDirty) {
diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java
index 4129868..a8dc34a 100644
--- a/graphics/java/android/graphics/drawable/RippleForeground.java
+++ b/graphics/java/android/graphics/drawable/RippleForeground.java
@@ -110,6 +110,7 @@
 
         // Take 60% of the maximum of the width and height, then divided half to get the radius.
         mStartRadius = Math.max(bounds.width(), bounds.height()) * 0.3f;
+        clampStartingPosition();
     }
 
     @Override
@@ -350,7 +351,7 @@
         final float cY = mBounds.exactCenterY();
         final float dX = mStartingX - cX;
         final float dY = mStartingY - cY;
-        final float r = mTargetRadius;
+        final float r = mTargetRadius - mStartRadius;
         if (dX * dX + dY * dY > r * r) {
             // Point is outside the circle, clamp to the perimeter.
             final double angle = Math.atan2(dY, dX);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index b2edd33..2b0b22d 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -187,11 +187,6 @@
 static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) {
     SkCanvas::SaveLayerFlags layerFlags = 0;
 
-    // We intentionally ignore the SaveFlags::HasAlphaLayer and
-    // SkCanvas::kIsOpaque_SaveLayerFlag flags because HWUI ignores it
-    // and our Android client may use it incorrectly.
-    // In Skia, this flag is purely for performance optimization.
-
     if (!(flags & SaveFlags::ClipToLayer)) {
         layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag;
     }
@@ -747,6 +742,12 @@
     SkPaint paintCopy(paint);
     paintCopy.setTextAlign(SkPaint::kLeft_Align);
     SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
+    // Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and
+    // older.
+    if (!mCanvasOwned && sApiLevel <= 27 && paintCopy.getStrokeWidth() <= 0
+            && paintCopy.getStyle() == SkPaint::kStroke_Style) {
+        paintCopy.setStyle(SkPaint::kFill_Style);
+    }
 
     SkRect bounds =
             SkRect::MakeLTRB(boundsLeft + x, boundsTop + y, boundsRight + x, boundsBottom + y);
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 06e2d6c..fc009d8 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -204,10 +204,6 @@
         saveFlags |= SaveFlags::ClipToLayer;
     }
 
-    if (!(layerFlags & SkCanvas::kIsOpaque_SaveLayerFlag)) {
-        saveFlags |= SaveFlags::HasAlphaLayer;
-    }
-
     return saveFlags;
 }
 
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index f118e8d..18358e2 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -518,10 +518,7 @@
             Bitmap& bitmap = getBitmapUpdateIfDirty();
             SkBitmap skiaBitmap;
             bitmap.getSkBitmap(&skiaBitmap);
-            if (!surface->getCanvas()->writePixels(skiaBitmap, dst.fLeft, dst.fTop)) {
-                ALOGD("VectorDrawable caching failed to efficiently upload");
-                surface->getCanvas()->drawBitmap(skiaBitmap, dst.fLeft, dst.fTop);
-            }
+            surface->writePixels(skiaBitmap, dst.fLeft, dst.fTop);
         }
         mCache.dirty = false;
     }
@@ -557,13 +554,12 @@
     mAtlasKey = INVALID_ATLAS_KEY;
 }
 
-void Tree::draw(SkCanvas* canvas) {
+void Tree::draw(SkCanvas* canvas, const SkRect& bounds) {
     SkRect src;
     sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
     if (vdSurface) {
         canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src,
-                              mutateProperties()->getBounds(), getPaint(),
-                              SkCanvas::kFast_SrcRectConstraint);
+                bounds, getPaint(), SkCanvas::kFast_SrcRectConstraint);
     } else {
         // Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure.
         // We render the VD into a temporary standalone buffer and mark the frame as dirty. Next
@@ -575,8 +571,7 @@
         int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
         int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
         canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight),
-                               mutateProperties()->getBounds(), getPaint(),
-                               SkCanvas::kFast_SrcRectConstraint);
+                bounds, getPaint(), SkCanvas::kFast_SrcRectConstraint);
         mCache.clear();
         markDirty();
     }
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index d9cf8ab..da52a95 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -644,7 +644,7 @@
      * Draws VD cache into a canvas. This should always be called from RT and it works with Skia
      * pipelines only.
      */
-    void draw(SkCanvas* canvas);
+    void draw(SkCanvas* canvas, const SkRect& bounds);
 
     /**
      * Draws VD into a GPU backed surface.
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index a75276f..4f06656 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -66,7 +66,7 @@
     Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
 
     int rowBytesAsPixels() const {
-        return rowBytes() >> SkColorTypeShiftPerPixel(mInfo.colorType());
+        return rowBytes() >> mInfo.shiftPerPixel();
     }
 
     void reconfigure(const SkImageInfo& info, size_t rowBytes);
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 284fd83..ad4c8be 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -225,4 +225,10 @@
     MinikinUtils::forFontRun(layout, &paintCopy, f);
 }
 
+int Canvas::sApiLevel = 1;
+
+void Canvas::setCompatibilityVersion(int apiLevel) {
+    sApiLevel = apiLevel;
+}
+
 }  // namespace android
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 3ddf1c4..fabb8d2 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -116,6 +116,14 @@
     static Canvas* create_canvas(SkCanvas* skiaCanvas);
 
     /**
+     *  Sets the target SDK version used to build the app.
+     *
+     *  @param apiLevel API level
+     *
+     */
+    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.
@@ -282,6 +290,8 @@
     virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
                                   const SkPaint& paint, const SkPath& path, size_t start,
                                   size_t end) = 0;
+    static int sApiLevel;
+
     friend class DrawTextFunctor;
     friend class DrawTextOnPathFunctor;
     friend class uirenderer::SkiaCanvasProxy;
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 091b526..dca9ef5 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -132,8 +132,8 @@
         bool italicFromFont;
 
         const minikin::FontStyle defaultStyle;
-        const minikin::MinikinFont* mf =
-                families.empty() ? nullptr : families[0]->getClosestMatch(defaultStyle).font;
+        const minikin::MinikinFont* mf = families.empty() ? nullptr
+                : families[0]->getClosestMatch(defaultStyle).font->typeface().get();
         if (mf != nullptr) {
             SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
             const SkFontStyle& style = skTypeface->fontStyle();
@@ -183,7 +183,7 @@
     std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
             std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
     std::vector<minikin::Font> fonts;
-    fonts.push_back(minikin::Font(std::move(font), minikin::FontStyle()));
+    fonts.push_back(minikin::Font::Builder(font).build());
 
     std::shared_ptr<minikin::FontCollection> collection = std::make_shared<minikin::FontCollection>(
             std::make_shared<minikin::FontFamily>(std::move(fonts)));
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index eabe2e8..25c76eb 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -124,14 +124,19 @@
 
 class VectorDrawable : public SkDrawable {
 public:
-    VectorDrawable(VectorDrawableRoot* tree) : mRoot(tree) {}
+    VectorDrawable(VectorDrawableRoot* tree)
+            : mRoot(tree)
+            , mBounds(tree->stagingProperties()->getBounds()) {}
 
 protected:
-    virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
-    virtual void onDraw(SkCanvas* canvas) override { mRoot->draw(canvas); }
+    virtual SkRect onGetBounds() override { return mBounds; }
+    virtual void onDraw(SkCanvas* canvas) override {
+        mRoot->draw(canvas, mBounds);
+    }
 
 private:
     sp<VectorDrawableRoot> mRoot;
+    SkRect mBounds;
 };
 
 void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 2953ea8..15c0ab1 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -471,6 +471,7 @@
         sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
         void onCopyOnWrite(ContentChangeMode) override {}
         int* mDrawCounter;
+        void onWritePixels(const SkPixmap&, int x, int y) {}
     };
 
     auto receiverBackground = TestUtils::createSkiaNode(
@@ -1143,4 +1144,47 @@
     RenderNodeDrawable drawable(parent.get(), &canvas, false);
     canvas.drawDrawable(&drawable);
     EXPECT_EQ(6, canvas.getIndex());
-}
\ No newline at end of file
+}
+
+// Draw a vector drawable twice but with different bounds and verify correct bounds are used.
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
+    static const int CANVAS_WIDTH = 100;
+    static const int CANVAS_HEIGHT = 200;
+    class VectorDrawableTestCanvas : public TestCanvasBase {
+    public:
+        VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
+        void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
+                const SkPaint* paint, SrcRectConstraint constraint) override {
+            const int index = mDrawCounter++;
+            switch (index) {
+                case 0:
+                    EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
+                    break;
+                case 1:
+                    EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH/2, CANVAS_HEIGHT));
+                    break;
+                default:
+                    ADD_FAILURE();
+            }
+        }
+    };
+
+    VectorDrawable::Group* group = new VectorDrawable::Group();
+    sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
+    vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH/10, CANVAS_HEIGHT/10);
+
+    auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+            [&](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+                vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH,
+                        CANVAS_HEIGHT));
+                canvas.drawVectorDrawable(vectorDrawable.get());
+                vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH/2,
+                        CANVAS_HEIGHT));
+                canvas.drawVectorDrawable(vectorDrawable.get());
+            });
+
+    VectorDrawableTestCanvas canvas;
+    RenderNodeDrawable drawable(node.get(), &canvas, true);
+    canvas.drawDrawable(&drawable);
+    EXPECT_EQ(2, canvas.mDrawCounter);
+}
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 8fdb0e3..42a92fc 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -250,6 +250,7 @@
     sk_sp<SkImage> onNewImageSnapshot() override { return nullptr; }
     T* canvas() { return static_cast<T*>(getCanvas()); }
     void onCopyOnWrite(ContentChangeMode) override {}
+    void onWritePixels(const SkPixmap&, int x, int y) override {}
 };
 }
 
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index 2232c25..e424a26 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -57,7 +57,7 @@
     std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
             std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
     std::vector<minikin::Font> fonts;
-    fonts.push_back(minikin::Font(std::move(font), minikin::FontStyle()));
+    fonts.push_back(minikin::Font::Builder(font).build());
     return std::make_shared<minikin::FontFamily>(std::move(fonts));
 }
 
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
index e568e4c..0a8a5aa 100644
--- a/libs/protoutil/include/android/util/EncodedBuffer.h
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -64,6 +64,11 @@
         size_t mOffset;
     };
 
+    /**
+     * Clears the buffer by rewinding its write pointer to avoid de/allocate buffers in heap.
+     */
+    void clear();
+
     /******************************** Write APIs ************************************************/
 
     /**
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index faea9b2..52830d3 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -123,6 +123,11 @@
     EncodedBuffer::iterator data(); // Get the reader apis of the data.
     bool flush(int fd); // Flush data directly to a file descriptor.
 
+    /**
+     * Clears the ProtoOutputStream so the buffer can be reused instead of deallocation/allocation again.
+     */
+    void clear();
+
     // Please don't use the following functions to dump protos unless you are familiar with protobuf encoding.
     void writeRawVarint(uint64_t varint);
     void writeLengthDelimitedHeader(uint32_t id, size_t size);
diff --git a/libs/protoutil/src/EncodedBuffer.cpp b/libs/protoutil/src/EncodedBuffer.cpp
index 435ae88..3a5e2e9 100644
--- a/libs/protoutil/src/EncodedBuffer.cpp
+++ b/libs/protoutil/src/EncodedBuffer.cpp
@@ -106,6 +106,13 @@
     return mBuffers[p.index()] + p.offset();
 }
 
+void
+EncodedBuffer::clear()
+{
+    mWp.rewind();
+    mEp.rewind();
+}
+
 /******************************** Write APIs ************************************************/
 size_t
 EncodedBuffer::size() const
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index f24abae..9d9ffec 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -36,6 +36,18 @@
 {
 }
 
+
+void
+ProtoOutputStream::clear()
+{
+    mBuffer.clear();
+    mCopyBegin = 0;
+    mCompact = false;
+    mDepth = 0;
+    mObjectId = 0;
+    mExpectedObjectToken = 0LL;
+}
+
 bool
 ProtoOutputStream::write(uint64_t fieldId, double val)
 {
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index c33dce1..d194796 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -236,6 +236,62 @@
      */
     public static final String GNSS_HARDWARE_MODEL_NAME_UNKNOWN = "Model Name Unknown";
 
+    /**
+     * Broadcast intent action for Settings app to inject a footer at the bottom of location
+     * settings.
+     *
+     * <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:
+     * <pre>
+     *     &lt;receiver android:name="com.example.android.footer.MyFooterInjector"&gt;
+     *         &lt;intent-filter&gt;
+     *             &lt;action android:name="com.android.settings.location.INJECT_FOOTER" /&gt;
+     *         &lt;/intent-filter&gt;
+     *         &lt;meta-data
+     *             android:name="com.android.settings.location.FOOTER_STRING"
+     *             android:resource="@string/my_injected_footer_string" /&gt;
+     *     &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.
+     *
+     * @hide
+     */
+    public static final String SETTINGS_FOOTER_DISPLAYED_ACTION =
+            "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.
+     *
+     * <p>See {@link #SETTINGS_FOOTER_DISPLAYED_ACTION} for more detail on how to use.
+     *
+     * @hide
+     */
+    public static final String METADATA_SETTINGS_FOOTER_STRING =
+            "com.android.settings.location.FOOTER_STRING";
+
     // Map from LocationListeners to their associated ListenerTransport objects
     private HashMap<LocationListener,ListenerTransport> mListeners =
         new HashMap<LocationListener,ListenerTransport>();
@@ -1215,6 +1271,9 @@
         final String allowedProviders = Settings.Secure.getStringForUser(
                 mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
                 userHandle.getIdentifier());
+        if (allowedProviders == null) {
+            return false;
+        }
         final List<String> providerList = Arrays.asList(allowedProviders.split(","));
         for(String provider : getAllProviders()) {
             if (provider.equals(PASSIVE_PROVIDER)) {
diff --git a/lowpan/java/android/net/lowpan/LowpanManager.java b/lowpan/java/android/net/lowpan/LowpanManager.java
index 2d974ee..76876ce 100644
--- a/lowpan/java/android/net/lowpan/LowpanManager.java
+++ b/lowpan/java/android/net/lowpan/LowpanManager.java
@@ -57,7 +57,7 @@
      * This design pattern allows us to skip removal of items
      * from this Map without leaking memory.
      */
-    private final Map<ILowpanInterface, WeakReference<LowpanInterface>> mBinderCache =
+    private final Map<IBinder, WeakReference<LowpanInterface>> mBinderCache =
             new WeakHashMap<>();
 
     private final ILowpanManager mService;
@@ -109,13 +109,27 @@
 
     /** @hide */
     @Nullable
+    public LowpanInterface getInterfaceNoCreate(@NonNull ILowpanInterface ifaceService) {
+        LowpanInterface iface = null;
+
+        synchronized (mBinderCache) {
+            if (mBinderCache.containsKey(ifaceService.asBinder())) {
+                iface = mBinderCache.get(ifaceService.asBinder()).get();
+            }
+        }
+
+        return iface;
+    }
+
+    /** @hide */
+    @Nullable
     public LowpanInterface getInterface(@NonNull ILowpanInterface ifaceService) {
         LowpanInterface iface = null;
 
         try {
             synchronized (mBinderCache) {
-                if (mBinderCache.containsKey(ifaceService)) {
-                    iface = mBinderCache.get(ifaceService).get();
+                if (mBinderCache.containsKey(ifaceService.asBinder())) {
+                    iface = mBinderCache.get(ifaceService.asBinder()).get();
                 }
 
                 if (iface == null) {
@@ -127,7 +141,7 @@
                         mInterfaceCache.put(iface.getName(), iface);
                     }
 
-                    mBinderCache.put(ifaceService, new WeakReference(iface));
+                    mBinderCache.put(ifaceService.asBinder(), new WeakReference(iface));
 
                     /* Make sure we remove the object from the
                      * interface cache if the associated service
@@ -260,7 +274,7 @@
                     public void onInterfaceRemoved(ILowpanInterface ifaceService) {
                         Runnable runnable =
                                 () -> {
-                                    LowpanInterface iface = getInterface(ifaceService);
+                                    LowpanInterface iface = getInterfaceNoCreate(ifaceService);
 
                                     if (iface != null) {
                                         cb.onInterfaceRemoved(iface);
diff --git a/media/java/android/media/AudioFocusInfo.java b/media/java/android/media/AudioFocusInfo.java
index 5d0c8e2..5467a69 100644
--- a/media/java/android/media/AudioFocusInfo.java
+++ b/media/java/android/media/AudioFocusInfo.java
@@ -38,6 +38,10 @@
     private int mLossReceived;
     private int mFlags;
 
+    // generation count for the validity of a request/response async exchange between
+    // external focus policy and MediaFocusControl
+    private long mGenCount = -1;
+
 
     /**
      * Class constructor
@@ -61,6 +65,16 @@
         mSdkTarget = sdk;
     }
 
+    /** @hide */
+    public void setGen(long g) {
+        mGenCount = g;
+    }
+
+    /** @hide */
+    public long getGen() {
+        return mGenCount;
+    }
+
 
     /**
      * The audio attributes for the audio focus request.
@@ -128,6 +142,7 @@
         dest.writeInt(mLossReceived);
         dest.writeInt(mFlags);
         dest.writeInt(mSdkTarget);
+        dest.writeLong(mGenCount);
     }
 
     @Override
@@ -168,6 +183,8 @@
         if (mSdkTarget != other.mSdkTarget) {
             return false;
         }
+        // mGenCount is not used to verify equality between two focus holds as multiple requests
+        // (hence of different generations) could correspond to the same hold
         return true;
     }
 
@@ -175,7 +192,7 @@
             = new Parcelable.Creator<AudioFocusInfo>() {
 
         public AudioFocusInfo createFromParcel(Parcel in) {
-            return new AudioFocusInfo(
+            final AudioFocusInfo afi = new AudioFocusInfo(
                     AudioAttributes.CREATOR.createFromParcel(in), //AudioAttributes aa
                     in.readInt(), // int clientUid
                     in.readString(), //String clientId
@@ -185,6 +202,8 @@
                     in.readInt(), //int flags
                     in.readInt()  //int sdkTarget
                     );
+            afi.setGen(in.readLong());
+            return afi;
         }
 
         public AudioFocusInfo[] newArray(int size) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index bf51d97..0be54ec 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.audiopolicy.AudioPolicy;
+import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionLegacyHelper;
@@ -54,10 +55,13 @@
 import android.util.Slog;
 import android.view.KeyEvent;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
@@ -2338,6 +2342,20 @@
                 }
             }
         }
+
+        @Override
+        public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
+            synchronized (mFocusRequestsLock) {
+                // TODO use generation counter as the key instead
+                final BlockingFocusResultReceiver focusReceiver =
+                        mFocusRequestsAwaitingResult.remove(clientId);
+                if (focusReceiver != null) {
+                    focusReceiver.notifyResult(requestResult);
+                } else {
+                    Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
+                }
+            }
+        }
     };
 
     private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
@@ -2390,6 +2408,40 @@
       */
     public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
 
+    /** @hide */
+    @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
+            AUDIOFOCUS_REQUEST_FAILED,
+            AUDIOFOCUS_REQUEST_GRANTED,
+            AUDIOFOCUS_REQUEST_DELAYED }
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FocusRequestResult {}
+
+    /**
+     * @hide
+     * code returned when a synchronous focus request on the client-side is to be blocked
+     * until the external audio focus policy decides on the response for the client
+     */
+    public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
+
+    /**
+     * Timeout duration in ms when waiting on an external focus policy for the result for a
+     * focus request
+     */
+    private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200;
+
+    private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
+
+    private final Object mFocusRequestsLock = new Object();
+    /**
+     * Map of all receivers of focus request results, one per unresolved focus request.
+     * Receivers are added before sending the request to the external focus policy,
+     * and are removed either after receiving the result, or after the timeout.
+     * This variable is lazily initialized.
+     */
+    @GuardedBy("mFocusRequestsLock")
+    private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
+
 
     /**
      *  Request audio focus.
@@ -2656,18 +2708,100 @@
             // some tests don't have a Context
             sdk = Build.VERSION.SDK_INT;
         }
-        try {
-            status = service.requestAudioFocus(afr.getAudioAttributes(),
-                    afr.getFocusGain(), mICallBack,
-                    mAudioFocusDispatcher,
-                    getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()),
-                    getContext().getOpPackageName() /* package name */, afr.getFlags(),
-                    ap != null ? ap.cb() : null,
-                    sdk);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+
+        final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
+        final BlockingFocusResultReceiver focusReceiver;
+        synchronized (mFocusRequestsLock) {
+            try {
+                // TODO status contains result and generation counter for ext policy
+                status = service.requestAudioFocus(afr.getAudioAttributes(),
+                        afr.getFocusGain(), mICallBack,
+                        mAudioFocusDispatcher,
+                        clientId,
+                        getContext().getOpPackageName() /* package name */, afr.getFlags(),
+                        ap != null ? ap.cb() : null,
+                        sdk);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
+                // default path with no external focus policy
+                return status;
+            }
+            if (mFocusRequestsAwaitingResult == null) {
+                mFocusRequestsAwaitingResult =
+                        new HashMap<String, BlockingFocusResultReceiver>(1);
+            }
+            focusReceiver = new BlockingFocusResultReceiver(clientId);
+            mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
         }
-        return status;
+        focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
+        if (DEBUG && !focusReceiver.receivedResult()) {
+            Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
+        }
+        synchronized (mFocusRequestsLock) {
+            mFocusRequestsAwaitingResult.remove(clientId);
+        }
+        return focusReceiver.requestResult();
+    }
+
+    // helper class that abstracts out the handling of spurious wakeups in Object.wait()
+    private static final class SafeWaitObject {
+        private boolean mQuit = false;
+
+        public void safeNotify() {
+            synchronized (this) {
+                mQuit = true;
+                this.notify();
+            }
+        }
+
+        public void safeWait(long millis) throws InterruptedException {
+            final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
+            synchronized (this) {
+                while (!mQuit) {
+                    final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
+                    if (timeToWait < 0) { break; }
+                    this.wait(timeToWait);
+                }
+            }
+        }
+    }
+
+    private static final class BlockingFocusResultReceiver {
+        private final SafeWaitObject mLock = new SafeWaitObject();
+        @GuardedBy("mLock")
+        private boolean mResultReceived = false;
+        // request denied by default (e.g. timeout)
+        private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+        private final String mFocusClientId;
+
+        BlockingFocusResultReceiver(String clientId) {
+            mFocusClientId = clientId;
+        }
+
+        boolean receivedResult() { return mResultReceived; }
+        int requestResult() { return mFocusRequestResult; }
+
+        void notifyResult(int requestResult) {
+            synchronized (mLock) {
+                mResultReceived = true;
+                mFocusRequestResult = requestResult;
+                mLock.safeNotify();
+            }
+        }
+
+        public void waitForResult(long timeOutMs) {
+            synchronized (mLock) {
+                if (mResultReceived) {
+                    // the result was received before waiting
+                    return;
+                }
+                try {
+                    mLock.safeWait(timeOutMs);
+                } catch (InterruptedException e) { }
+            }
+        }
     }
 
     /**
@@ -2714,6 +2848,32 @@
 
     /**
      * @hide
+     * Set the result to the audio focus request received through
+     * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
+     * @param afi the information about the focus requester
+     * @param requestResult the result to the focus request to be passed to the requester
+     * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
+            @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
+        if (afi == null) {
+            throw new IllegalArgumentException("Illegal null AudioFocusInfo");
+        }
+        if (ap == null) {
+            throw new IllegalArgumentException("Illegal null AudioPolicy");
+        }
+        final IAudioService service = getService();
+        try {
+            service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
      * Notifies an application with a focus listener of gain or loss of audio focus.
      * This method can only be used by owners of an {@link AudioPolicy} configured with
      * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index d0963cb..3847530 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -1416,6 +1416,7 @@
     /*
      * Call BEFORE adding a routing callback handler.
      */
+    @GuardedBy("mRoutingChangeListeners")
     private void testEnableNativeRoutingCallbacksLocked() {
         if (mRoutingChangeListeners.size() == 0) {
             native_enableDeviceCallback();
@@ -1425,6 +1426,7 @@
     /*
      * Call AFTER removing a routing callback handler.
      */
+    @GuardedBy("mRoutingChangeListeners")
     private void testDisableNativeRoutingCallbacksLocked() {
         if (mRoutingChangeListeners.size() == 0) {
             native_disableDeviceCallback();
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 8e822a5..2d5fad5 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -2821,6 +2821,7 @@
     /*
      * Call BEFORE adding a routing callback handler.
      */
+    @GuardedBy("mRoutingChangeListeners")
     private void testEnableNativeRoutingCallbacksLocked() {
         if (mRoutingChangeListeners.size() == 0) {
             native_enableDeviceCallback();
@@ -2830,6 +2831,7 @@
     /*
      * Call AFTER removing a routing callback handler.
      */
+    @GuardedBy("mRoutingChangeListeners")
     private void testDisableNativeRoutingCallbacksLocked() {
         if (mRoutingChangeListeners.size() == 0) {
             native_disableDeviceCallback();
diff --git a/media/java/android/media/IAudioFocusDispatcher.aidl b/media/java/android/media/IAudioFocusDispatcher.aidl
index 09575f7..3b33c5b 100644
--- a/media/java/android/media/IAudioFocusDispatcher.aidl
+++ b/media/java/android/media/IAudioFocusDispatcher.aidl
@@ -25,4 +25,6 @@
 
     void dispatchAudioFocusChange(int focusChange, String clientId);
 
+    void dispatchFocusResultFromExtPolicy(int requestResult, String clientId);
+
 }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 88d0a60..4c37014 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -16,9 +16,7 @@
 
 package android.media;
 
-import android.app.PendingIntent;
 import android.bluetooth.BluetoothDevice;
-import android.content.ComponentName;
 import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
 import android.media.AudioPlaybackConfiguration;
@@ -31,25 +29,33 @@
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.PlayerBase;
-import android.media.Rating;
 import android.media.VolumePolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.audiopolicy.IAudioPolicyCallback;
-import android.net.Uri;
-import android.view.KeyEvent;
 
 /**
  * {@hide}
  */
 interface IAudioService {
+    // C++ and Java methods below.
 
-    // WARNING: When methods are inserted or deleted, the transaction IDs in
+    // WARNING: When methods are inserted or deleted in this section, the transaction IDs in
     // frameworks/native/include/audiomanager/IAudioManager.h must be updated to match the order
     // in this file.
     //
     // When a method's argument list is changed, BpAudioManager's corresponding serialization code
     // (if any) in frameworks/native/services/audiomanager/IAudioManager.cpp must be updated.
 
+    int trackPlayer(in PlayerBase.PlayerIdCard pic);
+
+    oneway void playerAttributes(in int piid, in AudioAttributes attr);
+
+    oneway void playerEvent(in int piid, in int event);
+
+    oneway void releasePlayer(in int piid);
+
+    // Java-only methods below.
+
     oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
             String callingPackage, String caller);
 
@@ -187,14 +193,6 @@
 
     List<AudioPlaybackConfiguration> getActivePlaybackConfigurations();
 
-    int trackPlayer(in PlayerBase.PlayerIdCard pic);
-
-    oneway void playerAttributes(in int piid, in AudioAttributes attr);
-
-    oneway void playerEvent(in int piid, in int event);
-
-    oneway void releasePlayer(in int piid);
-
     void disableRingtoneSync(in int userId);
 
     int getFocusRampTimeMs(in int focusGain, in AudioAttributes attr);
@@ -207,5 +205,9 @@
     int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
             int state, int profile, boolean suppressNoisyIntent);
 
-    // WARNING: read warning at top of file, it is recommended to add new methods at the end
+    oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
+            in IAudioPolicyCallback pcb);
+
+    // WARNING: read warning at top of file, new methods that need to be used by native
+    // code via IAudioManager.h need to be added to the top section.
 }
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index e9ffe60..bd6c7e6 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -30,7 +30,7 @@
 import android.media.session.MediaSessionManager;
 import android.media.update.ApiLoader;
 import android.media.update.MediaController2Provider;
-import android.media.update.PlaybackInfoProvider;
+import android.media.update.MediaController2Provider.PlaybackInfoProvider;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ResultReceiver;
diff --git a/media/java/android/media/MediaDataSource.java b/media/java/android/media/MediaDataSource.java
index 948da0b..4ba2120 100644
--- a/media/java/android/media/MediaDataSource.java
+++ b/media/java/android/media/MediaDataSource.java
@@ -34,8 +34,8 @@
     /**
      * Called to request data from the given position.
      *
-     * Implementations should should write up to {@code size} bytes into
-     * {@code buffer}, and return the number of bytes written.
+     * Implementations should fill {@code buffer} with up to {@code size}
+     * bytes of data, and return the number of valid bytes in the buffer.
      *
      * Return {@code 0} if size is zero (thus no bytes are read).
      *
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 90fcaab..279e05f 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -634,8 +634,39 @@
      * @throws ResourceBusyException if required resources are in use
      */
     @NonNull
-    public native byte[] openSession() throws NotProvisionedException,
-            ResourceBusyException;
+    public byte[] openSession() throws NotProvisionedException,
+            ResourceBusyException {
+        return openSession(getMaxSecurityLevel());
+    }
+
+    /**
+     * Open a new session at a requested security level. The security level
+     * represents the robustness of the device's DRM implementation. By default,
+     * sessions are opened at the native security level of the device.
+     * Overriding the security level is necessary when the decrypted frames need
+     * to be manipulated, such as for image compositing. The security level
+     * parameter must be lower than the native level. Reducing the security
+     * level will typically limit the content to lower resolutions, as
+     * determined by the license policy. If the requested level is not
+     * supported, the next lower supported security level will be set. The level
+     * can be queried using {@link #getSecurityLevel}. A session
+     * ID is returned.
+     *
+     * @param level the new security level, one of
+     * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE},
+     * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or
+     * {@link #HW_SECURE_ALL}.
+     *
+     * @throws NotProvisionedException if provisioning is needed
+     * @throws ResourceBusyException if required resources are in use
+     * @throws IllegalArgumentException if the requested security level is
+     * higher than the native level or lower than the lowest supported level or
+     * if the device does not support specifying the security level when opening
+     * a session
+     */
+    @NonNull
+    public native byte[] openSession(@SecurityLevel int level) throws
+            NotProvisionedException, ResourceBusyException;
 
     /**
      * Close a session on the MediaDrm object that was previously opened
@@ -1109,7 +1140,7 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SECURITY_LEVEL_UNKNOWN, SW_SECURE_CRYPTO, SW_SECURE_DECODE,
-                        HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL})
+            HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL})
     public @interface SecurityLevel {}
 
     /**
@@ -1119,39 +1150,55 @@
     public static final int SECURITY_LEVEL_UNKNOWN = 0;
 
     /**
-     *  Software-based whitebox crypto
+     * DRM key management uses software-based whitebox crypto.
      */
     public static final int SW_SECURE_CRYPTO = 1;
 
     /**
-     * Software-based whitebox crypto and an obfuscated decoder
+     * DRM key management and decoding use software-based whitebox crypto.
      */
-     public static final int SW_SECURE_DECODE = 2;
+    public static final int SW_SECURE_DECODE = 2;
 
     /**
-     * DRM key management and crypto operations are performed within a
-     * hardware backed trusted execution environment
+     * DRM key management and crypto operations are performed within a hardware
+     * backed trusted execution environment.
      */
     public static final int HW_SECURE_CRYPTO = 3;
 
     /**
-     * DRM key management, crypto operations and decoding of content
-     * are performed within a hardware backed trusted execution environment
+     * DRM key management, crypto operations and decoding of content are
+     * performed within a hardware backed trusted execution environment.
      */
-     public static final int HW_SECURE_DECODE = 4;
+    public static final int HW_SECURE_DECODE = 4;
 
     /**
      * DRM key management, crypto operations, decoding of content and all
-     * handling of the media (compressed and uncompressed) is handled within
-     * a hardware backed trusted execution environment.
+     * handling of the media (compressed and uncompressed) is handled within a
+     * hardware backed trusted execution environment.
      */
     public static final int HW_SECURE_ALL = 5;
 
     /**
-     * Return the current security level of a session. A session
-     * has an initial security level determined by the robustness of
-     * the DRM system's implementation on the device. The security
-     * level may be adjusted using {@link #setSecurityLevel}.
+     * The maximum security level supported by the device. This is the default
+     * security level when a session is opened.
+     * @hide
+     */
+    public static final int SECURITY_LEVEL_MAX = 6;
+
+    /**
+     * The maximum security level supported by the device. This is the default
+     * security level when a session is opened.
+     */
+    @SecurityLevel
+    public static final int getMaxSecurityLevel() {
+        return SECURITY_LEVEL_MAX;
+    }
+
+    /**
+     * Return the current security level of a session. A session has an initial
+     * security level determined by the robustness of the DRM system's
+     * implementation on the device. The security level may be changed at the
+     * time a session is opened using {@link #openSession}.
      * @param sessionId the session to query.
      * <p>
      * @return one of {@link #SECURITY_LEVEL_UNKNOWN},
@@ -1163,21 +1210,6 @@
     public native int getSecurityLevel(@NonNull byte[] sessionId);
 
     /**
-     * Set the security level of a session. This can be useful if specific
-     * attributes of a lower security level are needed by an application,
-     * such as image manipulation or compositing. Reducing the security
-     * level will typically limit decryption to lower content resolutions,
-     * depending on the license policy.
-     * @param sessionId the session to set the security level on.
-     * @param level the new security level, one of
-     * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE},
-     * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or
-     * {@link #HW_SECURE_ALL}.
-     */
-    public native void setSecurityLevel(@NonNull byte[] sessionId,
-            @SecurityLevel int level);
-
-    /**
      * String property name: identifies the maker of the DRM plugin
      */
     public static final String PROPERTY_VENDOR = "vendor";
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 1bc3dfa..fe5e822 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1484,6 +1484,7 @@
     /*
      * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
      */
+    @GuardedBy("mRoutingChangeListeners")
     private void enableNativeRoutingCallbacksLocked(boolean enabled) {
         if (mRoutingChangeListeners.size() == 0) {
             native_enableDeviceCallback(enabled);
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index e3d5ac0..49bbc2b 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -1212,6 +1212,7 @@
         } else if (scheme != null) {
             // handle non-file sources
             nativeSetDataSource(
+                srcId,
                 Media2HTTPService.createHTTPService(path, cookies),
                 path,
                 keys,
@@ -1231,7 +1232,7 @@
     }
 
     private native void nativeSetDataSource(
-        Media2HTTPService httpService, String path, String[] keys, String[] values)
+        long srcId, Media2HTTPService httpService, String path, String[] keys, String[] values)
         throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
 
     /**
@@ -1245,10 +1246,10 @@
      */
     private void setDataSourcePriv(long srcId, FileDescriptor fd, long offset, long length)
             throws IOException {
-        _setDataSource(fd, offset, length);
+        _setDataSource(srcId, fd, offset, length);
     }
 
-    private native void _setDataSource(FileDescriptor fd, long offset, long length)
+    private native void _setDataSource(long srcId, FileDescriptor fd, long offset, long length)
             throws IOException;
 
     /**
@@ -1256,10 +1257,10 @@
      * @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
      */
     private void setDataSourcePriv(long srcId, Media2DataSource dataSource) {
-        _setDataSource(dataSource);
+        _setDataSource(srcId, dataSource);
     }
 
-    private native void _setDataSource(Media2DataSource dataSource);
+    private native void _setDataSource(long srcId, Media2DataSource dataSource);
 
     /**
      * Prepares the player for playback, synchronously.
@@ -1417,6 +1418,7 @@
     /*
      * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
      */
+    @GuardedBy("mRoutingChangeListeners")
     private void enableNativeRoutingCallbacksLocked(boolean enabled) {
         if (mRoutingChangeListeners.size() == 0) {
             native_enableDeviceCallback(enabled);
@@ -3072,6 +3074,10 @@
 
         @Override
         public void handleMessage(Message msg) {
+            handleMessage(msg, 0);
+        }
+
+        public void handleMessage(Message msg, long srcId) {
             if (mMediaPlayer.mNativeContext == 0) {
                 Log.w(TAG, "mediaplayer2 went away with unhandled events");
                 return;
@@ -3094,7 +3100,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, MEDIA_INFO_PREPARED, 0));
+                                mMediaPlayer, srcId, MEDIA_INFO_PREPARED, 0));
                     }
                 }
                 return;
@@ -3132,7 +3138,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
+                                mMediaPlayer, srcId, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
                     }
                 }
                 stayAwake(false);
@@ -3162,7 +3168,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onBufferingUpdate(
-                                mMediaPlayer, 0, percent));
+                                mMediaPlayer, srcId, percent));
                     }
                 }
                 return;
@@ -3171,7 +3177,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, MEDIA_INFO_COMPLETE_CALL_SEEK, 0));
+                                mMediaPlayer, srcId, MEDIA_INFO_COMPLETE_CALL_SEEK, 0));
                     }
                 }
                 // fall through
@@ -3191,7 +3197,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onVideoSizeChanged(
-                                mMediaPlayer, 0, width, height));
+                                mMediaPlayer, srcId, width, height));
                     }
                 }
                 return;
@@ -3201,9 +3207,9 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onError(
-                                mMediaPlayer, 0, what, extra));
+                                mMediaPlayer, srcId, what, extra));
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
+                                mMediaPlayer, srcId, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
                     }
                 }
                 stayAwake(false);
@@ -3246,7 +3252,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, what, extra));
+                                mMediaPlayer, srcId, what, extra));
                     }
                 }
                 // No real default action so far.
@@ -3271,7 +3277,7 @@
 
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, 0, text));
+                        cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, srcId, text));
                     }
                 }
                 return;
@@ -3302,7 +3308,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onTimedMetaDataAvailable(
-                                mMediaPlayer, 0, data));
+                                mMediaPlayer, srcId, data));
                     }
                 }
                 return;
@@ -3334,7 +3340,7 @@
      * code is safe from the object disappearing from underneath it.  (This is
      * the cookie passed to native_setup().)
      */
-    private static void postEventFromNative(Object mediaplayer2_ref,
+    private static void postEventFromNative(Object mediaplayer2_ref, long srcId,
                                             int what, int arg1, int arg2, Object obj)
     {
         final MediaPlayer2Impl mp = (MediaPlayer2Impl)((WeakReference)mediaplayer2_ref).get();
@@ -3387,7 +3393,13 @@
 
         if (mp.mEventHandler != null) {
             Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
-            mp.mEventHandler.sendMessage(m);
+
+            mp.mEventHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mp.mEventHandler.handleMessage(m, srcId);
+                }
+            });
         }
     }
 
@@ -4489,7 +4501,7 @@
         // no need for log(N) search performance
         private MediaTimeProvider.OnMediaTimeListener mListeners[];
         private long mTimes[];
-        private Handler mEventHandler;
+        private EventHandler mEventHandler;
         private boolean mRefresh = false;
         private boolean mPausing = false;
         private boolean mSeeking = false;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 62240ce..823410f 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -1353,6 +1353,7 @@
     /*
      * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
      */
+    @GuardedBy("mRoutingChangeListeners")
     private void enableNativeRoutingCallbacksLocked(boolean enabled) {
         if (mRoutingChangeListeners.size() == 0) {
             native_enableDeviceCallback(enabled);
diff --git a/media/java/android/media/VolumePolicy.java b/media/java/android/media/VolumePolicy.java
index bbcce82..bd6667f 100644
--- a/media/java/android/media/VolumePolicy.java
+++ b/media/java/android/media/VolumePolicy.java
@@ -23,7 +23,7 @@
 
 /** @hide */
 public final class VolumePolicy implements Parcelable {
-    public static final VolumePolicy DEFAULT = new VolumePolicy(false, false, true, 400);
+    public static final VolumePolicy DEFAULT = new VolumePolicy(false, false, false, 400);
 
     /**
      * Accessibility volume policy where the STREAM_MUSIC volume (i.e. media volume) affects
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 4de731a..2190635 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -463,9 +463,9 @@
          * Only ever called if the {@link AudioPolicy} was built with
          * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to {@code true}.
          * @param afi information about the focus request and the requester
-         * @param requestResult the result that was returned synchronously by the framework to the
-         *     application, {@link #AUDIOFOCUS_REQUEST_FAILED},or
-         *     {@link #AUDIOFOCUS_REQUEST_DELAYED}.
+         * @param requestResult deprecated after the addition of
+         *     {@link AudioManager#setFocusRequestResult(AudioFocusInfo, int, AudioPolicy)}
+         *     in Android P, always equal to {@link #AUDIOFOCUS_REQUEST_GRANTED}.
          */
         public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {}
         /**
@@ -534,7 +534,7 @@
             sendMsg(MSG_FOCUS_REQUEST, afi, requestResult);
             if (DEBUG) {
                 Log.v(TAG, "notifyAudioFocusRequest: pack=" + afi.getPackageName() + " client="
-                        + afi.getClientId() + "reqRes=" + requestResult);
+                        + afi.getClientId() + " gen=" + afi.getGen());
             }
         }
 
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index 71bc64a..c492d307 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.app.PendingIntent;
+import android.media.AudioAttributes;
 import android.media.MediaController2.PlaybackInfo;
 import android.media.MediaItem2;
 import android.media.MediaSession2.Command;
@@ -65,4 +66,12 @@
     PlaylistParams getPlaylistParams_impl();
     void setPlaylistParams_impl(PlaylistParams params);
     PlaybackState2 getPlaybackState_impl();
+
+    interface PlaybackInfoProvider {
+        int getPlaybackType_impl();
+        AudioAttributes getAudioAttributes_impl();
+        int getControlType_impl();
+        int getMaxVolume_impl();
+        int getCurrentVolume_impl();
+    }
 }
diff --git a/media/java/android/media/update/PlaybackInfoProvider.java b/media/java/android/media/update/PlaybackInfoProvider.java
deleted file mode 100644
index 36eb58a..0000000
--- a/media/java/android/media/update/PlaybackInfoProvider.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.update;
-
-import android.media.AudioAttributes;
-
-/**
- * @hide
- */
-// TODO(jaewan): @SystemApi
-public interface PlaybackInfoProvider {
-    int getPlaybackType_impl();
-    AudioAttributes getAudioAttributes_impl();
-    int getControlType_impl();
-    int getMaxVolume_impl();
-    int getCurrentVolume_impl();
-}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 7e5f581..fe2f64f 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -127,11 +127,11 @@
         "liblzma",
         "libmedia",
         "libmedia_helper",
-        "libmedia_player2",
         "libmedia_player2_util",
         "libmediadrm",
         "libmediaextractor",
         "libmediametrics",
+        "libmediaplayer2",
         "libmediautils",
         "libnativehelper",
         "libnetd_client",
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 4f06caa..d7f51d4 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -145,6 +145,7 @@
 
 struct SecurityLevels {
     jint kSecurityLevelUnknown;
+    jint kSecurityLevelMax;
     jint kSecurityLevelSwSecureCrypto;
     jint kSecurityLevelSwSecureDecode;
     jint kSecurityLevelHwSecureCrypto;
@@ -683,6 +684,10 @@
     GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_ALL", "I");
     gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
 
+    jmethodID getMaxSecurityLevel;
+    GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
+    gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
+
     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
     GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
     GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
@@ -813,7 +818,7 @@
 }
 
 static jbyteArray android_media_MediaDrm_openSession(
-    JNIEnv *env, jobject thiz) {
+        JNIEnv *env, jobject thiz, jint jlevel) {
     sp<IDrm> drm = GetDrm(env, thiz);
 
     if (drm == NULL) {
@@ -823,7 +828,26 @@
     }
 
     Vector<uint8_t> sessionId;
-    status_t err = drm->openSession(sessionId);
+    DrmPlugin::SecurityLevel level;
+
+    if (jlevel == gSecurityLevels.kSecurityLevelMax) {
+        level = DrmPlugin::kSecurityLevelMax;
+    }  else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
+        level = DrmPlugin::kSecurityLevelSwSecureCrypto;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
+        level = DrmPlugin::kSecurityLevelSwSecureDecode;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
+        level = DrmPlugin::kSecurityLevelHwSecureCrypto;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
+        level = DrmPlugin::kSecurityLevelHwSecureDecode;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
+        level = DrmPlugin::kSecurityLevelHwSecureAll;
+    } else {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
+        return NULL;
+    }
+
+    status_t err = drm->openSession(level, sessionId);
 
     if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
         return NULL;
@@ -1345,40 +1369,6 @@
 }
 
 
-static void android_media_MediaDrm_setSecurityLevel(JNIEnv *env,
-        jobject thiz, jbyteArray jsessionId, jint jlevel) {
-    sp<IDrm> drm = GetDrm(env, thiz);
-
-    if (!CheckSession(env, drm, jsessionId)) {
-        return;
-    }
-
-    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
-    DrmPlugin::SecurityLevel level;
-
-    if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
-        level = DrmPlugin::kSecurityLevelSwSecureCrypto;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
-        level = DrmPlugin::kSecurityLevelSwSecureDecode;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
-        level = DrmPlugin::kSecurityLevelHwSecureCrypto;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
-        level = DrmPlugin::kSecurityLevelHwSecureDecode;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
-        level = DrmPlugin::kSecurityLevelHwSecureAll;
-    } else {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
-        return;
-    }
-
-    status_t err = drm->setSecurityLevel(sessionId, level);
-
-    if (throwExceptionAsNecessary(env, err, "Failed to set security level")) {
-        return;
-    }
-}
-
-
 static jstring android_media_MediaDrm_getPropertyString(
     JNIEnv *env, jobject thiz, jstring jname) {
     sp<IDrm> drm = GetDrm(env, thiz);
@@ -1724,7 +1714,7 @@
     { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
       (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
 
-    { "openSession", "()[B",
+    { "openSession", "(I)[B",
       (void *)android_media_MediaDrm_openSession },
 
     { "closeSession", "([B)V",
@@ -1785,9 +1775,6 @@
     { "getSecurityLevel", "([B)I",
       (void *)android_media_MediaDrm_getSecurityLevel },
 
-    { "setSecurityLevel", "([BI)V",
-      (void *)android_media_MediaDrm_setSecurityLevel },
-
     { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
       (void *)android_media_MediaDrm_getPropertyString },
 
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 27eaed0..e73b2f8 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -21,15 +21,14 @@
 
 #include <sys/stat.h>
 
-#include <media/mediaplayer2.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/DataSourceDesc.h>
 #include <media/MediaHTTPService.h>
-#include <media/MediaPlayer2Interface.h>
 #include <media/MediaAnalyticsItem.h>
 #include <media/NdkWrapper.h>
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/foundation/ByteUtils.h>  // for FOURCC definition
+#include <mediaplayer2/mediaplayer2.h>
 #include <stdio.h>
 #include <assert.h>
 #include <limits.h>
@@ -155,7 +154,8 @@
 public:
     JNIMediaPlayer2Listener(JNIEnv* env, jobject thiz, jobject weak_thiz);
     ~JNIMediaPlayer2Listener();
-    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
+                        const Parcel *obj = NULL) override;
 private:
     JNIMediaPlayer2Listener();
     jclass      mClass;     // Reference to MediaPlayer2 class
@@ -188,7 +188,7 @@
     env->DeleteGlobalRef(mClass);
 }
 
-void JNIMediaPlayer2Listener::notify(int msg, int ext1, int ext2, const Parcel *obj)
+void JNIMediaPlayer2Listener::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     if (obj && obj->dataSize() > 0) {
@@ -197,12 +197,12 @@
             Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
             nativeParcel->setData(obj->data(), obj->dataSize());
             env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
-                    msg, ext1, ext2, jParcel);
+                    srcId, msg, ext1, ext2, jParcel);
             env->DeleteLocalRef(jParcel);
         }
     } else {
         env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
-                msg, ext1, ext2, NULL);
+                srcId, msg, ext1, ext2, NULL);
     }
     if (env->ExceptionCheck()) {
         ALOGW("An exception occurred while notifying an event.");
@@ -244,7 +244,11 @@
     if (exception == NULL) {  // Don't throw exception. Instead, send an event.
         if (opStatus != (status_t) OK) {
             sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-            if (mp != 0) mp->notify(MEDIA2_ERROR, opStatus, 0);
+            if (mp != 0) {
+                int64_t srcId = 0;
+                mp->getSrcId(&srcId);
+                mp->notify(srcId, MEDIA2_ERROR, opStatus, 0);
+            }
         }
     } else {  // Throw exception!
         if ( opStatus == (status_t) INVALID_OPERATION ) {
@@ -269,7 +273,7 @@
 
 static void
 android_media_MediaPlayer2_setDataSourceAndHeaders(
-        JNIEnv *env, jobject thiz, jobject httpServiceObj, jstring path,
+        JNIEnv *env, jobject thiz, jlong srcId, jobject httpServiceObj, jstring path,
         jobjectArray keys, jobjectArray values) {
 
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
@@ -287,7 +291,7 @@
     if (tmp == NULL) {  // Out of memory
         return;
     }
-    ALOGV("setDataSourceAndHeaders: path %s", tmp);
+    ALOGV("setDataSourceAndHeaders: path %s, srcId %lld", tmp, (long long)srcId);
 
     if (strncmp(tmp, "content://", 10) == 0) {
         ALOGE("setDataSourceAndHeaders: content scheme is not supported in native code");
@@ -297,6 +301,7 @@
     }
 
     sp<DataSourceDesc> dsd = new DataSourceDesc();
+    dsd->mId = srcId;
     dsd->mType = DataSourceDesc::TYPE_URL;
     dsd->mUrl = tmp;
 
@@ -322,7 +327,7 @@
 
 static void
 android_media_MediaPlayer2_setDataSourceFD(
-    JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
+    JNIEnv *env, jobject thiz, jlong srcId, jobject fileDescriptor, jlong offset, jlong length)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
@@ -335,8 +340,8 @@
         return;
     }
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    ALOGV("setDataSourceFD: fd=%d (%s), offset=%lld, length=%lld",
-          fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
+    ALOGV("setDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
+          (long long)srcId, fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
 
     struct stat sb;
     int ret = fstat(fd, &sb);
@@ -364,6 +369,7 @@
     }
 
     sp<DataSourceDesc> dsd = new DataSourceDesc();
+    dsd->mId = srcId;
     dsd->mType = DataSourceDesc::TYPE_FD;
     dsd->mFD = fd;
     dsd->mFDOffset = offset;
@@ -374,7 +380,7 @@
 
 static void
 android_media_MediaPlayer2_setDataSourceCallback(
-    JNIEnv *env, jobject thiz, jobject dataSource)
+    JNIEnv *env, jobject thiz, jlong srcId, jobject dataSource)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
@@ -388,6 +394,7 @@
     }
     sp<DataSource> callbackDataSource = new JMedia2DataSource(env, dataSource);
     sp<DataSourceDesc> dsd = new DataSourceDesc();
+    dsd->mId = srcId;
     dsd->mType = DataSourceDesc::TYPE_CALLBACK;
     dsd->mCallbackSource = callbackDataSource;
     process_media_player_call(env, thiz, mp->setDataSource(dsd),
@@ -1013,7 +1020,7 @@
     }
 
     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
-                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+                                               "(Ljava/lang/Object;JIIILjava/lang/Object;)V");
     if (fields.post_event == NULL) {
         return;
     }
@@ -1383,13 +1390,13 @@
 static const JNINativeMethod gMethods[] = {
     {
         "nativeSetDataSource",
-        "(Landroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
+        "(JLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
         "[Ljava/lang/String;)V",
         (void *)android_media_MediaPlayer2_setDataSourceAndHeaders
     },
 
-    {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer2_setDataSourceFD},
-    {"_setDataSource",      "(Landroid/media/Media2DataSource;)V",(void *)android_media_MediaPlayer2_setDataSourceCallback },
+    {"_setDataSource",      "(JLjava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer2_setDataSourceFD},
+    {"_setDataSource",      "(JLandroid/media/Media2DataSource;)V",(void *)android_media_MediaPlayer2_setDataSourceCallback },
     {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer2_setVideoSurface},
     {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
     {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
index 5566b4e..ddb05f0 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
@@ -659,6 +659,10 @@
                 updatePreviewSurfaceWithVideo(videoSz, profile.videoFrameRate);
 
                 prepareVideoSnapshot(videoSnapshotRequestBuilder, imageListener);
+                Range<Integer> fpsRange = Range.create(profile.videoFrameRate,
+                        profile.videoFrameRate);
+                videoSnapshotRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
+                        fpsRange);
                 CaptureRequest request = videoSnapshotRequestBuilder.build();
 
                 // Start recording
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
index 88b85e0..12972f1 100644
--- a/packages/CtsShim/Android.mk
+++ b/packages/CtsShim/Android.mk
@@ -32,9 +32,10 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
 
-my_archs := arm x86
-my_src_arch := $(call get-prebuilt-src-arch, $(my_archs))
-LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShimPriv.apk
+LOCAL_SRC_FILES_arm := apk/arm/CtsShimPriv.apk
+LOCAL_SRC_FILES_arm64 := apk/arm/CtsShimPriv.apk
+LOCAL_SRC_FILES_x86 := apk/x86/CtsShimPriv.apk
+LOCAL_SRC_FILES_x86_64 := apk/x86/CtsShimPriv.apk
 
 include $(BUILD_PREBUILT)
 
@@ -53,9 +54,10 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
 
-my_archs := arm x86
-my_src_arch := $(call get-prebuilt-src-arch, $(my_archs))
-LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShim.apk
+LOCAL_SRC_FILES_arm := apk/arm/CtsShim.apk
+LOCAL_SRC_FILES_arm64 := apk/arm/CtsShim.apk
+LOCAL_SRC_FILES_x86 := apk/x86/CtsShim.apk
+LOCAL_SRC_FILES_x86_64 := apk/x86/CtsShim.apk
 
 include $(BUILD_PREBUILT)
 
diff --git a/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml
index 72be35b..15dd64b 100644
--- a/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml
+++ b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml
@@ -20,6 +20,8 @@
 
     <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="PrintSpoolerOutOfProcessTests" />
+    <option name="config-descriptor:metadata" key="component" value="print" />
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.printspooler.outofprocess.tests" />
         <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
diff --git a/packages/SettingsLib/res/layout/zen_mode_turn_on_dialog_container.xml b/packages/SettingsLib/res/layout/zen_mode_turn_on_dialog_container.xml
index ac56a2d..bc330c7 100644
--- a/packages/SettingsLib/res/layout/zen_mode_turn_on_dialog_container.xml
+++ b/packages/SettingsLib/res/layout/zen_mode_turn_on_dialog_container.xml
@@ -22,25 +22,40 @@
             android:fillViewport ="true"
             android:orientation="vertical">
 
-    <com.android.settingslib.notification.ZenRadioLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/zen_conditions"
+    <LinearLayout
+        android:id="@+id/dialog_container"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="8dp"
-        android:layout_marginEnd="4dp"
-        android:layout_marginStart="4dp"
-        android:paddingBottom="4dp"
-        android:orientation="horizontal">
-        <RadioGroup
-            android:id="@+id/zen_radio_buttons"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-        <LinearLayout
-            android:id="@+id/zen_radio_buttons_content"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
-            android:orientation="vertical"/>
-    </com.android.settingslib.notification.ZenRadioLayout>
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <com.android.settingslib.notification.ZenRadioLayout
+            android:id="@+id/zen_conditions"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:layout_marginEnd="4dp"
+            android:layout_marginStart="4dp"
+            android:paddingBottom="4dp"
+            android:orientation="horizontal">
+            <RadioGroup
+                android:id="@+id/zen_radio_buttons"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+            <LinearLayout
+                android:id="@+id/zen_radio_buttons_content"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:orientation="vertical"/>
+        </com.android.settingslib.notification.ZenRadioLayout>
+
+        <TextView
+            android:id="@+id/zen_alarm_warning"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="18dp"
+            android:layout_marginEnd="16dp"
+            android:textDirection="locale"
+            android:textColor="?android:attr/colorError"/>
+    </LinearLayout>
 
 </ScrollView>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index c926e1f..c1aa2dc 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -250,6 +250,19 @@
         <item>Best Effort (Adaptive Bit Rate)</item>
     </string-array>
 
+    <!-- TODO: Enable for translation per b/73007419 -->
+    <!-- Summaries for Bluetooth Audio Active Device status. [CHAR LIMIT=50]-->
+    <string-array name="bluetooth_audio_active_device_summaries" translatable="false" >
+        <!-- Status message when the device is not Active. -->
+        <item></item>
+        <!-- Status message when the device is Active for Media and Phone. -->
+        <item>, active</item>
+        <!-- Status message when the device is Active for Media only. -->
+        <item>, active(media)</item>
+        <!-- Status message when the device is Active for Phone only. -->
+        <item>, active(phone)</item>
+    </string-array>
+
     <!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
     <string-array name="select_logd_size_titles">
         <item>Off</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 486a9bb..e6f4ec6 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -128,27 +128,27 @@
      <!-- Bluetooth settings.  Message when connecting to a device -->
     <string name="bluetooth_connecting">Connecting\u2026</string>
     <!-- Bluetooth settings.  Message when connected to a device. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected">Connected</string>
+    <string name="bluetooth_connected">Connected<xliff:g id="active_device">%1$s</xliff:g></string>
     <!--Bluetooth settings screen, summary text under individual Bluetooth devices when pairing -->
     <string name="bluetooth_pairing">Pairing\u2026</string>
 
     <!-- Bluetooth settings.  Message when connected to a device, except for phone audio. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected_no_headset">Connected (no phone)</string>
+    <string name="bluetooth_connected_no_headset">Connected (no phone)<xliff:g id="active_device">%1$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for media audio. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected_no_a2dp">Connected (no media)</string>
+    <string name="bluetooth_connected_no_a2dp">Connected (no media)<xliff:g id="active_device">%1$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for map. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected_no_map">Connected (no message access)</string>
+    <string name="bluetooth_connected_no_map">Connected (no message access)<xliff:g id="active_device">%1$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for phone/media audio. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected_no_headset_no_a2dp">Connected (no phone or media)</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp">Connected (no phone or media)<xliff:g id="active_device">%1$s</xliff:g></string>
 
     <!-- Bluetooth settings.  Message when connected to a device, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_connected_battery_level">Connected, battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+    <string name="bluetooth_connected_battery_level">Connected, battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for phone audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_connected_no_headset_battery_level">Connected (no phone), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+    <string name="bluetooth_connected_no_headset_battery_level">Connected (no phone), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for media audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_connected_no_a2dp_battery_level">Connected (no media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+    <string name="bluetooth_connected_no_a2dp_battery_level">Connected (no media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for phone/media audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level">Connected (no phone or media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level">Connected (no phone or media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string>
 
     <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the A2DP profile. -->
     <string name="bluetooth_profile_a2dp">Media audio</string>
@@ -805,13 +805,17 @@
         <item>Colors optimized for digital content</item>
     </string-array>
 
-    <!-- Settings item title for inactive apps [CHAR LIMIT=35] -->
-    <string name="inactive_apps_title">Inactive apps</string>
+    <!-- Settings item title for apps in standby (limiting background activity) [CHAR LIMIT=35] -->
+    <string name="inactive_apps_title">Standby apps</string>
     <!-- Settings item summary for inactive app [CHAR LIMIT=100] -->
     <string name="inactive_app_inactive_summary">Inactive. Tap to toggle.</string>
     <!-- Settings item summary for active app [CHAR LIMIT=100] -->
     <string name="inactive_app_active_summary">Active. Tap to toggle.</string>
 
+    <!-- Settings item summary for standby bucket value of an app. [CHAR LIMIT=100] -->
+    <string name="standby_bucket_summary">App standby
+        state:<xliff:g id="bucket"> %s</xliff:g></string>
+
     <!-- Services settings screen, setting option name for the user to go to the screen to view running services -->
     <string name="runningservices_settings_title">Running services</string>
     <!-- Services settings screen, setting option summary for the user to go to the screen to view running services  -->
@@ -865,30 +869,49 @@
     <!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
     <string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
 
-    <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging -->
-    <string name="power_remaining_duration_only">About <xliff:g id="time">^1</xliff:g> left</string>
-    <!-- [CHAR_LIMIT=60] Label for estimated remaining duration of battery discharging -->
-    <string name="power_remaining_duration_only_enhanced">About <xliff:g id="time">^1</xliff:g> left based on your usage</string>
-    <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging -->
-    <string name="power_remaining_charging_duration_only"><xliff:g id="time">^1</xliff:g> left until fully charged</string>
+  <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging -->
+  <string name="power_remaining_duration_only">About <xliff:g id="time">%1$s</xliff:g> left</string>
+  <!-- [CHAR_LIMIT=60] Label for estimated remaining duration of battery discharging -->
+  <string name="power_remaining_duration_only_enhanced">About <xliff:g id="time">%1$s</xliff:g> left based on your usage</string>
+  <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging -->
+  <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until fully charged</string>
 
-    <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
-    <string name="power_remaining_duration_only_short"><xliff:g id="time">^1</xliff:g> left</string>
-    <!-- [CHAR_LIMIT=60] Short label for estimated remaining duration of battery charging/discharging -->
-    <string name="power_remaining_duration_only_short_enhanced"><xliff:g id="time">^1</xliff:g> left based on your usage</string>
+  <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
+  <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
 
-    <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
-    <string name="power_discharging_duration"><xliff:g id="level">^1</xliff:g> - about <xliff:g id="time">^2</xliff:g> left</string>
-    <!-- [CHAR_LIMIT=60] Label for battery level chart when discharging with duration and using enhanced estimate -->
-    <string name="power_discharging_duration_enhanced"><xliff:g id="level">^1</xliff:g> - about <xliff:g id="time">^2</xliff:g> left based on your usage</string>
+  <!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount -->
+  <string name="power_remaining_less_than_duration_only">Less than <xliff:g id="threshold">%1$s</xliff:g> remaining</string>
+  <!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount with the percentage -->
+  <string name="power_remaining_less_than_duration"><xliff:g id="level">%1$s</xliff:g> - Less than <xliff:g id="threshold">%2$s</xliff:g> remaining</string>
 
-    <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
-    <string name="power_discharging_duration_short"><xliff:g id="level">^1</xliff:g> - <xliff:g id="time">^2</xliff:g> left</string>
+  <!-- Used to let users know that they have more than some amount of battery life remaining with percentage. ex: 75% - more than 1 day remaining [CHAR LIMIT = 80] -->
+  <string name="power_remaining_more_than_subtext"><xliff:g id="level">%1$s</xliff:g>more than <xliff:g id="time_remaining">%2$s</xliff:g> remaining</string>
+  <!-- Used to let users know that they have more than some amount of battery life remaining. ex: more than 1 day remaining [CHAR LIMIT = 40] -->
+  <string name="power_remaining_only_more_than_subtext">more than <xliff:g id="time_remaining">%1$s</xliff:g> remaining</string>
+
+  <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
+  <string name="power_remaining_duration_only_shutdown_imminent" product="default">phone may shutdown soon</string>
+  <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
+  <string name="power_remaining_duration_only_shutdown_imminent" product="tablet">tablet may shutdown soon</string>
+  <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
+  <string name="power_remaining_duration_only_shutdown_imminent" product="device">device may shutdown soon</string>
+
+  <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
+  <string name="power_discharging_duration"><xliff:g id="level">%1$s</xliff:g> - about <xliff:g id="time">%2$s</xliff:g> left</string>
+  <!-- [CHAR_LIMIT=60] Label for battery level chart when discharging with duration and using enhanced estimate -->
+  <string name="power_discharging_duration_enhanced"><xliff:g id="level">%1$s</xliff:g> - about <xliff:g id="time">%2$s</xliff:g> left based on your usage</string>
+
+  <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
+  <string name="power_remaining_duration_shutdown_imminent" product="default"><xliff:g id="level">%1$s</xliff:g> - phone may shutdown soon</string>
+  <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
+  <string name="power_remaining_duration_shutdown_imminent" product="tablet"><xliff:g id="level">%1$s</xliff:g> - tablet may shutdown soon</string>
+  <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
+  <string name="power_remaining_duration_shutdown_imminent" product="device"><xliff:g id="level">%1$s</xliff:g> - device may shutdown soon</string>
 
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging -->
     <string name="power_charging"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="state">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
-    <string name="power_charging_duration"><xliff:g id="level">^1</xliff:g> - <xliff:g id="time">^2</xliff:g> until fully charged</string>
+    <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until fully charged</string>
 
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_unknown">Unknown</string>
@@ -1039,5 +1062,13 @@
     <string name="zen_interruption_level_priority">Priority only</string>
     <!-- [CHAR LIMIT=20] Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description.  -->
     <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
+    <!-- Warning text when an alarm might be silenced by Do Not Disturb [CHAR LIMIT=NONE] -->
+    <string name="zen_alarm_warning_indef">You won\'t hear your next alarm <xliff:g id="when" example="at 7:00 AM">%1$s</xliff:g> unless you turn this off before then</string>
+    <!-- Warning text when an alarm might be silenced by Do Not Disturb due to a time-based condition [CHAR LIMIT=NONE] -->
+    <string name="zen_alarm_warning">You won\'t hear your next alarm <xliff:g id="when" example="at 7:00 AM">%1$s</xliff:g></string>
+    <!-- Alarm template for near alarms [CHAR LIMIT=25] -->
+    <string name="alarm_template">at <xliff:g id="when" example="7:00 AM">%1$s</xliff:g></string>
+    <!-- Alarm template for far in the future alarms [CHAR LIMIT=25] -->
+    <string name="alarm_template_far">on <xliff:g id="when" example="Fri 7:00 AM">%1$s</xliff:g></string>
 
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index fb0f75b..e1ebbc4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -940,60 +940,55 @@
                     com.android.settingslib.Utils.formatPercentage(batteryLevel);
         }
 
-        // TODO: A temporary workaround solution using string description the device is active.
-        // Issue tracked by b/72317067 .
-        // An alternative solution would be visual indication.
-        // Intentionally not adding the strings to strings.xml for now:
-        //  1) If this is just a short-term solution, no need to waste translation effort
-        //  2) The number of strings with all possible combinations becomes enormously large.
-        // If string description becomes part of the final solution, we MUST NOT
-        // concatenate the strings here: this does not translate well.
-        String activeString = null;
+        // Prepare the string for the Active Device summary
+        String[] activeDeviceStringsArray = mContext.getResources().getStringArray(
+                R.array.bluetooth_audio_active_device_summaries);
+        String activeDeviceString = activeDeviceStringsArray[0];  // Default value: not active
         if (mIsActiveDeviceA2dp && mIsActiveDeviceHeadset) {
-            activeString = ", active";
+            activeDeviceString = activeDeviceStringsArray[1];     // Active for Media and Phone
         } else {
             if (mIsActiveDeviceA2dp) {
-                activeString = ", active(media)";
+                activeDeviceString = activeDeviceStringsArray[2]; // Active for Media only
             }
             if (mIsActiveDeviceHeadset) {
-                activeString = ", active(phone)";
+                activeDeviceString = activeDeviceStringsArray[3]; // Active for Phone only
             }
         }
-        if (activeString == null) activeString = "";
 
         if (profileConnected) {
             if (a2dpNotConnected && hfpNotConnected) {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(
                             R.string.bluetooth_connected_no_headset_no_a2dp_battery_level,
-                            batteryLevelPercentageString) + activeString;
+                            batteryLevelPercentageString, activeDeviceString);
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp) +
-                        activeString;
+                    return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp,
+                            activeDeviceString);
                 }
 
             } else if (a2dpNotConnected) {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(R.string.bluetooth_connected_no_a2dp_battery_level,
-                            batteryLevelPercentageString) + activeString;
+                            batteryLevelPercentageString, activeDeviceString);
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected_no_a2dp) + activeString;
+                    return mContext.getString(R.string.bluetooth_connected_no_a2dp,
+                            activeDeviceString);
                 }
 
             } else if (hfpNotConnected) {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(R.string.bluetooth_connected_no_headset_battery_level,
-                            batteryLevelPercentageString) + activeString;
+                            batteryLevelPercentageString, activeDeviceString);
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected_no_headset)
-                          + activeString;
+                    return mContext.getString(R.string.bluetooth_connected_no_headset,
+                            activeDeviceString);
                 }
             } else {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(R.string.bluetooth_connected_battery_level,
-                            batteryLevelPercentageString) + activeString;
+                            batteryLevelPercentageString, activeDeviceString);
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected) + activeString;
+                    return mContext.getString(R.string.bluetooth_connected, activeDeviceString);
                 }
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
old mode 100755
new mode 100644
index cda4e45..5f7ba586
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -194,8 +194,13 @@
         return mState;
     }
 
-    synchronized void setBluetoothStateInt(int state) {
-        mState = state;
+    void setBluetoothStateInt(int state) {
+        synchronized(this) {
+            if (mState == state) {
+                return;
+            }
+            mState = state;
+        }
 
         if (state == BluetoothAdapter.STATE_ON) {
             // if mProfileManager hasn't been constructed yet, it will
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java b/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java
index 4e78d9b..85bf4e8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.support.v4.content.LocalBroadcastManager;
 
@@ -27,7 +28,8 @@
     public static final String DEVELOPMENT_SETTINGS_CHANGED_ACTION =
             "com.android.settingslib.development.DevelopmentSettingsEnabler.SETTINGS_CHANGED";
 
-    private DevelopmentSettingsEnabler() {}
+    private DevelopmentSettingsEnabler() {
+    }
 
     public static void setDevelopmentSettingsEnabled(Context context, boolean enable) {
         Settings.Global.putInt(context.getContentResolver(),
@@ -37,8 +39,14 @@
     }
 
     public static boolean isDevelopmentSettingsEnabled(Context context) {
-        return Settings.Global.getInt(context.getContentResolver(),
+        final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        final boolean settingEnabled = Settings.Global.getInt(context.getContentResolver(),
                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
                 Build.TYPE.equals("eng") ? 1 : 0) != 0;
+        final boolean hasRestriction = um.hasUserRestriction(
+                UserManager.DISALLOW_DEBUGGING_FEATURES);
+        final boolean isAdmin = um.isAdminUser();
+
+        return isAdmin && !hasRestriction && settingEnabled;
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 190f5e6..68ead09 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -17,7 +17,6 @@
 
 import android.annotation.LayoutRes;
 import android.annotation.Nullable;
-import android.app.ActionBar;
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -72,9 +71,9 @@
             requestWindowFeature(Window.FEATURE_NO_TITLE);
         }
         super.setContentView(R.layout.settings_with_drawer);
-        mContentHeaderContainer = (FrameLayout) findViewById(R.id.content_header_container);
+        mContentHeaderContainer = findViewById(R.id.content_header_container);
 
-        Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
+        Toolbar toolbar = findViewById(R.id.action_bar);
         if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
             toolbar.setVisibility(View.GONE);
             return;
@@ -89,7 +88,9 @@
 
     @Override
     public boolean onNavigateUp() {
-        finish();
+        if (!super.onNavigateUp()) {
+            finish();
+        }
         return true;
     }
 
@@ -104,11 +105,6 @@
         registerReceiver(mPackageReceiver, filter);
 
         new CategoriesUpdateTask().execute();
-        final Intent intent = getIntent();
-        if (intent != null && intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
-            // Intent explicitly set to show menu.
-            showMenuIcon();
-        }
     }
 
     @Override
@@ -125,13 +121,6 @@
         mCategoryListeners.remove(listener);
     }
 
-    public void setContentHeaderView(View headerView) {
-        mContentHeaderContainer.removeAllViews();
-        if (headerView != null) {
-            mContentHeaderContainer.addView(headerView);
-        }
-    }
-
     @Override
     public void setContentView(@LayoutRes int layoutResID) {
         final ViewGroup parent = findViewById(R.id.content_frame);
@@ -151,13 +140,6 @@
         ((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
     }
 
-    private void showMenuIcon() {
-        final ActionBar actionBar = getActionBar();
-        if (actionBar != null) {
-            actionBar.setDisplayHomeAsUpEnabled(true);
-        }
-    }
-
     private void onCategoriesChanged() {
         final int N = mCategoryListeners.size();
         for (int i = 0; i < N; i++) {
@@ -165,10 +147,6 @@
         }
     }
 
-    public void onProfileTileOpen() {
-        finish();
-    }
-
     /**
      * @return whether or not the enabled state actually changed.
      */
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index ed3696c..f7aa297 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -158,6 +158,9 @@
             usage.startDate = start;
             usage.usageLevel = totalBytes;
             usage.period = formatDateRange(start, end);
+            usage.cycleStart = start;
+            usage.cycleEnd = end;
+
             if (policy != null) {
                 usage.limitLevel = policy.limitBytes > 0 ? policy.limitBytes : 0;
                 usage.warningLevel = policy.warningBytes > 0 ? policy.warningBytes : 0;
@@ -245,6 +248,8 @@
         public long limitLevel;
         public long warningLevel;
         public long usageLevel;
+        public long cycleStart;
+        public long cycleEnd;
     }
 
     public interface Callback {
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index a20f687..1a54d6a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -1,5 +1,3 @@
-package com.android.settingslib.notification;
-
 /*
  * Copyright (C) 2018 The Android Open Source Project
  *
@@ -16,6 +14,8 @@
  * limitations under the License.
  */
 
+package com.android.settingslib.notification;
+
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.AlertDialog;
@@ -28,6 +28,7 @@
 import android.service.notification.Condition;
 import android.service.notification.ZenModeConfig;
 import android.text.TextUtils;
+import android.text.format.DateFormat;
 import android.util.Log;
 import android.util.Slog;
 import android.view.LayoutInflater;
@@ -40,6 +41,7 @@
 import android.widget.ScrollView;
 import android.widget.TextView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.policy.PhoneWindow;
@@ -48,11 +50,11 @@
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
+import java.util.Locale;
 import java.util.Objects;
 
 public class EnableZenModeDialog {
-
-    private static final String TAG = "QSEnableZenModeDialog";
+    private static final String TAG = "EnableZenModeDialog";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
@@ -60,25 +62,37 @@
     private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
     private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
 
-    private static final int FOREVER_CONDITION_INDEX = 0;
-    private static final int COUNTDOWN_CONDITION_INDEX = 1;
-    private static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2;
+    @VisibleForTesting
+    protected static final int FOREVER_CONDITION_INDEX = 0;
+    @VisibleForTesting
+    protected static final int COUNTDOWN_CONDITION_INDEX = 1;
+    @VisibleForTesting
+    protected static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2;
 
     private static final int SECONDS_MS = 1000;
     private static final int MINUTES_MS = 60 * SECONDS_MS;
 
-    private Uri mForeverId;
+    @VisibleForTesting
+    protected Uri mForeverId;
     private int mBucketIndex = -1;
 
     private AlarmManager mAlarmManager;
     private int mUserId;
     private boolean mAttached;
 
-    private Context mContext;
+    @VisibleForTesting
+    protected Context mContext;
+    @VisibleForTesting
+    protected TextView mZenAlarmWarning;
+    @VisibleForTesting
+    protected LinearLayout mZenRadioGroupContent;
+
     private RadioGroup mZenRadioGroup;
-    private LinearLayout mZenRadioGroupContent;
     private int MAX_MANUAL_DND_OPTIONS = 3;
 
+    @VisibleForTesting
+    protected LayoutInflater mLayoutInflater;
+
     public EnableZenModeDialog(Context context) {
         mContext = context;
     }
@@ -133,32 +147,40 @@
         for (int i = 0; i < N; i++) {
             mZenRadioGroupContent.getChildAt(i).setVisibility(View.GONE);
         }
+
+        mZenAlarmWarning.setVisibility(View.GONE);
     }
 
     protected View getContentView() {
-        final LayoutInflater inflater = new PhoneWindow(mContext).getLayoutInflater();
-        View contentView = inflater.inflate(R.layout.zen_mode_turn_on_dialog_container, null);
+        if (mLayoutInflater == null) {
+            mLayoutInflater = new PhoneWindow(mContext).getLayoutInflater();
+        }
+        View contentView = mLayoutInflater.inflate(R.layout.zen_mode_turn_on_dialog_container,
+                null);
         ScrollView container = (ScrollView) contentView.findViewById(R.id.container);
 
         mZenRadioGroup = container.findViewById(R.id.zen_radio_buttons);
         mZenRadioGroupContent = container.findViewById(R.id.zen_radio_buttons_content);
+        mZenAlarmWarning = container.findViewById(R.id.zen_alarm_warning);
 
         for (int i = 0; i < MAX_MANUAL_DND_OPTIONS; i++) {
-            final View radioButton = inflater.inflate(R.layout.zen_mode_radio_button,
+            final View radioButton = mLayoutInflater.inflate(R.layout.zen_mode_radio_button,
                     mZenRadioGroup, false);
             mZenRadioGroup.addView(radioButton);
             radioButton.setId(i);
 
-            final View radioButtonContent = inflater.inflate(R.layout.zen_mode_condition,
+            final View radioButtonContent = mLayoutInflater.inflate(R.layout.zen_mode_condition,
                     mZenRadioGroupContent, false);
             radioButtonContent.setId(i + MAX_MANUAL_DND_OPTIONS);
             mZenRadioGroupContent.addView(radioButtonContent);
         }
+
         hideAllConditions();
         return contentView;
     }
 
-    private void bind(final Condition condition, final View row, final int rowId) {
+    @VisibleForTesting
+    protected void bind(final Condition condition, final View row, final int rowId) {
         if (condition == null) throw new IllegalArgumentException("condition must not be null");
         final boolean enabled = condition.state == Condition.STATE_TRUE;
         final ConditionTag tag = row.getTag() != null ? (ConditionTag) row.getTag() :
@@ -181,6 +203,7 @@
                     if (DEBUG) Log.d(TAG, "onCheckedChanged " + conditionId);
                     MetricsLogger.action(mContext,
                             MetricsProto.MetricsEvent.QS_DND_CONDITION_SELECT);
+                    updateAlarmWarningText(tag.condition);
                     announceConditionSelection(tag);
                 }
             }
@@ -190,11 +213,13 @@
         row.setVisibility(View.VISIBLE);
     }
 
-    private ConditionTag getConditionTagAt(int index) {
+    @VisibleForTesting
+    protected ConditionTag getConditionTagAt(int index) {
         return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
     }
 
-    private void bindConditions(Condition c) {
+    @VisibleForTesting
+    protected void bindConditions(Condition c) {
         // forever
         bind(forever(), mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
                 FOREVER_CONDITION_INDEX);
@@ -236,11 +261,13 @@
         return info != null ? info.getTriggerTime() : 0;
     }
 
-    private boolean isAlarm(Condition c) {
+    @VisibleForTesting
+    protected boolean isAlarm(Condition c) {
         return c != null && ZenModeConfig.isValidCountdownToAlarmConditionId(c.id);
     }
 
-    private boolean isCountdown(Condition c) {
+    @VisibleForTesting
+    protected boolean isCountdown(Condition c) {
         return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
     }
 
@@ -264,7 +291,8 @@
     }
 
     // Returns a time condition if the next alarm is within the next week.
-    private Condition getTimeUntilNextAlarmCondition() {
+    @VisibleForTesting
+    protected Condition getTimeUntilNextAlarmCondition() {
         GregorianCalendar weekRange = new GregorianCalendar();
         setToMidnight(weekRange);
         weekRange.add(Calendar.DATE, 6);
@@ -282,7 +310,8 @@
         return null;
     }
 
-    private void bindGenericCountdown() {
+    @VisibleForTesting
+    protected void bindGenericCountdown() {
         mBucketIndex = DEFAULT_BUCKET_INDEX;
         Condition countdown = ZenModeConfig.toTimeCondition(mContext,
                 MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
@@ -366,7 +395,8 @@
         }
     }
 
-    private void bindNextAlarm(Condition c) {
+    @VisibleForTesting
+    protected void bindNextAlarm(Condition c) {
         View alarmContent = mZenRadioGroupContent.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX);
         ConditionTag tag = (ConditionTag) alarmContent.getTag();
 
@@ -415,6 +445,7 @@
                     MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
         }
         bind(newCondition, row, rowId);
+        updateAlarmWarningText(tag.condition);
         tag.rb.setChecked(true);
         announceConditionSelection(tag);
     }
@@ -428,8 +459,43 @@
         }
     }
 
+    private void updateAlarmWarningText(Condition condition) {
+        String warningText = computeAlarmWarningText(condition);
+        mZenAlarmWarning.setText(warningText);
+        mZenAlarmWarning.setVisibility(warningText == null ? View.GONE : View.VISIBLE);
+    }
+
+    private String computeAlarmWarningText(Condition condition) {
+        final long now = System.currentTimeMillis();
+        final long nextAlarm = getNextAlarm();
+        if (nextAlarm < now) {
+            return null;
+        }
+        int warningRes = 0;
+        if (condition == null || isForever(condition)) {
+            warningRes = R.string.zen_alarm_warning_indef;
+        } else {
+            final long time = ZenModeConfig.tryParseCountdownConditionId(condition.id);
+            if (time > now && nextAlarm < time) {
+                warningRes = R.string.zen_alarm_warning;
+            }
+        }
+        if (warningRes == 0) {
+            return null;
+        }
+        final boolean soon = (nextAlarm - now) < 24 * 60 * 60 * 1000;
+        final boolean is24 = DateFormat.is24HourFormat(mContext, ActivityManager.getCurrentUser());
+        final String skeleton = soon ? (is24 ? "Hm" : "hma") : (is24 ? "EEEHm" : "EEEhma");
+        final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
+        final CharSequence formattedTime = DateFormat.format(pattern, nextAlarm);
+        final int templateRes = soon ? R.string.alarm_template : R.string.alarm_template_far;
+        final String template = mContext.getResources().getString(templateRes, formattedTime);
+        return mContext.getResources().getString(warningRes, template);
+    }
+
     // used as the view tag on condition rows
-    private static class ConditionTag {
+    @VisibleForTesting
+    protected static class ConditionTag {
         public RadioButton rb;
         public View lines;
         public TextView line1;
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
new file mode 100644
index 0000000..346ca66
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
@@ -0,0 +1,143 @@
+/*
+ * 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.settingslib.utils;
+
+import android.content.Context;
+import android.icu.text.MeasureFormat;
+import android.icu.text.MeasureFormat.FormatWidth;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import com.android.settingslib.R;
+import com.android.settingslib.utils.StringUtil;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+/** Utility class for keeping power related strings consistent**/
+public class PowerUtil {
+    private static final long SEVEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(7);
+    private static final long FIFTEEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(15);
+    private static final long ONE_DAY_MILLIS = TimeUnit.DAYS.toMillis(1);
+
+    /**
+     * This method produces the text used in various places throughout the system to describe the
+     * remaining battery life of the phone in a consistent manner.
+     *
+     * @param context
+     * @param drainTimeMs The estimated time remaining before the phone dies in milliseconds.
+     * @param percentageString An optional percentage of battery remaining string.
+     * @param basedOnUsage Whether this estimate is based on usage or simple extrapolation.
+     * @return a properly formatted and localized string describing how much time remains
+     * before the battery runs out.
+     */
+    public static String getBatteryRemainingStringFormatted(Context context, long drainTimeMs,
+            @Nullable String percentageString, boolean basedOnUsage) {
+        if (drainTimeMs > 0) {
+            if (drainTimeMs <= SEVEN_MINUTES_MILLIS) {
+                // show a imminent shutdown warning if less than 7 minutes remain
+                return getShutdownImminentString(context, percentageString);
+            } else if (drainTimeMs <= FIFTEEN_MINUTES_MILLIS) {
+                // show a less than 15 min remaining warning if appropriate
+                CharSequence timeString = StringUtil.formatElapsedTime(context,
+                        FIFTEEN_MINUTES_MILLIS,
+                        false /* withSeconds */);
+                return getUnderFifteenString(context, timeString, percentageString);
+            } else if (drainTimeMs >= ONE_DAY_MILLIS) {
+                // just say more than one day if over 24 hours
+                return getMoreThanOneDayString(context, percentageString);
+            } else {
+                // show a regular time remaining string
+                return getRegularTimeRemainingString(context, drainTimeMs,
+                        percentageString, basedOnUsage);
+            }
+        }
+        return null;
+    }
+
+    private static String getShutdownImminentString(Context context, String percentageString) {
+        return TextUtils.isEmpty(percentageString)
+                ? context.getString(R.string.power_remaining_duration_only_shutdown_imminent)
+                : context.getString(
+                        R.string.power_remaining_duration_shutdown_imminent,
+                        percentageString);
+    }
+
+    private static String getUnderFifteenString(Context context, CharSequence timeString,
+            String percentageString) {
+        return TextUtils.isEmpty(percentageString)
+                ? context.getString(R.string.power_remaining_less_than_duration_only, timeString)
+                : context.getString(
+                        R.string.power_remaining_less_than_duration,
+                        percentageString,
+                        timeString);
+
+    }
+
+    private static String getMoreThanOneDayString(Context context, String percentageString) {
+        final Locale currentLocale = context.getResources().getConfiguration().getLocales().get(0);
+        final MeasureFormat frmt = MeasureFormat.getInstance(currentLocale, FormatWidth.SHORT);
+
+        final Measure daysMeasure = new Measure(1, MeasureUnit.DAY);
+
+        return TextUtils.isEmpty(percentageString)
+                ? context.getString(R.string.power_remaining_only_more_than_subtext,
+                        frmt.formatMeasures(daysMeasure))
+                : context.getString(
+                        R.string.power_remaining_more_than_subtext,
+                        percentageString,
+                        frmt.formatMeasures(daysMeasure));
+    }
+
+    private static String getRegularTimeRemainingString(Context context, long drainTimeMs,
+            String percentageString, boolean basedOnUsage) {
+        // round to the nearest 15 min to not appear oversly precise
+        final long roundedTimeMs = roundToNearestThreshold(drainTimeMs,
+                FIFTEEN_MINUTES_MILLIS);
+        CharSequence timeString = StringUtil.formatElapsedTime(context,
+                roundedTimeMs,
+                false /* withSeconds */);
+        if (TextUtils.isEmpty(percentageString)) {
+            int id = basedOnUsage
+                    ? R.string.power_remaining_duration_only_enhanced
+                    : R.string.power_remaining_duration_only;
+            return context.getString(id, timeString);
+        } else {
+            int id = basedOnUsage
+                    ? R.string.power_discharging_duration_enhanced
+                    : R.string.power_discharging_duration;
+            return context.getString(id, percentageString, timeString);
+        }
+    }
+
+    public static long convertUsToMs(long timeUs) {
+        return timeUs / 1000;
+    }
+
+    public static long convertMsToUs(long timeMs) {
+        return timeMs * 1000;
+    }
+
+    private static long roundToNearestThreshold(long drainTime, long threshold) {
+        final long remainder = drainTime % threshold;
+        if (remainder < threshold / 2) {
+            return drainTime - remainder;
+        } else {
+            return drainTime - remainder + threshold;
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
new file mode 100644
index 0000000..45fdd78
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.utils;
+
+import android.content.Context;
+import android.icu.text.MeasureFormat;
+import android.icu.text.MeasureFormat.FormatWidth;
+import android.icu.text.RelativeDateTimeFormatter;
+import android.icu.text.RelativeDateTimeFormatter.RelativeUnit;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
+import android.icu.util.ULocale;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.TtsSpan;
+import java.util.ArrayList;
+import java.util.Locale;
+
+/** Utility class for generally useful string methods **/
+public class StringUtil {
+
+  public static final int SECONDS_PER_MINUTE = 60;
+  public static final int SECONDS_PER_HOUR = 60 * 60;
+  public static final int SECONDS_PER_DAY = 24 * 60 * 60;
+
+  /**
+   * Returns elapsed time for the given millis, in the following format:
+   * 2d 5h 40m 29s
+   * @param context the application context
+   * @param millis the elapsed time in milli seconds
+   * @param withSeconds include seconds?
+   * @return the formatted elapsed time
+   */
+  public static CharSequence formatElapsedTime(Context context, double millis,
+          boolean withSeconds) {
+      SpannableStringBuilder sb = new SpannableStringBuilder();
+      int seconds = (int) Math.floor(millis / 1000);
+      if (!withSeconds) {
+          // Round up.
+          seconds += 30;
+      }
+
+      int days = 0, hours = 0, minutes = 0;
+      if (seconds >= SECONDS_PER_DAY) {
+          days = seconds / SECONDS_PER_DAY;
+          seconds -= days * SECONDS_PER_DAY;
+      }
+      if (seconds >= SECONDS_PER_HOUR) {
+          hours = seconds / SECONDS_PER_HOUR;
+          seconds -= hours * SECONDS_PER_HOUR;
+      }
+      if (seconds >= SECONDS_PER_MINUTE) {
+          minutes = seconds / SECONDS_PER_MINUTE;
+          seconds -= minutes * SECONDS_PER_MINUTE;
+      }
+
+      final ArrayList<Measure> measureList = new ArrayList(4);
+      if (days > 0) {
+          measureList.add(new Measure(days, MeasureUnit.DAY));
+      }
+      if (hours > 0) {
+          measureList.add(new Measure(hours, MeasureUnit.HOUR));
+      }
+      if (minutes > 0) {
+          measureList.add(new Measure(minutes, MeasureUnit.MINUTE));
+      }
+      if (withSeconds && seconds > 0) {
+          measureList.add(new Measure(seconds, MeasureUnit.SECOND));
+      }
+      if (measureList.size() == 0) {
+          // Everything addable was zero, so nothing was added. We add a zero.
+          measureList.add(new Measure(0, withSeconds ? MeasureUnit.SECOND : MeasureUnit.MINUTE));
+      }
+      final Measure[] measureArray = measureList.toArray(new Measure[measureList.size()]);
+
+      final Locale locale = context.getResources().getConfiguration().locale;
+      final MeasureFormat measureFormat = MeasureFormat.getInstance(
+              locale, FormatWidth.NARROW);
+      sb.append(measureFormat.formatMeasures(measureArray));
+
+      if (measureArray.length == 1 && MeasureUnit.MINUTE.equals(measureArray[0].getUnit())) {
+          // Add ttsSpan if it only have minute value, because it will be read as "meters"
+          final TtsSpan ttsSpan = new TtsSpan.MeasureBuilder().setNumber(minutes)
+                  .setUnit("minute").build();
+          sb.setSpan(ttsSpan, 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+      }
+
+      return sb;
+  }
+
+    /**
+     * Returns relative time for the given millis in the past, in a short format such as "2 days
+     * ago", "5 hr. ago", "40 min. ago", or "29 sec. ago".
+     *
+     * <p>The unit is chosen to have good information value while only using one unit. So 27 hours
+     * and 50 minutes would be formatted as "28 hr. ago", while 50 hours would be formatted as
+     * "2 days ago".
+     *
+     * @param context the application context
+     * @param millis the elapsed time in milli seconds
+     * @param withSeconds include seconds?
+     * @return the formatted elapsed time
+     */
+    public static CharSequence formatRelativeTime(Context context, double millis,
+            boolean withSeconds) {
+        final int seconds = (int) Math.floor(millis / 1000);
+        final RelativeUnit unit;
+        final int value;
+        if (withSeconds && seconds < 2 * SECONDS_PER_MINUTE) {
+            unit = RelativeUnit.SECONDS;
+            value = seconds;
+        } else if (seconds < 2 * SECONDS_PER_HOUR) {
+            unit = RelativeUnit.MINUTES;
+            value = (seconds + SECONDS_PER_MINUTE / 2)
+                    / SECONDS_PER_MINUTE;
+        } else if (seconds < 2 * SECONDS_PER_DAY) {
+            unit = RelativeUnit.HOURS;
+            value = (seconds + SECONDS_PER_HOUR / 2)
+                    / SECONDS_PER_HOUR;
+        } else {
+            unit = RelativeUnit.DAYS;
+            value = (seconds + SECONDS_PER_DAY / 2)
+                    / SECONDS_PER_DAY;
+        }
+
+        final Locale locale = context.getResources().getConfiguration().locale;
+        final RelativeDateTimeFormatter formatter = RelativeDateTimeFormatter.getInstance(
+                ULocale.forLocale(locale),
+                null /* default NumberFormat */,
+                RelativeDateTimeFormatter.Style.SHORT,
+                android.icu.text.DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE);
+
+        return formatter.format(value, RelativeDateTimeFormatter.Direction.LAST, unit);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 109eb97..8115ede2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -41,7 +41,7 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.wifi.AccessPoint.Speed;
 
-public class AccessPointPreference extends TwoTargetPreference {
+public class AccessPointPreference extends Preference {
 
     private static final int[] STATE_SECURED = {
             R.attr.state_encrypted
@@ -115,6 +115,7 @@
                           int iconResId, boolean forSavedNetworks, StateListDrawable frictionSld,
                           int level, IconInjector iconInjector) {
         super(context);
+        setWidgetLayoutResource(R.layout.access_point_friction_widget);
         mBadgeCache = cache;
         mAccessPoint = accessPoint;
         mForSavedNetworks = forSavedNetworks;
@@ -153,20 +154,6 @@
 
         ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
         bindFrictionImage(frictionImageView);
-        setDividerVisibility(view, View.GONE);
-    }
-
-    protected void setDividerVisibility(final PreferenceViewHolder view,
-            @View.Visibility int visibility) {
-        final View divider = view.findViewById(R.id.two_target_divider);
-        if (divider != null) {
-            divider.setVisibility(visibility);
-        }
-    }
-
-    @Override
-    protected int getSecondTargetResId() {
-        return R.layout.access_point_friction_widget;
     }
 
     protected void updateIcon(int level, Context context) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
index 003f905..2f417ad 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
@@ -18,8 +18,6 @@
 
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
 
 import android.app.Instrumentation;
@@ -49,42 +47,22 @@
     }
 
     @Test
-    public void startActivityWithNoExtra_showNoNavUp() {
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        instrumentation.startActivitySync(new Intent(instrumentation.getTargetContext(),
-                TestActivity.class));
-
-        onView(withContentDescription(com.android.internal.R.string.action_bar_up_description))
-                .check(doesNotExist());
-    }
-
-    @Test
-    public void startActivityWithExtraToHideMenu_showNavUp() {
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class)
-                .putExtra(TestActivity.EXTRA_SHOW_MENU, false);
+    public void startActivity_doNotShowNavUp() {
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         instrumentation.startActivitySync(intent);
 
         onView(withContentDescription(com.android.internal.R.string.action_bar_up_description))
                 .check(doesNotExist());
     }
 
-    @Test
-    public void startActivityWithExtraToShowMenu_showNavUp() {
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class)
-                .putExtra(TestActivity.EXTRA_SHOW_MENU, true);
-        instrumentation.startActivitySync(intent);
-
-        onView(withContentDescription(com.android.internal.R.string.action_bar_up_description))
-                .check(matches(isDisplayed()));
-    }
-
     /**
      * Test Activity in this test.
      *
      * Use this activity because SettingsDrawerActivity hasn't been registered in its
      * AndroidManifest.xml
      */
-    public static class TestActivity extends SettingsDrawerActivity {}
+    public static class TestActivity extends SettingsDrawerActivity {
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 4091ce1..1481161 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -80,22 +80,12 @@
         doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel();
     }
 
-    /**
-     * Test to verify the current test context object works so that we are not checking null
-     * against null
-     */
-    @Test
-    public void testContextMock() {
-        assertThat(mContext.getString(R.string.bluetooth_connected)).isEqualTo("Connected");
-    }
-
     @Test
     public void testGetConnectionSummary_testSingleProfileConnectDisconnect() {
         // Test without battery level
         // Set PAN profile to be connected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
 
         // Set PAN profile to be disconnected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -105,9 +95,7 @@
         mBatteryLevel = 10;
         // Set PAN profile to be connected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, battery 10%");
 
         // Set PAN profile to be disconnected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -118,8 +106,7 @@
 
         // Set PAN profile to be connected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
 
         // Set PAN profile to be disconnected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -134,28 +121,23 @@
         mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, battery 10%");
 
         // Disconnect HFP only and test connection state summary
         mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_no_headset_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no phone), battery 10%");
 
         // Disconnect A2DP only and test connection state summary
         mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_no_a2dp_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no media), battery 10%");
 
         // Disconnect both HFP and A2DP and test connection state summary
         mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_no_headset_no_a2dp_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no phone or media), battery 10%");
 
         // Disconnect all profiles and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -163,6 +145,117 @@
     }
 
     @Test
+    public void testGetConnectionSummary_testSingleProfileActiveDeviceA2dp() {
+        // Test without battery level
+        // Set A2DP profile to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
+
+        // Set device as Active for A2DP and test connection state summary
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(media)");
+
+        // Test with battery level
+        mBatteryLevel = 10;
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected, battery 10%, active(media)");
+
+        // Set A2DP profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+
+        // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
+        mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+        // Set A2DP profile to be connected, Active and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(media)");
+
+        // Set A2DP profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+
+    @Test
+    public void testGetConnectionSummary_testSingleProfileActiveDeviceHfp() {
+        // Test without battery level
+        // Set HFP profile to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
+
+        // Set device as Active for HFP and test connection state summary
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(phone)");
+
+        // Test with battery level
+        mBatteryLevel = 10;
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected, battery 10%, active(phone)");
+
+        // Set HFP profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+
+        // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
+        mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+        // Set HFP profile to be connected, Active and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(phone)");
+
+        // Set HFP profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+
+    @Test
+    public void testGetConnectionSummary_testMultipleProfilesActiveDevice() {
+        // Test without battery level
+        // Set A2DP and HFP profiles to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
+
+        // Set device as Active for A2DP and HFP and test connection state summary
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active");
+
+        // Test with battery level
+        mBatteryLevel = 10;
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected, battery 10%, active");
+
+        // Disconnect A2DP only and test connection state summary
+        mCachedDevice.setActiveDevice(false, BluetoothProfile.A2DP);
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no media), battery 10%, active(phone)");
+
+        // Disconnect HFP only and test connection state summary
+        mCachedDevice.setActiveDevice(false, BluetoothProfile.HEADSET);
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no phone), battery 10%, active(media)");
+
+        // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
+        mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+        // Set A2DP and HFP profiles to be connected, Active and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active");
+
+        // Set A2DP and HFP profiles to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+
+    @Test
     public void testDeviceName_testAliasNameAvailable() {
         when(mDevice.getAliasName()).thenReturn(DEVICE_ALIAS);
         when(mDevice.getName()).thenReturn(DEVICE_NAME);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
index d19d19a..708353e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
@@ -23,7 +23,9 @@
 
 import com.android.settingslib.SettingsLibRobolectricTestRunner;
 import com.android.settingslib.TestConfig;
+import com.android.settingslib.testutils.shadow.ShadowUserManager;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -31,7 +33,9 @@
 import org.robolectric.annotation.Config;
 
 @RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = {
+        ShadowUserManager.class
+})
 public class DevelopmentSettingsEnablerTest {
 
     private Context mContext;
@@ -39,10 +43,16 @@
     @Before
     public void setUp() {
         mContext = RuntimeEnvironment.application;
+        ShadowUserManager.getShadow().setIsAdminUser(true);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowUserManager.getShadow().reset();
     }
 
     @Test
-    public void testEnabling() {
+    public void isEnabled_settingsOn_noRestriction_isAdmin_shouldReturnTrue() {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
 
@@ -54,7 +64,7 @@
     }
 
     @Test
-    public void testDisabling() {
+    public void isEnabled_settingsOff_noRestriction_isAdmin_shouldReturnFalse() {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
 
@@ -64,4 +74,13 @@
 
         assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse();
     }
+
+    @Test
+    public void isEnabled_settingsOn_noRestriction_notAdmin_shouldReturnFalse() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+        ShadowUserManager.getShadow().setIsAdminUser(false);
+
+        assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
new file mode 100644
index 0000000..777cd98
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.notification;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Context;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.view.LayoutInflater;
+
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EnableZenModeDialogTest {
+    private EnableZenModeDialog mController;
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private Fragment mFragment;
+
+    private Context mShadowContext;
+    private LayoutInflater mLayoutInflater;
+    private Condition mCountdownCondition;
+    private Condition mAlarmCondition;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mShadowContext = RuntimeEnvironment.application;
+        when(mContext.getApplicationContext()).thenReturn(mContext);
+        when(mFragment.getContext()).thenReturn(mShadowContext);
+        mLayoutInflater = LayoutInflater.from(mShadowContext);
+
+        mController = spy(new EnableZenModeDialog(mContext));
+        mController.mContext = mContext;
+        mController.mLayoutInflater = mLayoutInflater;
+        mController.mForeverId =  Condition.newId(mContext).appendPath("forever").build();
+        when(mContext.getString(com.android.internal.R.string.zen_mode_forever))
+                .thenReturn("testSummary");
+        mController.getContentView();
+
+        // these methods use static calls to ZenModeConfig which would normally fail in robotests,
+        // so instead do nothing:
+        doNothing().when(mController).bindGenericCountdown();
+        doReturn(null).when(mController).getTimeUntilNextAlarmCondition();
+        doReturn(0L).when(mController).getNextAlarm();
+        doNothing().when(mController).bindNextAlarm(any());
+
+        // as a result of doing nothing above, must bind manually:
+        Uri alarm =  Condition.newId(mContext).appendPath("alarm").build();
+        mAlarmCondition = new Condition(alarm, "alarm", "", "", 0, 0, 0);
+        Uri countdown =  Condition.newId(mContext).appendPath("countdown").build();
+        mCountdownCondition = new Condition(countdown, "countdown", "", "", 0, 0, 0);
+        mController.bind(mCountdownCondition,
+                mController.mZenRadioGroupContent.getChildAt(
+                        EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX),
+                EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX);
+        mController.bind(mAlarmCondition,
+                mController.mZenRadioGroupContent.getChildAt(
+                        EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX),
+                EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX);
+    }
+
+    @Test
+    public void testForeverChecked() {
+        mController.bindConditions(mController.forever());
+
+        assertTrue(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(
+                EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
+    }
+
+    @Test
+    public void testNoneChecked() {
+        mController.bindConditions(null);
+        assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(
+                EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
+    }
+
+    @Test
+    public void testAlarmChecked() {
+        doReturn(false).when(mController).isCountdown(mAlarmCondition);
+        doReturn(true).when(mController).isAlarm(mAlarmCondition);
+
+        mController.bindConditions(mAlarmCondition);
+        assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
+                .isChecked());
+        assertTrue(mController.getConditionTagAt(
+                EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
+    }
+
+    @Test
+    public void testCountdownChecked() {
+        doReturn(false).when(mController).isAlarm(mCountdownCondition);
+        doReturn(true).when(mController).isCountdown(mCountdownCondition);
+
+        mController.bindConditions(mCountdownCondition);
+        assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
+                .isChecked());
+        assertTrue(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
+                .isChecked());
+        assertFalse(mController.getConditionTagAt(
+                EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
new file mode 100644
index 0000000..c8b3269
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -0,0 +1,56 @@
+/*
+ * 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.settingslib.testutils.shadow;
+
+import android.content.Context;
+import android.os.UserManager;
+
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+import org.robolectric.shadow.api.Shadow;
+
+@Implements(UserManager.class)
+public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
+
+    private boolean mAdminUser;
+
+    public void setIsAdminUser(boolean isAdminUser) {
+        mAdminUser = isAdminUser;
+    }
+
+    @Resetter
+    public void reset() {
+        mAdminUser = false;
+    }
+
+    @Implementation
+    public boolean isAdminUser() {
+        return mAdminUser;
+    }
+
+    @Implementation
+    public static UserManager get(Context context) {
+        return (UserManager) context.getSystemService(Context.USER_SERVICE);
+    }
+
+    public static ShadowUserManager getShadow() {
+        return (ShadowUserManager) Shadow.extract(
+                RuntimeEnvironment.application.getSystemService(UserManager.class));
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
new file mode 100644
index 0000000..f93210f
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.settingslib.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import com.android.settingslib.R;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.utils.PowerUtil;
+import java.time.Duration;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class PowerUtilTest {
+    public static final String TEST_BATTERY_LEVEL_10 = "10%";
+    public static final String FIFTEEN_MIN_FORMATTED = "15m";
+    public static final long SEVENTEEN_MIN_MILLIS = Duration.ofMinutes(17).toMillis();
+    public static final long FIVE_MINUTES_MILLIS = Duration.ofMinutes(5).toMillis();
+    public static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis();
+    public static final long TWO_DAYS_MILLIS = Duration.ofDays(2).toMillis();
+    public static final String ONE_DAY_FORMATTED = "1 day";
+
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+    }
+
+    @Test
+    public void testGetBatteryRemainingStringFormatted_moreThanFifteenMinutes_withPercentage() {
+        String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                SEVENTEEN_MIN_MILLIS,
+                TEST_BATTERY_LEVEL_10,
+                true /* basedOnUsage */);
+        String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                SEVENTEEN_MIN_MILLIS,
+                TEST_BATTERY_LEVEL_10,
+                false /* basedOnUsage */);
+
+        // We only add special mention for the long string
+        assertThat(info).isEqualTo(mContext.getString(
+                R.string.power_discharging_duration_enhanced,
+                TEST_BATTERY_LEVEL_10,
+                FIFTEEN_MIN_FORMATTED));
+        // shortened string should not have extra text
+        assertThat(info2).isEqualTo(mContext.getString(
+                R.string.power_discharging_duration,
+                TEST_BATTERY_LEVEL_10,
+                FIFTEEN_MIN_FORMATTED));
+    }
+
+    @Test
+    public void testGetBatteryRemainingStringFormatted_moreThanFifteenMinutes_noPercentage() {
+        String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                SEVENTEEN_MIN_MILLIS,
+                null /* percentageString */,
+                true /* basedOnUsage */);
+        String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                SEVENTEEN_MIN_MILLIS,
+                null /* percentageString */,
+                false /* basedOnUsage */);
+
+        // We only add special mention for the long string
+        assertThat(info).isEqualTo(mContext.getString(
+                R.string.power_remaining_duration_only_enhanced,
+                FIFTEEN_MIN_FORMATTED));
+        // shortened string should not have extra text
+        assertThat(info2).isEqualTo(mContext.getString(
+                R.string.power_remaining_duration_only,
+                FIFTEEN_MIN_FORMATTED));
+    }
+
+
+    @Test
+    public void testGetBatteryRemainingStringFormatted_lessThanSevenMinutes_usesCorrectString() {
+        String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                FIVE_MINUTES_MILLIS,
+                TEST_BATTERY_LEVEL_10 /* percentageString */,
+                true /* basedOnUsage */);
+        String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                FIVE_MINUTES_MILLIS,
+                null /* percentageString */,
+                true /* basedOnUsage */);
+
+        // additional battery percentage in this string
+        assertThat(info).isEqualTo(mContext.getString(
+                R.string.power_remaining_duration_shutdown_imminent,
+                TEST_BATTERY_LEVEL_10));
+        // shortened string should not have percentage
+        assertThat(info2).isEqualTo(mContext.getString(
+                R.string.power_remaining_duration_only_shutdown_imminent));
+    }
+
+    @Test
+    public void testGetBatteryRemainingStringFormatted_betweenSevenAndFifteenMinutes_usesCorrectString() {
+        String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                TEN_MINUTES_MILLIS,
+                null /* percentageString */,
+                true /* basedOnUsage */);
+        String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                TEN_MINUTES_MILLIS,
+                TEST_BATTERY_LEVEL_10 /* percentageString */,
+                true /* basedOnUsage */);
+
+        // shortened string should not have percentage
+        assertThat(info).isEqualTo(mContext.getString(
+                R.string.power_remaining_less_than_duration_only,
+                FIFTEEN_MIN_FORMATTED));
+        // Add percentage to string when provided
+        assertThat(info2).isEqualTo(mContext.getString(
+                R.string.power_remaining_less_than_duration,
+                TEST_BATTERY_LEVEL_10,
+                FIFTEEN_MIN_FORMATTED));
+    }
+
+    @Test
+    public void testGetBatteryRemainingStringFormatted_moreThanOneDay_usesCorrectString() {
+        String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                TWO_DAYS_MILLIS,
+                null /* percentageString */,
+                true /* basedOnUsage */);
+        String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+                TWO_DAYS_MILLIS,
+                TEST_BATTERY_LEVEL_10 /* percentageString */,
+                true /* basedOnUsage */);
+
+        // shortened string should not have percentage
+        assertThat(info).isEqualTo(mContext.getString(
+                R.string.power_remaining_only_more_than_subtext,
+                ONE_DAY_FORMATTED));
+        // Add percentage to string when provided
+        assertThat(info2).isEqualTo(mContext.getString(
+                R.string.power_remaining_more_than_subtext,
+                TEST_BATTERY_LEVEL_10,
+                ONE_DAY_FORMATTED));
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
new file mode 100644
index 0000000..d5e3cdb
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
@@ -0,0 +1,213 @@
+/*
+ * 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.settingslib.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.text.SpannableStringBuilder;
+import android.text.format.DateUtils;
+import android.text.style.TtsSpan;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class StringUtilTest {
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = spy(RuntimeEnvironment.application);
+    }
+
+    @Test
+    public void testFormatElapsedTime_WithSeconds_ShowSeconds() {
+        final double testMillis = 5 * DateUtils.MINUTE_IN_MILLIS + 30 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "5m 30s";
+
+        assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true).toString())
+                .isEqualTo(expectedTime);
+    }
+
+    @Test
+    public void testFormatElapsedTime_NoSeconds_DoNotShowSeconds() {
+        final double testMillis = 5 * DateUtils.MINUTE_IN_MILLIS + 30 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "6m";
+
+        assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+                .isEqualTo(expectedTime);
+    }
+
+    @Test
+    public void testFormatElapsedTime_TimeMoreThanOneDay_ShowCorrectly() {
+        final double testMillis = 2 * DateUtils.DAY_IN_MILLIS
+                + 4 * DateUtils.HOUR_IN_MILLIS + 15 * DateUtils.MINUTE_IN_MILLIS;
+        final String expectedTime = "2d 4h 15m";
+
+        assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+                .isEqualTo(expectedTime);
+    }
+
+    @Test
+    public void testFormatElapsedTime_ZeroFieldsInTheMiddleDontShow() {
+        final double testMillis = 2 * DateUtils.DAY_IN_MILLIS + 15 * DateUtils.MINUTE_IN_MILLIS;
+        final String expectedTime = "2d 15m";
+
+        assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+                .isEqualTo(expectedTime);
+    }
+
+    @Test
+    public void testFormatElapsedTime_FormatZero_WithSeconds() {
+        final double testMillis = 0;
+        final String expectedTime = "0s";
+
+        assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true).toString())
+                .isEqualTo(expectedTime);
+    }
+
+    @Test
+    public void testFormatElapsedTime_FormatZero_NoSeconds() {
+        final double testMillis = 0;
+        final String expectedTime = "0m";
+
+        assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+                .isEqualTo(expectedTime);
+    }
+
+    @Test
+    public void testFormatElapsedTime_onlyContainsMinute_hasTtsSpan() {
+        final double testMillis = 15 * DateUtils.MINUTE_IN_MILLIS;
+
+        final CharSequence charSequence =
+                StringUtil.formatElapsedTime(mContext, testMillis, false);
+        assertThat(charSequence).isInstanceOf(SpannableStringBuilder.class);
+
+        final SpannableStringBuilder expectedString = (SpannableStringBuilder) charSequence;
+        final TtsSpan[] ttsSpans = expectedString.getSpans(0, expectedString.length(),
+                TtsSpan.class);
+
+        assertThat(ttsSpans).asList().hasSize(1);
+        assertThat(ttsSpans[0].getType()).isEqualTo(TtsSpan.TYPE_MEASURE);
+    }
+
+    @Test
+    public void testFormatRelativeTime_WithSeconds_ShowSeconds() {
+        final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "40 sec. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_NoSeconds_DoNotShowSeconds() {
+        final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "1 min. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_LessThanTwoMinutes_withSeconds() {
+        final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "119 sec. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_LessThanTwoMinutes_NoSeconds() {
+        final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "2 min. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_TwoMinutes_withSeconds() {
+        final double testMillis = 2 * DateUtils.MINUTE_IN_MILLIS;
+        final String expectedTime = "2 min. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_LessThanTwoHours_withSeconds() {
+        final double testMillis = 119 * DateUtils.MINUTE_IN_MILLIS;
+        final String expectedTime = "119 min. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_TwoHours_withSeconds() {
+        final double testMillis = 2 * DateUtils.HOUR_IN_MILLIS;
+        final String expectedTime = "2 hr. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_LessThanTwoDays_withSeconds() {
+        final double testMillis = 47 * DateUtils.HOUR_IN_MILLIS;
+        final String expectedTime = "47 hr. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_TwoDays_withSeconds() {
+        final double testMillis = 2 * DateUtils.DAY_IN_MILLIS;
+        final String expectedTime = "2 days ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_FormatZero_WithSeconds() {
+        final double testMillis = 0;
+        final String expectedTime = "0 sec. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_FormatZero_NoSeconds() {
+        final double testMillis = 0;
+        final String expectedTime = "0 min. ago";
+
+        assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
+                expectedTime);
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 1dc8e46..cfcfb95 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -43,7 +43,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.ims.ImsConfig;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
@@ -1504,7 +1503,7 @@
                 try {
                     stmt = db.compileStatement("INSERT OR REPLACE INTO global(name,value)"
                             + " VALUES(?,?);");
-                    loadStringSetting(stmt, Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
+                    loadStringSetting(stmt, Settings.Global.CHARGING_STARTED_SOUND,
                             R.string.def_wireless_charging_started_sound);
                     db.setTransactionSuccessful();
                 } finally {
@@ -2578,7 +2577,7 @@
                     R.string.def_car_dock_sound);
             loadStringSetting(stmt, Settings.Global.CAR_UNDOCK_SOUND,
                     R.string.def_car_undock_sound);
-            loadStringSetting(stmt, Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
+            loadStringSetting(stmt, Settings.Global.CHARGING_STARTED_SOUND,
                     R.string.def_wireless_charging_started_sound);
 
             loadIntegerSetting(stmt, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 537e8dc..1551b8e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -160,7 +160,7 @@
                 Settings.Global.POWER_SOUNDS_ENABLED,
                 GlobalSettingsProto.POWER_SOUNDS_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
+                Settings.Global.CHARGING_STARTED_SOUND,
                 GlobalSettingsProto.WIRELESS_CHARGING_STARTED_SOUND);
         dumpSetting(s, p,
                 Settings.Global.CHARGING_SOUNDS_ENABLED,
@@ -1112,8 +1112,8 @@
                 Settings.Global.ZRAM_ENABLED,
                 GlobalSettingsProto.ZRAM_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS,
-                GlobalSettingsProto.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS);
+                Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
+                GlobalSettingsProto.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS);
         dumpSetting(s, p,
                 Settings.Global.SHOW_FIRST_CRASH_DIALOG,
                 GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index adb4dbf..85a579d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3017,7 +3017,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 153;
+            private static final int SETTINGS_VERSION = 154;
 
             private final int mUserId;
 
@@ -3627,6 +3627,23 @@
                     currentVersion = 153;
                 }
 
+                if (currentVersion == 153) {
+                    // Version 154: Read notification badge configuration from config.
+                    // If user has already set the value, don't do anything.
+                    final SettingsState systemSecureSettings = getSecureSettingsLocked(userId);
+                    final Setting showNotificationBadges = systemSecureSettings.getSettingLocked(
+                            Settings.Secure.NOTIFICATION_BADGING);
+                    if (showNotificationBadges.isNull()) {
+                        final boolean defaultValue = getContext().getResources().getBoolean(
+                                com.android.internal.R.bool.config_notificationBadging);
+                        systemSecureSettings.insertSettingLocked(
+                                Secure.NOTIFICATION_BADGING,
+                                defaultValue ? "1" : "0",
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    currentVersion = 154;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 64b2ae6..5c8d745 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -138,6 +138,11 @@
     <uses-permission android:name="android.permission.MANAGE_SENSORS" />
     <uses-permission android:name="android.permission.MANAGE_AUDIO_POLICY" />
     <uses-permission android:name="android.permission.MANAGE_CAMERA" />
+    <!-- Permission needed to enable/disable Bluetooth/Wifi when on permission review mode -->
+    <uses-permission
+        android:name="android.permission.MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED" />
+    <uses-permission
+        android:name="android.permission.MANAGE_WIFI_WHEN_PERMISSION_REVIEW_REQUIRED" />
 
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 2bcf4ef..1e48213 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -56,7 +56,6 @@
     SystemUI-proto
 
 LOCAL_JAVA_LIBRARIES := telephony-common
-LOCAL_JAVA_LIBRARIES += android.car
 
 LOCAL_PACKAGE_NAME := SystemUI
 LOCAL_CERTIFICATE := platform
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 9613a6a..cbb3e8f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -176,9 +176,6 @@
     <!-- It's like, reality, but, you know, virtual -->
     <uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
 
-    <!-- To control car audio module volume -->
-    <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
-
     <!-- the ability to rename notifications posted by other apps -->
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
 
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
new file mode 100644
index 0000000..af6dd77
--- /dev/null
+++ b/packages/SystemUI/OWNERS
@@ -0,0 +1,20 @@
+set noparent
+
+dsandler@google.com
+
+asc@google.com
+ashaikh@google.com
+beverlyt@google.com
+cinek@google.com
+cwren@google.com
+evanlaird@google.com
+jmonk@google.com
+jaggies@google.com
+jjaggi@google.com
+juliacr@google.com
+dupin@google.com
+madym@google.com
+roosa@google.com
+shahrk@google.com
+winsonc@google.com
+
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index bf0d679..3f5f76f 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Volgende wekker gestel vir <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Vee uit"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Deaktiveer e-SIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Kan nie e-SIM deaktiveer nie"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Die e-SIM kan weens \'n fout nie gedeaktiveer word nie."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Het jy die patroon vergeet?"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Verkeerde patroon"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Teken jou patroon"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Voer SIM se PIN in."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Voer SIM se PIN vir \"<xliff:g id="CARRIER">%1$s</xliff:g>\" in."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Deaktiveer e-SIM om toestel sonder mobiele diens te gebruik."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Deaktiveer e-SIM om toestel sonder mobiele diens te gebruik."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Voer PIN in"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Voer wagwoord in"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Kontak diensverskaffer vir besonderhede."</string>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 340e514..1cd862d 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"ቀጣዩ ማንቂያ ለ<xliff:g id="ALARM">%1$s</xliff:g> ተዘጋጅቷል"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"ሰርዝ"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIMን አሰናክል"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"eSIMን ማሰናከል አልተቻለም"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"በአንድ ስህተት ምክንያት eSIM ሊሰናከል አልቻለም።"</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"አስገባ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"ስርዓተ ጥለቱን እርሳ"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"የተሳሳተ ስርዓተ ጥለት"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"ስርዓተ ጥለትዎን ይሳሉ"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"የሲም ፒን ያስገቡ።"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"የ«<xliff:g id="CARRIER">%1$s</xliff:g>» ሲም ፒን ያስገቡ።"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"መሣሪያን ያለተንቀሳቃሽ ስልክ አገልግሎት ለመጠቀም eSIMን ያሰናክሉ።"</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> መሣሪያን ያለሞባይል አገልግሎት ለመጠቀም eSIMን ያሰናክሉ።"</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"ፒን ያስገቡ"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"የይለፍ ቃል ያስገቡ"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"ሲም አሁን ተሰናክሏል። ለመቀጠል የፒዩኬ ኮድ ያስገቡ። ለዝርዝር አገልግሎት አቅራቢን ያግኙ።"</string>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index b0503ea..3ab93c5 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Növbəti zəng vaxtı: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Silin"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSİM\'i deaktiv edin"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"eSIM-i deaktiv etmək alınmadı"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"eSIM xəta səbəbi ilə deaktiv edilmədi."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Daxil edin"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Modeli unutmuşam"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Yanlış Model"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Modeli çəkin"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"SIM PIN\'ni daxil edin."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" üçün SIM PIN\'ni daxil edin."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Mobil xidmət olmadan cihazı istifadə etmək üçün eSIM\'i deaktiv edin."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Mobil xidmət olmadan cihazı istifadə etmək üçün eSIM-i deaktiv edin."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"PIN daxil edin"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Parol daxil edin"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM indi deaktivdir. Davam etmək üçün PUK kod daxil edin. Ətraflı məlumat üçün operatorla əlaqə saxlayın."</string>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 791f5e9..81c56da 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"পরবর্তী অ্যালার্ম <xliff:g id="ALARM">%1$s</xliff:g> এ সেট করা হয়েছে"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"মুছুন"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"ই-সিমটি অক্ষম করুন"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"এন্টার"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"প্যাটার্ন ভুলে গেছি"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"ভুল প্যাটার্ন"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"আপনার প্যাটার্ন আঁকুন"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"সিমের পিন লিখুন।"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" এর জন্য সিমের পিন লিখুন।"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"মোবাইল পরিষেবা ছাড়াই ডিভাইস ব্যবহার করতে ই-সিম অক্ষম করুন।"</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"পিন লিখুন"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"পাসওয়ার্ড লিখুন"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"সিমটি এখন অক্ষম করা হয়েছে। চালিয়ে যেতে PUK কোডটি লিখুন। বিশদ বিবরণের জন্য পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 1f6addf..6ff819c 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -53,6 +53,10 @@
     <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>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Zaboravili ste uzorak?"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Pogrešan uzorak"</string>
@@ -66,7 +70,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Nacrtajte uzorak"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Unesite PIN SIM kartice."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Unesite PIN SIM kartice operatera \"<xliff:g id="CARRIER">%1$s</xliff:g>\""</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Onemogućite eSIM karticu za korištenje uređaja bez mobilne usluge."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Unesite PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Unesite lozinku"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM kartica je sada onemogućena. Unesite PUK kôd da nastavite. Za više informacija obratite se operateru."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index dd2844a..511516e 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"S\'ha definit la pròxima alarma per a l\'hora següent: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Suprimeix"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Desactiva l\'eSIM"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Retorn"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"He oblidat el patró"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"El patró no és correcte"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Dibuixa el patró"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Introdueix el PIN de la SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Introdueix el PIN de la SIM de: <xliff:g id="CARRIER">%1$s</xliff:g>."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Desactiva l\'eSIM per utilitzar el dispositiu sense servei mòbil."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Introdueix el PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Introdueix la contrasenya"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"La SIM està desactivada. Introdueix el codi PUK per continuar. Contacta amb l\'operador de telefonia mòbil per obtenir més informació."</string>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index cf7abf1..d5f80cb 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Další budík je nastaven na <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Smazat"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Deaktivovat eSIM kartu"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Nelze deaktivovat eSIM kartu"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"eSIM kartu kvůli chybě nelze deaktivovat."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Zapomenuté gesto"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Nesprávné gesto"</string>
@@ -67,7 +69,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Zadejte gesto"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Zadejte kód PIN SIM karty."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Zadejte kód PIN SIM karty <xliff:g id="CARRIER">%1$s</xliff:g>."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"eSIM kartu deaktivujte, chcete-li telefon používat bez mobilních služeb."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> eSIM kartu deaktivujte, chcete-li zařízení používat bez mobilních služeb."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Zadejte kód PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Zadejte heslo"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM karta byla zablokována. Chcete-li pokračovat, je třeba zadat kód PUK. Podrobné informace získáte od operátora."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index b6dc72b..57b98fa 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Next alarm set for <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Delete"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Disable eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Can’t disable eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"The eSIM can’t be disabled due to an error."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Forgotten Pattern"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Wrong Pattern"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Draw your pattern"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Enter SIM PIN."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Enter SIM PIN for \'<xliff:g id="CARRIER">%1$s</xliff:g>\'."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Disable eSIM to use device without mobile service."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Enter PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Enter Password"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index b6dc72b..57b98fa 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Next alarm set for <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Delete"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Disable eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Can’t disable eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"The eSIM can’t be disabled due to an error."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Forgotten Pattern"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Wrong Pattern"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Draw your pattern"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Enter SIM PIN."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Enter SIM PIN for \'<xliff:g id="CARRIER">%1$s</xliff:g>\'."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Disable eSIM to use device without mobile service."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Enter PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Enter Password"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index b6dc72b..57b98fa 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Next alarm set for <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Delete"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Disable eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Can’t disable eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"The eSIM can’t be disabled due to an error."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Forgotten Pattern"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Wrong Pattern"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Draw your pattern"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Enter SIM PIN."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Enter SIM PIN for \'<xliff:g id="CARRIER">%1$s</xliff:g>\'."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Disable eSIM to use device without mobile service."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Enter PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Enter Password"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index b6dc72b..57b98fa 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Next alarm set for <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Delete"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Disable eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Can’t disable eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"The eSIM can’t be disabled due to an error."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Forgotten Pattern"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Wrong Pattern"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Draw your pattern"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Enter SIM PIN."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Enter SIM PIN for \'<xliff:g id="CARRIER">%1$s</xliff:g>\'."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Disable eSIM to use device without mobile service."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disable eSIM to use device without mobile service."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Enter PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Enter Password"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM is now disabled. Enter PUK code to continue. Contact carrier for details."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
index 97d16c6..d27d204 100644
--- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎Next alarm set for ‎‏‎‎‏‏‎<xliff:g id="ALARM">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‏‏‏‎‎Delete‎‏‎‎‏‎"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎Disable eSIM‎‏‎‎‏‎"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‎‏‏‎‎Can’t disable eSIM‎‏‎‎‏‎"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‏‏‎The eSIM can’t be disabled due to an error.‎‏‎‎‏‎"</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎Enter‎‏‎‎‏‎"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎Forgot Pattern‎‏‎‎‏‎"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎Wrong Pattern‎‏‎‎‏‎"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‎‎Draw your pattern‎‏‎‎‏‎"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‎‎‏‏‎Enter SIM PIN.‎‏‎‎‏‎"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎‏‎Enter SIM PIN for \"‎‏‎‎‏‏‎<xliff:g id="CARRIER">%1$s</xliff:g>‎‏‎‎‏‏‏‎\".‎‏‎‎‏‎"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎Disable eSIM to use device without mobile service.‎‏‎‎‏‎"</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g>‎‏‎‎‏‏‏‎ Disable eSIM to use device without mobile service.‎‏‎‎‏‎"</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎Enter PIN‎‏‎‎‏‎"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‎‎Enter Password‎‏‎‎‏‎"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎SIM is now disabled. Enter PUK code to continue. Contact carrier for details.‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index ec36fd7..780d8d4 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Próxima alarma: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Eliminar"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Inhabilita la tarjeta eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"No se puede inhabilitar la tarjeta eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"No se puede mostrar la tarjeta eSIM debido a un error."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Intro"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"¿Has olvidado el patrón?"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Patrón incorrecto"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Dibuja tu patrón"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Introduce el PIN de la tarjeta SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Introduce el PIN de la tarjeta SIM de <xliff:g id="CARRIER">%1$s</xliff:g>."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Inhabilita la tarjeta eSIM para utilizar el dispositivo sin servicio móvil."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Inhabilita la tarjeta eSIM para usar el dispositivo sin servicio móvil."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Introduce el PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Introduce tu contraseña"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"La tarjeta SIM está inhabilitada. Para continuar, introduce el código PUK. Si quieres obtener más información, ponte en contacto con el operador."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 2b14e3c..44aab01 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Seuraava hälytys asetettu: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Poista"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Poista eSIM käytöstä"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"eSIMiä ei voi poistaa käytöstä"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Tapahtui virhe, eikä eSIMiä voitu poistaa käytöstä."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Unohtunut kuvio"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Väärä kuvio"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Piirrä kuvio"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Anna SIM-kortin PIN-koodi."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Anna operaattorin <xliff:g id="CARRIER">%1$s</xliff:g> SIM-kortin PIN-koodi."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Poista eSIM käytöstä, jos haluat käyttää laitetta ilman mobiilipalvelua."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Poista eSIM käytöstä, jos haluat käyttää laitetta ilman mobiililiittymää."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Anna PIN-koodi."</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Anna salasana"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM-kortti on nyt poistettu käytöstä. Jatka antamalla PUK-koodi. Saat lisätietoja ottamalla yhteyttä operaattoriin."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index b033311..e0b14b9 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Heure de la prochaine alarme : <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Supprimer"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Désactiver la carte eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Impossible de désactiver la carte eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"La carte eSIM ne peut pas être réinitialisée à cause d\'une erreur."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Entrée"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"J\'ai oublié le schéma"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Schéma incorrect"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Dessinez votre schéma"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Entrez le NIP de la carte SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Entrez le NIP de la carte SIM pour « <xliff:g id="CARRIER">%1$s</xliff:g> »."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Désactivez la carte eSIM pour utiliser l\'appareil sans service cellulaire."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Désactivez la carte eSIM pour utiliser l\'appareil sans service cellulaire."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Entrez le NIP"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Entrez votre mot de passe."</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Pour obtenir plus de détails, communiquez avec votre fournisseur de services."</string>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index c62bab8..d2e6c02 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"<xliff:g id="ALARM">%1$s</xliff:g> માટે આગલું એલાર્મ સેટ કર્યું"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"કાઢી નાખો"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIMને અક્ષમ કરો"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"દાખલ કરો"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"પૅટર્ન ભૂલી ગયાં"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"ખોટી પૅટર્ન"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"તમારી પૅટર્ન દોરો"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"સિમ પિન દાખલ કરો"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" માટે સિમ પિન દાખલ કરો."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"મોબાઇલ સેવા વગર ઉપકરણનો ઉપયોગ કરવા eSIMને અક્ષમ કરો."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"પિન દાખલ કરો"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"પાસવર્ડ દાખલ કરો"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"સિમ હમણાં અક્ષમ કરેલ છે. ચાલુ રાખવા માટે PUK કોડ દાખલ કરો. વિગતો માટે કૅરિઅરનો સંપર્ક કરો."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 641c072..dfd06b2 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"अगला अलार्म <xliff:g id="ALARM">%1$s</xliff:g> बजे के लिए सेट किया गया है"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"मिटाएं"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM अक्षम करें"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"पैटर्न भूल गए हैं"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"गलत पैटर्न"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"अपना पैटर्न बनाएं"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"सिम पिन डालें."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" के लिए सिम पिन डालें"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"मोबाइल सेवा के बिना डिवाइस का उपयोग करने के लिए eSIM अक्षम करें."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"पिन डालें"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"पासवर्ड डालें"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"सिम अब काम नहीं करेगा. जारी रखने के लिए PUK कोड डालें. ज़्यादा जानकारी के लिए अपनी मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करें."</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 813377a..96bcb10 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Prossima sveglia impostata a: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Elimina"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Disattiva eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Impossibile disattivare la eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Impossibile disattivare la eSIM a causa di un errore."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Invio"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Sequenza dimenticata"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Sequenza sbagliata"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Inserisci la sequenza"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Inserisci il PIN della SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Inserisci il PIN della SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Disattiva l\'eSIM per usare il dispositivo senza servizio dati mobile."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Disattiva la eSIM per usare il dispositivo senza servizio dati mobile."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Inserisci PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Inserisci la password"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"La scheda SIM è disattivata. Inserisci il codice PUK per continuare. Contatta l\'operatore per avere informazioni dettagliate."</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 2c29112..690ce65 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"<xliff:g id="ALARM">%1$s</xliff:g> ಗಂಟೆಗೆ ಮುಂದಿನ ಅಲಾರಮ್ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"ಅಳಿಸಿ"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"ನಮೂದಿಸಿ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"ಪ್ಯಾಟರ್ನ್ ಮರೆತಿದ್ದೀರಿ"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"ಪ್ಯಾಟರ್ನ್ ತಪ್ಪಾಗಿದೆ"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"ನಿಮ್ಮ ಪ್ಯಾಟರ್ನ್ ಚಿತ್ರಿಸಿ"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"ಸಿಮ್‌ ಪಿನ್‌ ನಮೂದಿಸಿ."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" ಗಾಗಿ ಸಿಮ್ ಪಿನ್ ನಮೂದಿಸಿ."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"ಮೊಬೈಲ್ ಸೇವೆ ಇಲ್ಲದೆಯೇ ಸಾಧನವನ್ನು ಬಳಸಲು eSIM ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"ಪಿನ್‌ ನಮೂದಿಸಿ"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"ಪಾಸ್‌ವರ್ಡ್ ನಮೂದಿಸಿ"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"ಈಗ ಸಿಮ್‌ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ. ಮುಂದುವರೆಯಲು PUK ಕೋಡ್ ನಮೂದಿಸಿ. ವಿವರಗಳಿಗಾಗಿ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 545d32a..10a81d0 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"ໂມງປຸກຕໍ່ໄປຖືກຕັ້ງໄວ້ເວລາ <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"ລຶບ"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"ປິດການໃຊ້ eSIM ແລ້ວ"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"ປ້ອນເຂົ້າ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"ລືມຮູບແບບປົດລັອກ?"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"ຮູບແບບຜິດ"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"ແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານ"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"ໃສ່ລະຫັດ PIN ຂອງຊິມ."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"ໃສ່ລະຫັດ PIN ຂອງຊິມສຳລັບ \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"ປິດການໃຊ້ eSIM ເພື່ອໃຊ້ອຸປະກອນໂດຍບໍ່ມີບໍລິການມືຖື."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"ໃສ່ລະຫັດ PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"ໃສ່ລະຫັດຜ່ານ"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"ຊິມຖືກປິດການນຳໃຊ້ແລ້ວ. ປ້ອນລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ຕິດຕໍ່ຜູ່ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 0951787..d060ff4 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Следниот аларм е поставен во <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Избриши"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Оневозможи ја eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Не може да се оневозможи eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"eSIM-картичката не може да се оневозможи поради грешка."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Внеси"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Ја заборавивте шемата?"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Погрешна шема"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Нацртајте ја шемата"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Внесете PIN на SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Внесете PIN на SIM за „<xliff:g id="CARRIER">%1$s</xliff:g>“."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Оневозможете ја eSIM за да го користите уредот без мобилна услуга."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Оневозможете ја eSIM-картичката за да го користите уредот без мобилна услуга."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Внесете PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Внесете лозинка"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM-картичката сега е оневозможена. Внесете PUK-код за да продолжите. Контактирајте со операторот за детали."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index d62537d..7e12a22 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"അടുത്ത അലാറം <xliff:g id="ALARM">%1$s</xliff:g>-ന് സജ്ജീകരിച്ചു"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"ഇല്ലാതാക്കുക"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM പ്രവർത്തനരഹിതമാക്കുക"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"എന്റർ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"പാറ്റേൺ മറന്നു"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"പാറ്റേൺ തെറ്റാണ്"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"നിങ്ങളുടെ പാറ്റേൺ വരയ്‌ക്കുക"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"സിം പിൻ നൽകുക."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" എന്ന കാരിയർക്കുള്ള സിം പിൻ നൽകുക."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"മൊ‌ബൈൽ സേവനമില്ലാതെ ഉപകരണം ഉപയോഗിക്കാൻ eSIM പ്രവർത്തനരഹിതമാക്കുക."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"പിൻ നൽകുക"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"പാസ്‌വേഡ് നൽകുക"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"സിം ഇപ്പോൾ പ്രവർത്തനരഹിതമാക്കി. തുടരുന്നതിന് PUK കോഡ് നൽകുക. വിശദാംശങ്ങൾക്ക് കാരിയറെ ബന്ധപ്പെടുക."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 7d04edc..daa40c6 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"पुढील अलार्म <xliff:g id="ALARM">%1$s</xliff:g> साठी सेट केला"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"हटवा"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM बंद करा"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"एंटर करा"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"पॅटर्न विसरलात"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"चुकीचा पॅटर्न"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"तुमचा पॅटर्न काढा"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"सिम पिन एंटर करा"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" साठी सिम पिन एंटर करा"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"मोबाइल सेवांशिवाय डिव्हाइस वापरण्यासाठी eSIM बंद करा."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"पिन एंटर करा"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"पासवर्ड एंटर करा"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड एंटर करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index fb85589..a7236cf 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"နောက်နှိုးစက်အချိန်ကို <xliff:g id="ALARM">%1$s</xliff:g> တွင် သတ်မှတ်ထားပါသည်"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"ဖျက်ရန်"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM ကို ပိတ်ရန်"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"eSIM ကို ပိတ်၍မရခြင်း"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"အမှားအယွင်းရှိနေသောကြောင့် eSIM ကို ပိတ်၍မရပါ။"</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter ခလုတ်"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"ပုံစံအား မေ့သွားပါသည်"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"ပုံစံ မမှန်ကန်ပါ"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"ပုံစံကို ဆွဲပါ"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"ဆင်းမ်ကဒ် ပင်နံပါတ်ကို ထည့်ပါ။"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" အတွက် ဆင်းမ်ကဒ်ပင်နံပါတ်ကို ထည့်ပါ။"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"စက်ပစ္စည်းကို မိုဘိုင်းဝန်ဆောင်မှုမပါဘဲ အသုံးပြုရန် eSIM ကို ပိတ်ပါ။"</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> မိုဘိုင်းဝန်ဆောင်မှု မရှိဘဲ စက်ပစ္စည်းကို အသုံးပြုရန် eSIM ကို ပိတ်ပါ။"</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"ပင်နံပါတ်ကို ထည့်ပါ"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"စကားဝှက်ကို ထည့်ပါ"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ်ကို ထည့်ပါ။ ပိုမိုလေ့လာရန် မိုဘိုင်းဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်နိုင်ပါသည်။"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index ca51c96..2c0e3d6 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Neste alarm er stilt inn for <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Slett"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Deaktiver e-SIM-kortet"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Har du glemt mønsteret?"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Feil mønster"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Tegn mønsteret ditt"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Skriv inn PIN-koden for SIM-kortet."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Skriv inn PIN-koden for SIM-kortet «<xliff:g id="CARRIER">%1$s</xliff:g>»."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Deaktiver e-SIM-kortet for å bruke enheten uten mobiltjeneste."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Skriv inn PIN-koden"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Skriv inn passordet"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM-kortet er nå deaktivert. Skriv inn PUK-koden for å fortsette. Ta kontakt med operatøren for mer informasjon."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 90d6c5cfc..dcb309f 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"अर्को अलार्म <xliff:g id="ALARM">%1$s</xliff:g> का लागि सेट गरियो"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"मेट्नुहोस्"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM लाई असक्षम पार्नुहोस्"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"प्रविष्टि गर्नुहोस्"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"ढाँचा बिर्सनुभयो"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"गलत ढाँचा"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"आफ्नो ढाँचा कोर्नुहोस्"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"SIM को PIN प्रविष्टि गर्नुहोस्।"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" को SIM को PIN प्रविष्ट गर्नुहोस्।"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"मोबाइल सेवा बिना यन्त्रको प्रयोग गर्न eSIM लाई असक्षम पार्नुहोस्।"</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"PIN प्रविष्टि गर्नुहोस्"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"पासवर्ड प्रविष्ट गर्नुहोस्"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM कार्ड अहिले असक्षम छ। सुचारु गर्नको लागि PUK कोड प्रविष्ट गर्नुहोस्।  विवरणको लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index d5d27ca..ddb83e9 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"ਅਗਲਾ ਅਲਾਰਮ <xliff:g id="ALARM">%1$s</xliff:g> \'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"ਮਿਟਾਓ"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM ਨੂੰ ਅਯੋਗ ਬਣਾਓ"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"ਦਾਖਲ ਕਰੋ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"ਪੈਟਰਨ ਭੁੱਲ ਗਏ"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"ਗਲਤ ਪੈਟਰਨ"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"ਆਪਣਾ ਪੈਟਰਨ ਉਲੀਕੋ"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"ਸਿਮ ਪਿੰਨ ਦਾਖਲ ਕਰੋ।"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" ਲਈ ਸਿਮ ਪਿੰਨ ਦਾਖਲ ਕਰੋ।"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"ਮੋਬਾਈਲ ਸੇਵਾ ਤੋਂ ਬਿਨਾਂ ਡੀਵਾਈਸ ਨੂੰ ਵਰਤਣ ਲਈ eSIM ਬੰਦ ਕਰੋ।"</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"ਪਿੰਨ ਦਾਖਲ ਕਰੋ"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"ਪਾਸਵਰਡ ਦਾਖਲ ਕਰੋ"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"ਸਿਮ ਹੁਣ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ। ਜਾਰੀ ਰੱਖਣ ਲਈ PUK ਕੋਡ ਦਾਖਲ ਕਰੋ। ਵੇਰਵਿਆਂ ਲਈ ਕੈਰੀਅਰ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index bb547f15..5c02d4f 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Próximo alarme definido para <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Excluir"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Desativar eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Não é possível desativar o eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Não é possível desativar o eSIM devido a um erro."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Inserir"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Esqueci o padrão"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Padrão incorreto"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Desenhe seu padrão"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Informe o PIN do cartão SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Informe o PIN do cartão SIM para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Digite o PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Digite a senha"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"O SIM foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para mais detalhes."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 6a0e627..73f2b7f 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Próximo alarme definido para <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Eliminar"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Desativar eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Não é possível desativar o eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Não é possível desativar o eSIM devido a um erro."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Tecla Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Esqueceu-se do padrão"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Padrão incorreto"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Desenhe o seu padrão"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Introduza o PIN do cartão SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Introduza o PIN do cartão SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Desativar eSIM para utilizar sem serviço móvel"</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para utilizar o dispositivo sem serviço móvel."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Introduza o PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Introduza a palavra-passe"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"O cartão SIM está agora desativado. Introduza o código PUK para continuar. Contacte o operador para obter mais detalhes."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index bb547f15..5c02d4f 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Próximo alarme definido para <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Excluir"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Desativar eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Não é possível desativar o eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Não é possível desativar o eSIM devido a um erro."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Inserir"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Esqueci o padrão"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Padrão incorreto"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Desenhe seu padrão"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Informe o PIN do cartão SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Informe o PIN do cartão SIM para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desative o eSIM para usar o dispositivo sem serviço móvel."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Digite o PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Digite a senha"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"O SIM foi desativado. Insira o código PUK para continuar. Entre em contato com a operadora para mais detalhes."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 341c952..f449701 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Următoarea alarmă este setată pentru <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Ștergeți"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Dezactivați cardul eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Nu se poate dezactiva cardul eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Cardul eSIM nu poate fi dezactivat din cauza unei erori."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Introduceți"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Ați uitat modelul"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Model greșit"</string>
@@ -66,7 +68,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Desenați modelul"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Introduceți codul PIN al cardului SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Introduceți codul PIN al cardului SIM pentru „<xliff:g id="CARRIER">%1$s</xliff:g>”."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Dezactivați cardul eSIM pentru a folosi dispozitivul fără serviciu mobil."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Dezactivați cardul eSIM pentru a folosi dispozitivul fără serviciu mobil."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Introduceți codul PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Introduceți parola"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"Cardul SIM este acum dezactivat. Pentru a continua, introduceți codul PUK. Pentru detalii, contactați operatorul."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index 1a794ee..dbdbf93 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Время следующего сигнала будильника: <xliff:g id="ALARM">%1$s</xliff:g>."</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Удалить"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Отключить eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Произошла ошибка"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Не удалось отключить eSIM."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Клавиша ввода"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Забыли графический ключ?"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Неверный графический ключ"</string>
@@ -67,7 +69,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Введите графический ключ"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Введите PIN-код SIM-карты."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Введите PIN-код SIM-карты \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Чтобы пользоваться устройством без мобильной связи, отключите eSIM."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Чтобы пользоваться устройством без мобильной связи, отключите eSIM."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Введите PIN-код"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Введите пароль"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM-карта отключена. Чтобы продолжить, введите PUK-код. За подробной информацией обратитесь к оператору связи."</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index d36e752..a670f16 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"<xliff:g id="ALARM">%1$s</xliff:g>ට ඊළඟ එලාමය සකසා ඇත"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"මකන්න"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM අබල කරන්න"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"eSIM අබල කළ නොහැකිය."</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"දෝෂයක් හේතුවෙන් eSIM අබල කළ නොහැකිය."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"ඇතුල් කරන්න"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"රටාව අමතකයි"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"වැරදි රටාවකි"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"ඔබගේ රටාව අඳින්න"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"SIM PIN ඇතුළු කරන්න"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" සඳහා SIM PIN ඇතුළු කරන්න"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"ජංගම සේවාවෙන් තොරව උපාංගය භාවිත කිරීමට eSIM අබල කරන්න."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> ජංගම සේවාවෙන් තොරව උපාංගය භාවිත කිරීමට eSIM අබල කරන්න."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"PIN එක ඇතුළු කරන්න"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"මුරපදය ඇතුළු කරන්න"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"දැන් SIM එක අබල කර ඇත. ඉදිරියට යාමට PUK කේතය යොදන්න. විස්තර සඳහා වාහකයා අමතන්න."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 7e85131..06acf81 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Kengele inayofuata italia saa <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Futa"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Zima eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Imeshindwa kuzima eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Hitilafu imetokea wakati wa kuzima eSIM."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Weka"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Umesahau Mchoro"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Mchoro si Sahihi"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Chora mchoro wako"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Weka PIN ya SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Weka PIN ya SIM ya \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Zima eSIM ili utumie kifaa bila huduma ya vifaa vya mkononi."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Zima eSIM ili utumie kifaa bila huduma ya vifaa vya mkononi."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Weka PIN"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Weka Nenosiri"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM sasa imefungwa. Weka nambari ya PUK ili uendelee. Wasiliana na mtoa huduma za mtandao kwa maelezo."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 2ce57a0..376c74f 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"அடுத்த அலாரம் <xliff:g id="ALARM">%1$s</xliff:g>க்கு அமைக்கப்பட்டுள்ளது"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"நீக்கும் பொத்தான்"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"இ-சிம்மை முடக்கும்"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"என்டர் பொத்தான்"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"பேட்டர்ன் நினைவில்லையா"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"தவறான பேட்டர்ன்"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"பேட்டர்னை வரையவும்"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"சிம் பின்னை உள்ளிடவும்."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\"க்கான சிம் பின்னை உள்ளிடவும்."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"மொபைல் சேவை இல்லாமல் சாதனத்தைப் பயன்படுத்த, இ-சிம்மை முடக்கவும்."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"பின்னை உள்ளிடவும்"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"கடவுச்சொல்லை உள்ளிடவும்"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"சிம் தற்போது முடக்கப்பட்டுள்ளது. தொடர, PUK குறியீட்டை உள்ளிடவும். விவரங்களுக்கு, தொலைத்தொடர்பு நிறுவனத்தைத் தொடர்புகொள்ளவும்."</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index bdee4a3..934d6a2 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"తర్వాత అలారం <xliff:g id="ALARM">%1$s</xliff:g>కి సెట్ చేయబడింది"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"తొలగించు"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIMని నిలిపివేయండి"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"నమూనాను మర్చిపోయాను"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"ఆకృతి తప్పు"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"మీ నమూనాను గీయండి"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"SIM పిన్‌ని నమోదు చేయండి."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" కోసం SIM పిన్‌ని నమోదు చేయండి."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"మొబైల్ సేవ లేకుండా డివైజ్‌ని ఉపయోగించడం కోసం eSIMని నిలిపివేయండి."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"పిన్‌ను నమోదు చేయండి"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"పాస్‌వర్డ్‌ని నమోదు చేయండి"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"ఇప్పుడు SIM నిలిపివేయబడింది. కొనసాగించాలంటే, PUK కోడ్‌ను నమోదు చేయండి. వివరాల కోసం క్యారియర్‌ను సంప్రదించండి."</string>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index ca53dfb8..e716ee4 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Sonraki alarm <xliff:g id="ALARM">%1$s</xliff:g> olarak ayarlandı"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Delete"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM\'i devre dışı bırak"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Deseni unuttunuz mu?"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Yanlış Desen"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Deseninizi çizin"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"SIM PIN kodunu girin."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" için SIM PIN kodunu girin."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Cihazı mobil hizmet olmadan kullanmak için eSIM\'i devre dışı bırakın."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"PIN\'i girin"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Şifreyi Girin"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM kart artık devre dışı bırakıldı. Devam etmek için PUK kodunu girin. Ayrıntılı bilgi için operatörle bağlantı kurun."</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 4b79744..277b103 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Наступний сигнал: <xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Видалити"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Вимкнути eSIM-карту"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Не вдається вимкнути eSIM-карту"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"Не вдається вимкнути eSIM-карту через помилку."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Ввести"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Не пам’ятаю ключ"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Неправильний ключ"</string>
@@ -67,7 +69,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Намалюйте ключ"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Введіть PIN-код SIM-карти."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Введіть PIN-код SIM-карти для оператора \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Вимкнути eSIM-карту, щоб використовувати пристрій без мобільного зв’язку."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Вимкніть eSIM-карту, щоб використовувати пристрій без мобільного зв’язку."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Введіть PIN-код"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Введіть пароль"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"Зараз SIM-карту вимкнено. Введіть PUK-код, щоб продовжити. Зв’яжіться з оператором, щоб дізнатися більше."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index cd99c92..28a52c0 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"اگلا الارم <xliff:g id="ALARM">%1$s</xliff:g> کیلئے سیٹ ہے"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"حذف کریں"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"‏eSIM غیر فعال کریں"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"درج کریں"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"پیٹرن بھول گئے"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"غلط پیٹرن"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"اپنا پیٹرن ڈرا کریں"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"‏SIM PIN درج کریں۔"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"‏\"<xliff:g id="CARRIER">%1$s</xliff:g>\" کیلئے SIM PIN درج کریں۔"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"‏موبائل سروس کے بغیر آلہ کا استعمال کرنے کیلئے eSIM غیر فعال کریں۔"</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"‏PIN درج کریں"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"پاسورڈ درج کریں"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"‏SIM اب غیر فعال ہوگیا ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 204bb8b..3272cb2 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"Signal <xliff:g id="ALARM">%1$s</xliff:g> da chalinadi."</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"O‘chirib tashlash"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIMni faolsizlantirish"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter tugmasi"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Grafik kalit esimdan chiqdi"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Grafik kalit xato"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Grafik kalit chizing"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"SIM karta PIN kodini kiriting."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"“<xliff:g id="CARRIER">%1$s</xliff:g>” SIM kartasi PIN kodini kiriting."</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Qurilmadan mobil xizmatlarsiz foydalanish uchun eSIMni faolsizlantiring."</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"PIN kodni kiriting"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Parol kiriting"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM karta hozir o‘chirilgan. Davom etish uchun PUK kodni kiriting. Batafsil axborot olish uchun tarmoq operatori bilan bog‘laning."</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index 45ab593..ee234cc 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -53,6 +53,10 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"已設定下一個鬧鐘時間:<xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"刪除"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"停用 eSIM 卡"</string>
+    <!-- no translation found for error_disable_esim_title (4852978431156228006) -->
+    <skip />
+    <!-- no translation found for error_disable_esim_msg (676694908770135639) -->
+    <skip />
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Enter 鍵"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"忘記解鎖圖案"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"解鎖圖案錯誤"</string>
@@ -65,7 +69,8 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"畫出解鎖圖案"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"輸入 SIM 卡的 PIN 碼。"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"輸入「<xliff:g id="CARRIER">%1$s</xliff:g>」SIM 卡的 PIN 碼。"</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"停用 eSIM 卡即可在沒有行動服務的情況下使用裝置。"</string>
+    <!-- no translation found for kg_sim_lock_esim_instructions (4416732549172148542) -->
+    <skip />
     <string name="kg_pin_instructions" msgid="4069609316644030034">"輸入 PIN 碼"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"輸入密碼"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"SIM 卡已遭停用,輸入 PUK 碼即可繼續使用。如需瞭解詳情,請與電信業者聯絡。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 2329320..2415bf3 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -53,6 +53,8 @@
     <string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"I-alamu elandelayo esethelwe i-<xliff:g id="ALARM">%1$s</xliff:g>"</string>
     <string name="keyboardview_keycode_delete" msgid="6883116827512721630">"Susa"</string>
     <string name="disable_carrier_button_text" msgid="6914341927421916114">"Khubaza i-eSIM"</string>
+    <string name="error_disable_esim_title" msgid="4852978431156228006">"Ayikwazi ukukhubaz i-eSIM"</string>
+    <string name="error_disable_esim_msg" msgid="676694908770135639">"I-eSIM ayikwakhi ukukhutshazwa ngenxa yephutha."</string>
     <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"Faka"</string>
     <string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"Ukhohlwe iphethini?"</string>
     <string name="kg_wrong_pattern" msgid="7620081431514773802">"Iphatheni engalungile"</string>
@@ -65,7 +67,7 @@
     <string name="kg_pattern_instructions" msgid="5547646893001491340">"Dweba iphethini yakho"</string>
     <string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Faka i-PIN ye-SIM"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"Faka i-PIN ye-SIM ye-\"<xliff:g id="CARRIER">%1$s</xliff:g>\""</string>
-    <string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"Khubaza i-eSIM ukusebenzisa idivayisi ngaphandle kwesevisi yeselula."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="4416732549172148542">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Khubaza i-eSIM ukuze usebenzise le sevisi yeselula."</string>
     <string name="kg_pin_instructions" msgid="4069609316644030034">"Faka iphinikhodi"</string>
     <string name="kg_password_instructions" msgid="136952397352976538">"Faka iphasiwedi"</string>
     <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Xhumana nenkampani yenethiwekhi ngemininingwane."</string>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 28a0935..4934e14 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -44,13 +44,13 @@
     <!-- Default clock parameters -->
     <dimen name="bottom_text_spacing_digital">-24dp</dimen>
     <!-- Slice header -->
-    <dimen name="widget_title_font_size">28sp</dimen>
+    <dimen name="widget_title_font_size">24sp</dimen>
     <!-- Slice subtitle  -->
     <dimen name="widget_label_font_size">16sp</dimen>
     <!-- Clock without header -->
     <dimen name="widget_big_font_size">64dp</dimen>
     <!-- Clock with header -->
-    <dimen name="widget_small_font_size">22dp</dimen>
+    <dimen name="widget_small_font_size">24dp</dimen>
     <!-- Dash between clock and header -->
     <dimen name="widget_separator_width">16dp</dimen>
     <dimen name="widget_separator_thickness">1dp</dimen>
diff --git a/packages/SystemUI/res/color/accent_tint_color_selector.xml b/packages/SystemUI/res/color/accent_tint_color_selector.xml
new file mode 100644
index 0000000..85af186
--- /dev/null
+++ b/packages/SystemUI/res/color/accent_tint_color_selector.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:color="?android:attr/colorButtonNormal"/>
+
+    <item android:color="?android:attr/colorAccent"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 100c2aa..97472a4 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -20,7 +20,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/qs_footer"
     android:layout_width="match_parent"
-    android:layout_height="48dp"
+    android:layout_height="@dimen/qs_footer_height"
     android:elevation="4dp"
     android:baselineAligned="false"
     android:clickable="false"
@@ -28,6 +28,12 @@
     android:clipToPadding="false">
 
     <View
+        android:id="@+id/qs_footer_background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/qs_background_primary" />
+
+    <View
         android:id="@+id/qs_footer_divider"
         android:layout_width="match_parent"
         android:layout_height="1dp"
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 1dab761..15b0f00 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -54,7 +54,6 @@
         android:layout_marginTop="@*android:dimen/quick_qs_offset_height"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="48dp"
         android:elevation="4dp"
     />
 
diff --git a/packages/SystemUI/res/layout/recents_swipe_up_onboarding.xml b/packages/SystemUI/res/layout/recents_onboarding.xml
similarity index 96%
rename from packages/SystemUI/res/layout/recents_swipe_up_onboarding.xml
rename to packages/SystemUI/res/layout/recents_onboarding.xml
index b3d5c90..12f278a 100644
--- a/packages/SystemUI/res/layout/recents_swipe_up_onboarding.xml
+++ b/packages/SystemUI/res/layout/recents_onboarding.xml
@@ -30,7 +30,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center"
-        android:text="@string/recents_swipe_up_onboarding"
         android:textColor="@android:color/white"
         android:textSize="16sp"
         android:drawableBottom="@drawable/ic_chevron_up"/>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 36298ca..803659f 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -15,8 +15,8 @@
 -->
 <com.android.systemui.volume.VolumeUiLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:background="@android:color/transparent"
     android:theme="@style/qs_theme"
     android:clipChildren="false" >
@@ -29,7 +29,6 @@
         android:minWidth="@dimen/volume_dialog_panel_width"
         android:background="@android:color/transparent"
         android:layout_margin="@dimen/volume_dialog_base_margin"
-        android:translationZ="8dp"
         android:orientation="vertical"
         android:clipChildren="false" >
 
@@ -39,59 +38,64 @@
             android:layout_height="wrap_content"
             android:clipChildren="false"
             android:clipToPadding="false"
-            android:paddingTop="10dp"
-            android:paddingBottom="10dp"
             android:background="@drawable/rounded_bg_full"
-            android:translationZ="8dp"
+            android:translationZ="@dimen/volume_panel_elevation"
             android:orientation="horizontal" >
                 <!-- volume rows added and removed here! :-) -->
         </LinearLayout>
 
-        <LinearLayout
+        <FrameLayout
             android:id="@+id/footer"
             android:layout_width="@dimen/volume_dialog_panel_width"
             android:layout_height="@dimen/volume_dialog_panel_width"
-            android:clipChildren="false"
-            android:clipToPadding="false"
             android:layout_marginTop="6dp"
             android:layout_marginBottom="6dp"
             android:layout_below="@id/volume_dialog_rows"
-            android:background="@drawable/rounded_bg_full"
-            android:gravity="center"
-            android:layout_gravity="end"
-            android:translationZ="8dp"
-            android:clickable="true"
-            android:orientation="vertical" >
+            android:background="@drawable/rounded_bg_full">
 
-            <TextView
-                android:id="@+id/ringer_title"
-                android:text="@string/ring_toggle_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:ellipsize="end"
-                android:maxLines="1"
-                android:layout_centerVertical="true"
-                android:textColor="?android:attr/colorControlNormal"
-                android:textAppearance="@style/TextAppearance.Volume.Header" />
+            <LinearLayout
+                android:id="@+id/footer_linear_layout"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:gravity="center"
+                android:layout_gravity="end"
+                android:translationZ="@dimen/volume_panel_elevation"
+                android:clickable="true"
+                android:orientation="vertical" >
 
-            <com.android.keyguard.AlphaOptimizedImageButton
-                android:id="@+id/ringer_icon"
-                style="@style/VolumeButtons"
-                android:background="?android:selectableItemBackgroundBorderless"
-                android:layout_width="@dimen/volume_dialog_panel_width"
-                android:layout_height="@dimen/volume_button_size"
-                android:tint="?android:attr/colorAccent"
-                android:soundEffectsEnabled="false" />
+                <TextView
+                    android:id="@+id/ringer_title"
+                    android:text="@string/ring_toggle_title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end"
+                    android:maxLines="1"
+                    android:layout_centerVertical="true"
+                    android:textColor="?android:attr/colorControlNormal"
+                    android:textAppearance="@style/TextAppearance.Volume.Header" />
 
-            <TextView
-                android:id="@+id/ringer_status"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:ellipsize="end"
-                android:maxLines="1"
-                android:textColor="?android:attr/colorControlNormal"
-                android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
+                <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/ringer_icon"
+                    style="@style/VolumeButtons"
+                    android:background="?android:selectableItemBackgroundBorderless"
+                    android:layout_width="@dimen/volume_dialog_panel_width"
+                    android:layout_height="@dimen/volume_button_size"
+                    android:tint="@color/accent_tint_color_selector"
+                    android:soundEffectsEnabled="false" />
 
-        </LinearLayout>
+                <TextView
+                    android:id="@+id/ringer_status"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end"
+                    android:maxLines="1"
+                    android:textColor="?android:attr/colorControlNormal"
+                    android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
+            </LinearLayout>
+
+            <include layout="@layout/volume_dnd_icon"/>
+        </FrameLayout>
     </LinearLayout>
 </com.android.systemui.volume.VolumeUiLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 70654a8..fb9355a 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -13,89 +13,98 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:tag="row"
     android:layout_height="wrap_content"
     android:layout_width="@dimen/volume_dialog_panel_width"
     android:clipChildren="true"
     android:clipToPadding="true"
-    android:theme="@style/qs_theme"
-    android:gravity="center"
-    android:orientation="vertical" >
+    android:theme="@style/qs_theme">
 
     <LinearLayout
-        android:orientation="vertical"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="10dp"
         android:gravity="center"
-        android:padding="5dp">
-        <TextView
-            android:id="@+id/volume_row_header"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:maxLength="10"
-            android:maxLines="1"
-            android:textColor="?android:attr/colorControlNormal"
-            android:textAppearance="@style/TextAppearance.Volume.Header" />
+        android:orientation="vertical" >
+
         <LinearLayout
-            android:id="@+id/output_chooser"
             android:orientation="vertical"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:minWidth="48dp"
-            android:minHeight="48dp"
-            android:paddingTop="10dp"
-            android:background="?android:selectableItemBackgroundBorderless"
-            android:gravity="center">
+            android:gravity="center"
+            android:padding="5dp">
             <TextView
-                android:id="@+id/volume_row_connected_device"
-                android:visibility="gone"
+                android:id="@+id/volume_row_header"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:maxLength="10"
                 android:ellipsize="end"
+                android:maxLength="10"
                 android:maxLines="1"
-                android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
-            <com.android.keyguard.AlphaOptimizedImageButton
-                android:id="@+id/output_chooser_button"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
+                android:textColor="?android:attr/colorControlNormal"
+                android:textAppearance="@style/TextAppearance.Volume.Header" />
+            <LinearLayout
+                android:id="@+id/output_chooser"
+                android:orientation="vertical"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minWidth="48dp"
+                android:minHeight="48dp"
+                android:paddingTop="10dp"
                 android:background="?android:selectableItemBackgroundBorderless"
-                android:contentDescription="@string/accessibility_output_chooser"
-                style="@style/VolumeButtons"
-                android:clickable="false"
-                android:layout_centerVertical="true"
-                android:src="@drawable/ic_swap"
-                android:soundEffectsEnabled="false" />
+                android:gravity="center">
+                <TextView
+                    android:id="@+id/volume_row_connected_device"
+                    android:visibility="gone"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:maxLength="10"
+                    android:ellipsize="end"
+                    android:maxLines="1"
+                    android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
+                <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/output_chooser_button"
+                    android:layout_width="24dp"
+                    android:layout_height="24dp"
+                    android:background="?android:selectableItemBackgroundBorderless"
+                    android:contentDescription="@string/accessibility_output_chooser"
+                    style="@style/VolumeButtons"
+                    android:clickable="false"
+                    android:layout_centerVertical="true"
+                    android:src="@drawable/ic_swap"
+                    android:soundEffectsEnabled="false"/>
+            </LinearLayout>
         </LinearLayout>
-    </LinearLayout>
-    <FrameLayout
-        android:id="@+id/volume_row_slider_frame"
-        android:padding="0dp"
-        android:layout_width="@dimen/volume_dialog_panel_width"
-        android:layoutDirection="rtl"
-        android:layout_height="@dimen/volume_dialog_panel_width">
-        <SeekBar
-            android:id="@+id/volume_row_slider"
-            android:clickable="true"
+        <FrameLayout
+            android:id="@+id/volume_row_slider_frame"
             android:padding="0dp"
-            android:layout_margin="0dp"
             android:layout_width="@dimen/volume_dialog_panel_width"
-            android:layout_height="@dimen/volume_dialog_panel_width"
             android:layoutDirection="rtl"
-            android:layout_gravity="center"
-            android:rotation="90" />
-    </FrameLayout>
+            android:layout_height="@dimen/volume_dialog_panel_width">
+            <SeekBar
+                android:id="@+id/volume_row_slider"
+                android:clickable="true"
+                android:padding="0dp"
+                android:layout_margin="0dp"
+                android:layout_width="@dimen/volume_dialog_panel_width"
+                android:layout_height="@dimen/volume_dialog_panel_width"
+                android:layoutDirection="rtl"
+                android:layout_gravity="center"
+                android:rotation="90" />
+        </FrameLayout>
 
-    <com.android.keyguard.AlphaOptimizedImageButton
-        android:id="@+id/volume_row_icon"
-        style="@style/VolumeButtons"
-        android:padding="10dp"
-        android:layout_width="@dimen/volume_button_size"
-        android:layout_height="@dimen/volume_button_size"
-        android:background="?android:selectableItemBackgroundBorderless"
-        android:soundEffectsEnabled="false" />
+        <com.android.keyguard.AlphaOptimizedImageButton
+            android:id="@+id/volume_row_icon"
+            style="@style/VolumeButtons"
+            android:padding="10dp"
+            android:layout_width="@dimen/volume_button_size"
+            android:layout_height="@dimen/volume_button_size"
+            android:background="?android:selectableItemBackgroundBorderless"
+            android:soundEffectsEnabled="false" />
+    </LinearLayout>
 
-</LinearLayout>
\ No newline at end of file
+    <include layout="@layout/volume_dnd_icon"/>
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/volume_dnd_icon.xml b/packages/SystemUI/res/layout/volume_dnd_icon.xml
new file mode 100644
index 0000000..215b230
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_dnd_icon.xml
@@ -0,0 +1,30 @@
+<!--
+     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.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="14dp"
+    android:layout_height="14dp"
+    android:layout_marginTop="6dp"
+    android:layout_marginRight="6dp"
+    android:layout_gravity="right|top">
+
+    <ImageView
+        android:id="@+id/dnd_icon"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@drawable/ic_dnd"
+        android:tint="?android:attr/textColorTertiary"/>
+</FrameLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 5242029..9d090ba7 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"maak kamera oop"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Kies nuwe taakuitleg"</string>
     <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Vingerafdrukikoon"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Programikoon"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Hulpboodskapgebied"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Versoenbaarheid-zoem se knoppie."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoem kleiner na groter skerm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth gekoppel."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi af"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi is aan"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Geen Wi-Fi-netwerke beskikbaar nie"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Saai uit"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Saai tans uit"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Onbenoemde toestel"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Koppel tans …"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"USB-verbinding"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Warmkol"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Skakel tans aan …"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d toestelle</item>
+      <item quantity="one">%d toestel</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Kennisgewings"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Flitslig"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobiele data"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> gebruik"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g>-limiet"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> waarskuwing"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Werkprofiel"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Kennisgewings en programme is af"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Aandbeligting"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Aan by sonsondergang"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Tot sonsopkoms"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> is in veiligmodus gedeaktiveer."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Vee alles uit"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Trek hier om verdeelde skerm te gebruik"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Swiep op om programme te wissel"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Verdeel horisontaal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verdeel vertikaal"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Verdeel gepasmaak"</string>
@@ -502,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Skakel nou af"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Vou uit"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Vou in"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Wissel uitvoertoestel"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skerm is vasgespeld"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Oorsig om dit te ontspeld."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Oorsig om dit te ontspeld."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Het dit"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nee, dankie"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Versteek <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Dit sal verskyn die volgende keer wanneer jy dit in instellings aanskakel."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Versteek"</string>
@@ -586,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Met kragkennisgewingkontroles kan jy \'n belangrikheidvlak van 0 tot 5 vir \'n program se kennisgewings stel. \n\n"<b>"Vlak 5"</b>" \n- Wys aan die bokant van die kennisgewinglys \n- Laat volskermonderbreking toe \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 4"</b>" \n- Verhoed volskermonderbreking \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 3"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n\n"<b>"Vlak 2"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n\n"<b>"Vlak 1"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n- Versteek van sluitskerm en statusbalk \n- Wys aan die onderkant van die kennisgewinglys \n\n"<b>"Vlak 0"</b>" \n- Blokkeer alle kennisgewings van die program af"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Kennisgewings"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Jy sal nie meer hierdie kennisgewings sien nie"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Jy maak hierdie kennisgewings gewoonlik toe. \nMoet ons aanhou om hulle te wys?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Hou aan om hierdie kennisgewings te wys?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Stop kennisgewings"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Hou aan wys"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index f08c71e..cf1adf2 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"ካሜራ ክፈት"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"የአዲስ ተግባር አቀማመጥን ይምረጡ"</string>
     <string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"የጣት አሻራ አዶ"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"የመተግበሪያ አዶ"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"የእገዛ መልዕክት አካባቢ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ብሉቱዝ ተያይዟል።"</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ጠፍቷል"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi በርቷል"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"ምንም የWi-Fi  አውታረ መረቦች የሉም"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"በመውሰድ ላይ"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ያልተሰየመ መሳሪያ"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"በማገናኘት ላይ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"በማገናኘት ላይ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"መገናኛ ነጥብ"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"በማብራት ላይ..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d መሣሪያዎች</item>
+      <item quantity="other">%d መሣሪያዎች</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"ማሳወቂያዎች"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"የባትሪ ብርሃን"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"የተንቀሳቃሽ ስልክ ውሂብ"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ጥቅም ላይ ውሏል"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ገደብ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"የ<xliff:g id="DATA_LIMIT">%s</xliff:g> ማስጠንቀቂያ"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"የሥራ መገለጫ"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"ማሳወቂያዎች እና መተግበሪያዎች ጠፍተዋል"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"የምሽት ብርሃን"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"ጸሐይ ስትጠልቅ ይበራል"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"ጸሐይ እስክትወጣ ድረስ"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> በጥንቃቄ ሁነታ ውስጥ ታግዷል።"</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ሁሉንም አጽዳ"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"የተከፈለ ማያ ገጽን ለመጠቀም እዚህ ላይ ይጎትቱ"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"መተግበሪያዎችን ለመቀየር ወደ ላይ ያንሸራትቱ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"አግድም ክፈል"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ቁልቁል ክፈል"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"በብጁ ክፈል"</string>
@@ -502,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"አሁን አጥፋ"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"አስፋ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ሰብስብ"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"የውጽዓት መሣሪያን ይቀይሩ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ማያ ገጽ ተሰክቷል"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል ተመለስ እና አጠቃላይ ዕይታ የሚለውን ይጫኑ እና ይያዙ።"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል አጠቃላይ ዕይታ ተጭነው ይያዙ።"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ገባኝ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"አይ፣ አመሰግናለሁ"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ይደበቅ?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"በቅንብሮች ውስጥ በሚቀጥለው ጊዜ እንዲበራ በሚያደርጉበት ጊዜ ዳግመኛ ብቅ ይላል።"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ደብቅ"</string>
@@ -586,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"በኃይል ማሳወቂያ መቆጣጠሪያዎች አማካኝነት የአንድ መተግበሪያ ማሳወቂያዎች የአስፈላጊነት ደረጃ ከ0 እስከ 5 ድረስ ማዘጋጀት ይችላሉ። \n\n"<b>"ደረጃ 5"</b>" \n- በማሳወቂያ ዝርዝሩ አናት ላይ አሳይ \n- የሙሉ ማያ ገጽ ማቋረጥን ፍቀድ \n- ሁልጊዜ አጮልቀው ይመልከቱ \n\n"<b>"ደረጃ 4"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ከልክል \n- ሁልጊዜ አጮልቀው ይመልከቱ \n\n"<b>"ደረጃ 3"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ከልክል \n- በፍጹም አጮልቀው አይምልከቱ \n\n"<b>"ደረጃ 2"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ይከልክሉ \n- በፍጹም አጮልቀው አይመልከቱ \n- ድምፅ እና ንዝረትን በፍጹም አይኑር \n\n"<b>"ደረጃ 1"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ይከልክሉ \n- በፍጹም አጮልቀው አይመልከቱ \n- ድምፅ ወይም ንዝረትን በፍጹም አያደርጉ \n- ከመቆለፊያ ገጽ እና የሁኔታ አሞሌ ይደብቁ \n- በማሳወቂያ ዝርዝር ግርጌ ላይ አሳይ \n\n"<b>"ደረጃ 0"</b>" \n- ሁሉንም የመተግበሪያው ማሳወቂያዎች ያግዱ"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"ማሳወቂያዎች"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"እነዚህን ማሳወቂያዎችን ከእንግዲህ አይመለከቷቸውም"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"አብዛኛውን ጊዜ እነዚህን ማሳወቂያዎች ያሰናብቷቸዋል። \nመታየታቸው ይቀጥል??"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"እነዚህን ማሳወቂያዎች ማሳየት ይቀጥሉ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"ማሳወቂያዎችን አስቁም"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"ማሳየትን ቀጥል"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 17d7718..e00a2dd 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"kemaranı açın"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Yeni tapşırıq sxemi seçin"</string>
     <string name="cancel" msgid="6442560571259935130">"Ləğv et"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Barmaq izi ikonası"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Tətbiq ikonası"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Yardım mesajı bölməsi"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyğunluq zoom düyməsi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha böyük ekranda uzaqlaşdır."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth qoşulub."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi sönülüdür"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi Aktiv"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Heç bir Wi-Fi şəbəkəsi əlçatan deyil"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Yayım"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Yayım"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Adsız cihaz"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Qoşulur..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Birləşmə"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Aktiv edilir..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d cihaz</item>
+      <item quantity="one">%d cihaz</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Bildirişlər"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"İşartı"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobil data"</string>
@@ -499,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"İndi deaktiv edin"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişləndirin"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yığcamlaşdırın"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Çıxış cihazına keçin"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrana sancaq taxıldı"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə basıb saxlayın."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri düyməsinə basıb saxlayın."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Yox, çox sağ olun"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlədilsin?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ayarlarda onu aktivləşdirəcəyiniz vaxta qədər o, yenidən görünəcək."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Gizlədin"</string>
@@ -583,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Enerji bildiriş nəzarəti ilə, tətbiq bildirişləri üçün əhəmiyyət səviyyəsini 0-dan 5-ə kimi ayarlaya bilərsiniz. \n\n"<b>"Səviyyə 5"</b>" \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n- Tam ekran kəsintisinə icazə verin \n- Hər zaman izləyin \n\n"<b>"Səviyyə 4"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Hər zaman izləyin \n\n"<b>"Level 3"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n\n"<b>"Level 2"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n\n"<b>"Səviyyə 1"</b>" \n- Prevent full screen interruption \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n- Ekran kilidi və ya status panelindən gizlədin \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n\n"<b>"Səviyyə 0"</b>" \n- Bütün bildirişləri tətbiqdən blok edin"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirişlər"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Artıq bu bildirişləri görməyəcəkəsiniz"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Adətən bu bildirişləri rədd edirsiniz. \nBildirişlər göstərilsin?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Bu bildirişlər göstərilməyə davam edilsin?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Bildirişləri dayandırın"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Göstərməyə davam edin"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 4cbb5ed..eb08f50 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"ক্যামেরা খুলুন"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"নতুন কার্য লেআউট বেছে নিন"</string>
     <string name="cancel" msgid="6442560571259935130">"বাতিল করুন"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"আঙ্গুলের ছাপের আইকন"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"অ্যাপ্লিকেশনের আইকন"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"সহায়তার মেসেজ দেখানোর জায়গা"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"সামঞ্জস্যের জুম বোতাম৷"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ছোট থেকে বৃহৎ স্ক্রীণে জুম করুন৷"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ব্লুটুথ সংযুক্ত হয়েছে৷"</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ওয়াই-ফাই বন্ধ"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"ওয়াই-ফাই চালু আছে"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"কোনো ওয়াই-ফাই নেটওয়ার্ক উপলব্ধ নেই"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"কাস্ট করুন"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"কাস্ট করা হচ্ছে"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"নামবিহীন ডিভাইস"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"সংযুক্ত হচ্ছে..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"টেদারিং"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"হটস্পট"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"চালু করা হচ্ছে…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%dটি ডিভাইস</item>
+      <item quantity="other">%dটি ডিভাইস</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"বিজ্ঞপ্তিগুলি"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ফ্ল্যাশলাইট"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"মোবাইল ডেটা"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ব্যবহৃত হয়েছে"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"সীমা <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"কাজের প্রোফাইল"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"বিজ্ঞপ্তি ও অ্যাপ বন্ধ আছে"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"নাইট লাইট"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"সূর্যাস্তে চালু হবে"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"সূর্যোদয় পর্যন্ত"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"নিরাপদ মোডে <xliff:g id="APP">%s</xliff:g> অক্ষম করা হয়েছে৷"</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"সবকিছু সাফ করুন"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"বিভক্ত স্ক্রীন ব্যবহার করতে এখানে টেনে আনুন"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"অন্য অ্যাপে যেতে উপরের দিকে সোয়াইপ করুন"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"অনুভূমিক স্প্লিট"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"উল্লম্ব স্প্লিট"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"কাস্টম স্প্লিট করুন"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"এখনই বন্ধ করুন"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"বড় করুন"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"সঙ্কুচিত করুন"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"স্ক্রিন পিন করা হয়েছে"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ফিরুন এবং ওভারভিউ স্পর্শ করে ধরে থাকুন।"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ওভারভিউ স্পর্শ করে ধরে থাকুন৷"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"বুঝেছি"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"না থাক"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকাবেন?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"আপনি পরের বার সেটিংস-এ এটি চালু করলে এটি উপস্থিত হবে"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"লুকান"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"পাওয়ার বিজ্ঞপ্তির নিয়ন্ত্রণগুলি ব্যহবার করে, আপনি কোনও অ্যাপ্লিকেশনের বিজ্ঞপ্তির জন্য ০ থেকে ৫ পর্যন্ত একটি গুরুত্বের লেভেলকে সেট করতে পারবেন৷ \n\n"<b>"লেভেল ৫"</b>" \n- বিজ্ঞপ্তি তালিকার শীর্ষে দেখায় \n- পূর্ণ স্ক্রিনের বাধাকে অনুমতি দেয় \n- সর্বদা স্ক্রিনে উপস্থিত হয় \n\n"<b>"লেভেল ৪"</b>" \n- পূর্ণ স্ক্রিনের বাধাকে আটকায় \n- সর্বদা স্ক্রিনে উপস্থিত হয় \n\n"<b>"লেভেল ৩"</b>" \n- পূর্ণ স্ক্রিনের বাধাকে আটকায় \n- কখনওই স্ক্রিনে উপস্থিত হয় না \n\n"<b>"লেভেল ২"</b>" \n- পূর্ণ স্ক্রিনের বাধাকে আটকায় \n- কখনওই স্ক্রিনে উপস্থিত হয় না \n- কখনওই শব্দ এবং কম্পন করে না \n\n"<b>"লেভেল ১"</b>" \n- পূর্ণ স্ক্রিনের বাধাকে আটকায় \n- কখনওই স্ক্রিনে উপস্থিত হয় না \n- কখনওই শব্দ এবং কম্পন করে না \n- লক স্ক্রিন এবং স্ট্যাটাস বার থেকে লুকায় \n- বিজ্ঞপ্তি তালিকার নীচের দিকে দেখায় \n\n"<b>"লেভেল ০"</b>" \n- অ্যাপ্লিকেশন থেকে সমস্ত বিজ্ঞপ্তিকে অবরূদ্ধ করে"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"বিজ্ঞপ্তি"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"এই বিজ্ঞপ্তিগুলি আপনাকে আর দেখানো হবে না"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"এই বিজ্ঞপ্তিগুলিকে আপনি সাধারণত বাতিল করেন। \nসেগুলি দেখতে চান?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"এই বিজ্ঞপ্তিগুলি পরেও দেখে যেতে চান?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"বিজ্ঞপ্তি বন্ধ করুন"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"দেখতে থাকুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 7f8d001..676ecd0 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -104,12 +104,9 @@
     <string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Odaberite novi raspored zadataka"</string>
     <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona za otisak prsta"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikacije"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Prostor za poruku za pomoć"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme za uvećavanje u slučaju nekompatibilnosti."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Uvećani prikaz manjeg ekrana na većem ekranu."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth je povezan."</string>
@@ -210,13 +207,13 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Uključen način rada u avionu."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Način rada u avionu je isključen."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Način rada u avionu je uključen."</string>
-    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Opcija Ne ometaj je uključena, čut će se samo prioritetna obavještenja."</string>
-    <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Opcija Ne ometaj je uključena, potpuna tišina."</string>
-    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Opcija Ne ometaj je uključena, čut će se samo alarmi."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Način rada Ne ometaj je uključen, čut će se samo prioritetna obavještenja."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Način rada Ne ometaj je uključen, potpuna tišina."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Način rada Ne ometaj je uključen, čut će se samo alarmi."</string>
     <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"Ne ometaj."</string>
-    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Opcija Ne ometaj je isključena."</string>
-    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Opcija Ne ometaj je isključena."</string>
-    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Opcija Ne ometaj je uključena."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Način rada Ne ometaj je isključen."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Način rada Ne ometaj je isključen."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Način rada Ne ometaj je uključen."</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth isključen."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth uključen."</string>
@@ -313,6 +310,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi isključen"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi uključen"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nema dostupnih Wi-Fi mreža"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Emitiranje"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Prebacivanje"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Neimenovani uređaj"</string>
@@ -329,9 +328,12 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Povezivanje..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Dijeljenje veze"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Pristupna tačka"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Uključivanje…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d uređaj</item>
+      <item quantity="few">%d uređaja</item>
+      <item quantity="other">%d uređaja</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obavještenja"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Svjetiljka"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Prijenos podataka na mobilnoj mreži"</string>
@@ -341,10 +343,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Iskorišteno <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ograničenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Radni profil"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Isključena su obavještenja i aplikacije"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svjetlo"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Uključuje se u suton"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Do svitanja"</string>
@@ -362,8 +362,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> je onemogućena u sigurnom načinu rada."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Obriši sve"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Povucite ovdje za korištenje podijeljenog ekrana"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Prevucite prema gore za promjenu aplikacije"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podjela po horizontali"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podjela po vertikali"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođena podjela"</string>
@@ -504,11 +503,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Isključi sada"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skupi"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran je prikačen"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Nazad."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Pregled."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Razumijem"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Pojavit će se sljedeći put kada opciju uključite u postavkama."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sakrij"</string>
@@ -590,8 +603,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Uz kontrolu obavještenja o napajanju, možete postaviti nivo značaja obavještenja iz aplikacije, i to od nivoa 0 do 5. \n\n"<b>"Nivo 5"</b>" \n- Prikaži na vrhu liste obavještenja \n- Dopusti prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nvio 4"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nivo 3"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n\n"<b>"Nivo 2"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n\n"<b>"Nivo 1"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikada ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n- Sakrij sa ekrana za zaključavanje i statusne trake \n- Prikaži na dnu liste obavještenja \n\n"<b>"Nivo 0"</b>" \n- Blokiraj sva obavještenja iz aplikacije"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Obavještenja"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Nećete više vidjeti ova obavještenja"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Obično odbacujete ova obavještenja. \nNastaviti ih prikazivati?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Nastaviti prikazivanje ovih obavještenja?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Zaustavi obavještenja"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Nastavi prikazivanje"</string>
@@ -668,7 +680,7 @@
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"Prikazati sa kontrolama jačine zvuka"</string>
     <string name="volume_and_do_not_disturb" msgid="3373784330208603030">"Ne ometaj"</string>
     <string name="volume_dnd_silent" msgid="4363882330723050727">"Prečica za dugmad za Jačinu zvuka"</string>
-    <string name="volume_up_silent" msgid="7141255269783588286">"Deaktiviraj režim Ne ometaj kada se zvuk pojača"</string>
+    <string name="volume_up_silent" msgid="7141255269783588286">"Deaktiviraj način rada Ne ometaj kada se zvuk pojača"</string>
     <string name="battery" msgid="7498329822413202973">"Baterija"</string>
     <string name="clock" msgid="7416090374234785905">"Sat"</string>
     <string name="headset" msgid="4534219457597457353">"Slušalice s mikrofonom"</string>
@@ -802,10 +814,10 @@
     <string name="mobile_data" msgid="7094582042819250762">"Prijenos podataka na mobilnoj mreži"</string>
     <string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi veza je isključena"</string>
     <string name="bt_is_off" msgid="2640685272289706392">"Bluetooth je isključen"</string>
-    <string name="dnd_is_off" msgid="6167780215212497572">"Opcija Ne ometaj je isključena"</string>
+    <string name="dnd_is_off" msgid="6167780215212497572">"Način rada Ne ometaj je isključen"</string>
     <string name="qs_dnd_prompt_auto_rule" msgid="862559028345233052">"Opciju Ne ometaju uključilo je automatsko pravilo (<xliff:g id="ID_1">%s</xliff:g>)."</string>
-    <string name="qs_dnd_prompt_app" msgid="7978037419334156034">"Opciju Ne ometaj uključila je aplikacija <xliff:g id="ID_1">%s</xliff:g>."</string>
-    <string name="qs_dnd_prompt_auto_rule_app" msgid="2599343675391111951">"Opciju Ne ometaj uključilo je automatsko pravilo ili aplikacija."</string>
+    <string name="qs_dnd_prompt_app" msgid="7978037419334156034">"Način rada Ne ometaj uključila je aplikacija <xliff:g id="ID_1">%s</xliff:g>."</string>
+    <string name="qs_dnd_prompt_auto_rule_app" msgid="2599343675391111951">"Način rada Ne ometaj uključilo je automatsko pravilo ili aplikacija."</string>
     <string name="qs_dnd_until" msgid="3469471136280079874">"Do <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Zadrži"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Zamijeni"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 8d61a9a..4eff30d 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -33,13 +33,13 @@
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continu"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacions"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Queda poca bateria"</string>
-    <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Queda poca bateria. Activa el mode Estalvi de bateria."</string>
+    <string name="battery_low_title_hybrid" msgid="6268991275887381595">"Queda poca bateria. Activa el mode d\'estalvi de bateria."</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>."</string>
     <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>; temps restant aproximat segons l\'ús que en fas: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="battery_low_percent_format_hybrid_short" msgid="9025795469949145586">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>; temps restant aproximat: <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g>. La funció Estalvi de bateria està activada."</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"Pujada d\'USB no admesa.\nUtilitza només el carregador proporcionat."</string>
-    <string name="invalid_charger_title" msgid="3515740382572798460">"La pujada per USB no és compatible."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"Càrrega per USB no admesa.\nUtilitza només el carregador proporcionat."</string>
+    <string name="invalid_charger_title" msgid="3515740382572798460">"La càrrega per USB no és compatible."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Fes servir només el carregador proporcionat amb el dispositiu."</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Configuració"</string>
     <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"Vols activar la funció Estalvi de bateria?"</string>
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"obre la càmera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selecciona el disseny de la tasca nova"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel·la"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona d\'empremta digital"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icona d\'aplicació"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Àrea de missatge d\'ajuda"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Amplia menys com més gran sigui la pantalla."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connectat."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desconnectada"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"La Wi-Fi està activada"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"No hi ha cap xarxa Wi-Fi disponible"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Emet"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"En emissió"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositiu sense nom"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"S\'està connectant..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Compartició de xarxa"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Punt d\'accés Wi-Fi"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"S\'està activant..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d dispositius</item>
+      <item quantity="one">%d dispositiu</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificacions"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Llanterna"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Dades mòbils"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Utilitzats: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertiment: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Perfil professional"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Les notificacions i les aplicacions estan desactivades"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Llum nocturna"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"A la posta de sol"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Fins a l\'alba"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"En mode segur, l\'aplicació <xliff:g id="APP">%s</xliff:g> està desactivada."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Esborra-ho tot"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Arrossega-ho aquí per utilitzar la pantalla dividida"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Llisca cap amunt per canviar d\'aplicació"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisió horitzontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisió vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisió personalitzada"</string>
@@ -370,7 +368,7 @@
     <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Divideix la pantalla cap a la dreta"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"S\'està carregant"</string>
-    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> per completar la pujada"</string>
+    <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> per completar la càrrega"</string>
     <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No s\'està carregant"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string>
     <string name="description_target_search" msgid="3091587249776033139">"Cerca"</string>
@@ -397,9 +395,9 @@
     <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Silenci\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Només\ninterr. prior."</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Només\nalarmes"</string>
-    <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la pujada)"</string>
-    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Pujada ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
-    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Pujada lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
+    <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Càrrega ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Càrrega lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Canvia d\'usuari"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Canvia d\'usuari. Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Desactiva ara"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Amplia"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Replega"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"La pantalla està fixada"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, toca i mantén premudes els botons Enrere i Aplicacions recents."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, toca i mantén premut el botó Aplicacions recents."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"D\'acord"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gràcies"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vols amagar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tornarà a mostrar-se la propera vegada que l\'activis a la configuració."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Amaga"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Amb els controls de notificació millorats, pots establir un nivell d\'importància d\'entre 0 i 5 per a les notificacions d\'una aplicació. \n\n"<b>"Nivell 5"</b>" \n- Mostra les notificacions a la part superior de la llista \n- Permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 4"</b>" \n- No permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 3"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n\n"<b>"Nivell 2"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- Les notificacions no poden emetre sons ni vibracions \n\n"<b>"Nivell 1"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- No activa mai el so ni la vibració \n- Amaga les notificacions de la pantalla de bloqueig i de la barra d\'estat \n- Mostra les notificacions a la part inferior de la llista \n\n"<b>"Nivell 0"</b>" \n- Bloqueja totes les notificacions de l\'aplicació"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificacions"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Ja no veuràs aquestes notificacions"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Normalment ignores aquestes notificacions. \nVols que es continuïn mostrant?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Vols continuar rebent aquestes notificacions?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Deixa d\'enviar notificacions"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Continua rebent"</string>
@@ -614,7 +625,7 @@
       <item quantity="one">%d minut</item>
     </plurals>
     <string name="battery_panel_title" msgid="7944156115535366613">"Consum de la bateria"</string>
-    <string name="battery_detail_charging_summary" msgid="1279095653533044008">"La funció Estalvi de bateria no està disponible durant la pujada"</string>
+    <string name="battery_detail_charging_summary" msgid="1279095653533044008">"La funció Estalvi de bateria no està disponible durant la càrrega"</string>
     <string name="battery_detail_switch_title" msgid="6285872470260795421">"Estalvi de bateria"</string>
     <string name="battery_detail_switch_summary" msgid="9049111149407626804">"Redueix el rendiment i les dades en segon pla"</string>
     <string name="keyboard_key_button_template" msgid="6230056639734377300">"Botó <xliff:g id="NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 3c3e1d4..faa1f1f 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -105,12 +105,9 @@
     <string name="camera_label" msgid="7261107956054836961">"spustit fotoaparát"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Vybrat nové rozvržení úkolů"</string>
     <string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikona otisku prstu"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ikona aplikace"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Oblast pro zprávu nápovědy"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Rozhraní Bluetooth je připojeno."</string>
@@ -317,6 +314,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi vypnuta"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi je zapnutá"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Žádné sítě Wi-Fi nejsou k dispozici"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Odeslat"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Odesílání"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nepojmenované zařízení"</string>
@@ -333,9 +332,13 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Připojování..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Sdílené připojení"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Zapínání..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="few">%d zařízení</item>
+      <item quantity="many">%d zařízení</item>
+      <item quantity="other">%d zařízení</item>
+      <item quantity="one">%d zařízení</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Oznámení"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Svítilna"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobilní data"</string>
@@ -345,10 +348,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Využito: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornění při <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Pracovní profil"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Oznámení a aplikace jsou vypnuty"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noční režim"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Zapnout při soumraku"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Do svítání"</string>
@@ -366,8 +367,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikace <xliff:g id="APP">%s</xliff:g> je v nouzovém režimu zakázána."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Vymazat vše"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Rozdělenou obrazovku můžete použít přetažením zde"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Přejetím nahoru přepnete aplikace"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vodorovné rozdělení"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikální rozdělení"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Vlastní rozdělení"</string>
@@ -508,11 +508,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Vypnout"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozbalit"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sbalit"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Přepnout zařízení pro výstup"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je připnuta"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítek Zpět a Přehled."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítka Přehled."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Rozumím"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, děkuji"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skrýt <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Tato položka se znovu zobrazí, až ji v nastavení znovu zapnete."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skrýt"</string>
@@ -592,8 +605,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Rozšířené ovládací prvky oznámení umožňují nastavit úroveň důležitosti oznámení aplikace od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazit na začátku seznamu oznámení \n– Povolit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 4"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 3"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n\n"<b>"Úroveň 2"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat žádný zvukový signál ani nevibrovat \n\n"<b>"Úroveň 1"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat zvukový signál ani nevibrovat \n– Skrýt z obrazovky uzamčení a stavového řádku \n– Zobrazovat na konci seznamu oznámení \n\n"<b>";Úroveň 0"</b>" \n– Blokovat všechna oznámení z aplikace"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Oznámení"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Tato oznámení již nebudete dostávat"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Tato oznámení obvykle odmítáte. \nChcete je nadále zobrazovat?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Mají se tato oznámení nadále zobrazovat?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Přestat zobrazovat oznámení"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Nadále zobrazovat"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 3f6d5e5..3e9e3a2 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi On"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"No Wi-Fi networks available"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Casting"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Turning on..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d devices</item>
+      <item quantity="one">%d device</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifications"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Torch"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobile data"</string>
@@ -499,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Turn off now"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Switch output device"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
@@ -583,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. \n\n"<b>"Level 5"</b>" \n- Show at the top of the notification list \n- Allow full screen interruption \n- Always peek \n\n"<b>"Level 4"</b>" \n- Prevent full screen interruption \n- Always peek \n\n"<b>"Level 3"</b>" \n- Prevent full screen interruption \n- Never peek \n\n"<b>"Level 2"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound and vibration \n\n"<b>"Level 1"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound or vibrate \n- Hide from lock screen and status bar \n- Show at the bottom of the notification list \n\n"<b>"Level 0"</b>" \n- Block all notifications from the app"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"You won\'t see these notifications anymore"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"You usually dismiss these notifications. \nKeep showing them?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Keep showing these notifications?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Stop notifications"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Keep showing"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index d49c25a..e5f4ece 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi On"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"No Wi-Fi networks available"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Casting"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Turning on..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d devices</item>
+      <item quantity="one">%d device</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifications"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Flashlight"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobile data"</string>
@@ -499,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Turn off now"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Switch output device"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
@@ -583,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. \n\n"<b>"Level 5"</b>" \n- Show at the top of the notification list \n- Allow full screen interruption \n- Always peek \n\n"<b>"Level 4"</b>" \n- Prevent full screen interruption \n- Always peek \n\n"<b>"Level 3"</b>" \n- Prevent full screen interruption \n- Never peek \n\n"<b>"Level 2"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound and vibration \n\n"<b>"Level 1"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound or vibrate \n- Hide from lock screen and status bar \n- Show at the bottom of the notification list \n\n"<b>"Level 0"</b>" \n- Block all notifications from the app"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"You won\'t see these notifications anymore"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"You usually dismiss these notifications. \nKeep showing them?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Keep showing these notifications?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Stop notifications"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Keep showing"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 3f6d5e5..3e9e3a2 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi On"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"No Wi-Fi networks available"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Casting"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Turning on..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d devices</item>
+      <item quantity="one">%d device</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifications"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Torch"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobile data"</string>
@@ -499,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Turn off now"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Switch output device"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
@@ -583,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. \n\n"<b>"Level 5"</b>" \n- Show at the top of the notification list \n- Allow full screen interruption \n- Always peek \n\n"<b>"Level 4"</b>" \n- Prevent full screen interruption \n- Always peek \n\n"<b>"Level 3"</b>" \n- Prevent full screen interruption \n- Never peek \n\n"<b>"Level 2"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound and vibration \n\n"<b>"Level 1"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound or vibrate \n- Hide from lock screen and status bar \n- Show at the bottom of the notification list \n\n"<b>"Level 0"</b>" \n- Block all notifications from the app"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"You won\'t see these notifications anymore"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"You usually dismiss these notifications. \nKeep showing them?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Keep showing these notifications?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Stop notifications"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Keep showing"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 3f6d5e5..3e9e3a2 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Select new task layout"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Fingerprint icon"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Application icon"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Help message area"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi On"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"No Wi-Fi networks available"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Casting"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Turning on..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d devices</item>
+      <item quantity="one">%d device</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifications"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Torch"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobile data"</string>
@@ -499,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Turn off now"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Switch output device"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"It will reappear the next time you turn it on in settings."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Hide"</string>
@@ -583,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. \n\n"<b>"Level 5"</b>" \n- Show at the top of the notification list \n- Allow full screen interruption \n- Always peek \n\n"<b>"Level 4"</b>" \n- Prevent full screen interruption \n- Always peek \n\n"<b>"Level 3"</b>" \n- Prevent full screen interruption \n- Never peek \n\n"<b>"Level 2"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound and vibration \n\n"<b>"Level 1"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound or vibrate \n- Hide from lock screen and status bar \n- Show at the bottom of the notification list \n\n"<b>"Level 0"</b>" \n- Block all notifications from the app"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"You won\'t see these notifications anymore"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"You usually dismiss these notifications. \nKeep showing them?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Keep showing these notifications?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Stop notifications"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Keep showing"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 0571c1f..35cef20 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‎‏‏‏‎‎‎‎‏‎open camera‎‏‎‎‏‎"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‎‎Select new task layout‎‏‎‎‏‎"</string>
     <string name="cancel" msgid="6442560571259935130">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎Cancel‎‏‎‎‏‎"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‎‎Fingerprint icon‎‏‎‎‏‎"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‎‎‏‎Application icon‎‏‎‎‏‎"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎Help message area‎‏‎‎‏‎"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‎Compatibility zoom button.‎‏‎‎‏‎"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎Zoom smaller to larger screen.‎‏‎‎‏‎"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎Bluetooth connected.‎‏‎‎‏‎"</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‎Wi-Fi Off‎‏‎‎‏‎"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎Wi-Fi On‎‏‎‎‏‎"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‏‎‏‎‏‎‎No Wi-Fi networks available‎‏‎‎‏‎"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‏‎Cast‎‏‎‎‏‎"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎Casting‎‏‎‎‏‎"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎Unnamed device‎‏‎‎‏‎"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎Connecting...‎‏‎‎‏‎"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‏‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‎‏‎Tethering‎‏‎‎‏‎"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‏‎‎‎‏‏‏‏‎Hotspot‎‏‎‎‏‎"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎Turning on...‎‏‎‎‏‎"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‎%d devices‎‏‎‎‏‎</item>
+      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‎%d device‎‏‎‎‏‎</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎Notifications‎‏‎‎‏‎"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‏‎‎Flashlight‎‏‎‎‏‎"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎‏‏‎Mobile data‎‏‎‎‏‎"</string>
@@ -499,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‏‎‎‎Turn off now‎‏‎‎‏‎"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎Expand‎‏‎‎‏‎"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎Collapse‎‏‎‎‏‎"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‎‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‎‎Switch output device‎‏‎‎‏‎"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎Screen is pinned‎‏‎‎‏‎"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin.‎‏‎‎‏‎"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‎‎‎This keeps it in view until you unpin. Touch &amp; hold Overview to unpin.‎‏‎‎‏‎"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎Got it‎‏‎‎‏‎"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‏‎‎‎No thanks‎‏‎‎‏‎"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎Hide ‎‏‎‎‏‏‎<xliff:g id="TILE_LABEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎‎It will reappear the next time you turn it on in settings.‎‏‎‎‏‎"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‎Hide‎‏‎‎‏‎"</string>
@@ -583,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‎‎‎‎‎‏‏‏‎‎With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎Level 5‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Show at the top of the notification list ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Allow full screen interruption ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Always peek ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎Level 4‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Prevent full screen interruption ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Always peek ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎Level 3‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Prevent full screen interruption ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Never peek ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎Level 2‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Prevent full screen interruption ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Never peek ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Never make sound and vibration ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎Level 1‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Prevent full screen interruption ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Never peek ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Never make sound or vibrate ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Hide from lock screen and status bar ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Show at the bottom of the notification list ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎Level 0‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎- Block all notifications from the app‎‏‎‎‏‎"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‏‎‏‏‎‏‎‏‎Notifications‎‏‎‎‏‎"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎You won\'t see these notifications anymore‎‏‎‎‏‎"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‎You usually dismiss these notifications. ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Keep showing them?‎‏‎‎‏‎"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‎Keep showing these notifications?‎‏‎‎‏‎"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‎‏‎Stop notifications‎‏‎‎‏‎"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎Keep showing‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 5cc6ab6..2a409a5 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -88,7 +88,7 @@
     <string name="accessibility_home" msgid="8217216074895377641">"Inicio"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menú"</string>
     <string name="accessibility_accessibility_button" msgid="7601252764577607915">"Accesibilidad"</string>
-    <string name="accessibility_rotate_button" msgid="7402949513740253006">"Girar la pantalla"</string>
+    <string name="accessibility_rotate_button" msgid="7402949513740253006">"Girar pantalla"</string>
     <string name="accessibility_recent" msgid="5208608566793607626">"Aplicaciones recientes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Seleccionar diseño de tarea nueva"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icono de huella digital"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icono de aplicación"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área de mensaje de ayuda"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -313,6 +310,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivado"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi activada"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"No hay ninguna red Wi-Fi disponible"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Enviar"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Enviando"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sin nombre"</string>
@@ -329,9 +328,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Compartir conexión"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Activando..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d dispositivos</item>
+      <item quantity="one">%d dispositivo</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificaciones"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Linterna"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Datos móviles"</string>
@@ -341,10 +342,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> usado"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Perfil de trabajo"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Las notificaciones y las aplicaciones están desactivadas"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Al atardecer"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Hasta el amanecer"</string>
@@ -362,8 +361,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"La aplicación <xliff:g id="APP">%s</xliff:g> se ha inhabilitado en modo seguro."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Borrar todo"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Arrastra hasta aquí para utilizar la pantalla dividida"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Desliza el dedo hacia arriba para cambiar de aplicación"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
@@ -504,11 +502,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Desactivar"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Mostrar"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ocultar"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Cambiar dispositivo de salida"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantalla fijada"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsados los botones Atrás y Aplicaciones recientes."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsado el botón Aplicaciones recientes."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendido"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gracias"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Volverá a aparecer la próxima vez que actives esta opción en Ajustes."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
@@ -588,8 +599,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Los controles de energía de las notificaciones permiten establecer un nivel de importancia de 0 a 5 para las notificaciones de las aplicaciones. \n\n"<b>"Nivel 5"</b>" \n- Mostrar en la parte superior de la lista de notificaciones \n- Permitir interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 4"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 3"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n\n"<b>"Nivel 2"</b>" \n- Evitar interrumpir en el modo de pantalla completa\n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n\n"<b>"Nivel 1"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n- Ocultar de la pantalla de bloqueo y de la barra de estado \n- Mostrar en la parte inferior de la lista de notificaciones \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas las notificaciones de la aplicación"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificaciones"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"No volverás a ver estas notificaciones"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Normalmente ignoras estas notificaciones. \n¿Quieres seguir viéndolas?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"¿Quieres seguir viendo estas notificaciones?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Detener las notificaciones"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Seguir mostrando"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 34072db..e7fcb43 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"avaa kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Valitse uusi tehtävien asettelu"</string>
     <string name="cancel" msgid="6442560571259935130">"Peruuta"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Sormenjälkikuvake"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Sovelluskuvake"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Ohjeviestialue"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Yhteensopivuuszoomaus-painike."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoomaa pienemmältä suuremmalle ruudulle."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth yhdistetty."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi-yhteys pois käytöstä"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi on käytössä"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Ei Wi-Fi-verkkoja käytettävissä"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Suoratoisto"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Lähetetään"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nimetön laite"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Yhdistetään…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jaettu yhteys"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Otetaan käyttöön…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d laitetta</item>
+      <item quantity="one">%d laite</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Ilmoitukset"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Taskulamppu"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobiilidata"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"käytetty <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"kiintiö <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> – varoitus"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Työprofiili"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Ilmoitukset ja sovellukset on poistettu käytöstä"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Yövalo"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Auringon laskiessa"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Auringonnousuun"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> on poistettu käytöstä vikasietotilassa."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tyhjennä kaikki"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Jaa näyttö vetämällä tähän."</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Vaihda sovellusta pyyhkäisemällä ylös"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vaakasuuntainen jako"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pystysuuntainen jako"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Muokattu jako"</string>
@@ -502,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Sammuta nyt"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Laajenna."</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tiivistä."</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Vaihda toistolaitetta"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Näyttö on kiinnitetty"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Viimeisimmät."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Viimeisimmät."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Selvä"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ei kiitos"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Piilotetaanko <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Se tulee takaisin näkyviin, kun seuraavan kerran otat sen käyttöön asetuksissa."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Piilota"</string>
@@ -586,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ilmoitusten tehohallinnan avulla voit määrittää sovelluksen ilmoituksille tärkeystason väliltä 0–5. \n\n"<b>"Taso 5"</b>" \n– Ilmoitukset näytetään ilmoitusluettelon yläosassa \n– Näkyminen koko näytön tilassa sallitaan \n– Ilmoitukset kurkistavat aina näytölle\n\n"<b>"Taso 4"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ilmoitukset kurkistavat aina näytölle \n\n"<b>"Taso 3"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n\n"<b>"Taso 2"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n\n"<b>"Taso 1"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n– Ilmoitukset piilotetaan lukitusnäytöltä ja tilapalkista \n– Ilmoitukset näytetään ilmoitusluettelon alaosassa \n\n"<b>"Taso 0"</b>" \n– Kaikki sovelluksen ilmoitukset estetään"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Ilmoitukset"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Et näe näitä ilmoituksia enää"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Hylkäät yleensä nämä ilmoitukset. \nHaluatko, että niitä näytetään myös jatkossa?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Jatketaanko näiden ilmoitusten näyttämistä?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Lopeta ilmoitukset"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Jatka näyttämistä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 16a4eac..56ca97c 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -88,6 +88,7 @@
     <string name="accessibility_home" msgid="8217216074895377641">"Domicile"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
     <string name="accessibility_accessibility_button" msgid="7601252764577607915">"Accessibilité"</string>
+    <string name="accessibility_rotate_button" msgid="7402949513740253006">"Faire pivoter l\'écran"</string>
     <string name="accessibility_recent" msgid="5208608566793607626">"Aperçu"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
@@ -102,6 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"Ouvrir l\'appareil photo"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Sélectionner un nouveau format de tâche"</string>
     <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icône d\'empreinte digitale"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icône de l\'application"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Zone de message d\'aide"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string>
@@ -180,7 +184,8 @@
     <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Sonnerie en mode silencieux"</string>
     <!-- no translation found for accessibility_casting (6887382141726543668) -->
     <skip />
-    <string name="accessibility_work_mode" msgid="2478631941714607225">"Mode Travail"</string>
+    <!-- no translation found for accessibility_work_mode (702887484664647430) -->
+    <skip />
     <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Supprimer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Application \"<xliff:g id="APP">%s</xliff:g>\" ignorée."</string>
     <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Toutes les applications récentes ont été supprimées."</string>
@@ -277,6 +282,10 @@
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"BLUETOOTH DÉSACTIVÉ"</string>
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Aucun des appareils associés n\'est disponible"</string>
+    <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="7106697106764717416">"Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
+    <string name="quick_settings_bluetooth_secondary_label_audio" msgid="5673845963301132071">"Audio"</string>
+    <string name="quick_settings_bluetooth_secondary_label_headset" msgid="1880572731276240588">"Écouteurs"</string>
+    <string name="quick_settings_bluetooth_secondary_label_input" msgid="2173322305072945905">"Entrée"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Luminosité"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotation automatique"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Rotation automatique de l\'écran"</string>
@@ -301,6 +310,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi activé"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Aucun réseau Wi-Fi à proximité"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Diffuser"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Diffusion"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Appareil sans nom"</string>
@@ -317,6 +328,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connexion en cours…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès sans fil"</string>
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Activation en cours…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d appareil</item>
+      <item quantity="other">%d appareils</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifications"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lampe de poche"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Données cellulaires"</string>
@@ -326,8 +342,13 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Quantité de données utilisées :<xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Profil professionnel"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Les notifications et les applications sont désactivées"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éclairage nocturne"</string>
+    <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Au coucher du soleil"</string>
+    <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Jusqu\'au lev. soleil"</string>
+    <string name="quick_settings_night_secondary_label_on_at" msgid="6256314040368487637">"Actif à <xliff:g id="TIME">%s</xliff:g>"</string>
+    <string name="quick_settings_night_secondary_label_until" msgid="8664820079774824618">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_nfc_label" msgid="9012153754816969325">"NFC"</string>
     <string name="quick_settings_nfc_off" msgid="6883274004315134333">"NFC désactivée"</string>
     <string name="quick_settings_nfc_on" msgid="6680317193676884311">"NFC activée"</string>
@@ -340,6 +361,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> est désactivée en mode sans échec."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Effacer tout"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Glissez l\'élément ici pour utiliser l\'écran partagé"</string>
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Balayez vers le haut pour changer d\'application"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
@@ -480,11 +502,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Désactiver maintenant"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Développer"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Réduire"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Changer d\'appareil de sortie"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"L\'écran est épinglé"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Retour » et « Aperçu »."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Aperçu »."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, merci"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Cet élément réapparaîtra la prochaine fois que vous l\'activerez dans les paramètres."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Masquer"</string>
@@ -564,9 +599,10 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Avec les réglages avancés des notifications, vous pouvez définir un degré d\'importance de 0 à 5 pour les notifications d\'une application. \n\n"<b>"Niveau 5"</b>" \n- Afficher dans le haut de la liste des notifications \n- Autoriser les interruptions en mode plein écran \n- Toujours afficher les aperçus \n\n"<b>"Niveau 4"</b>" \n- Empêcher les interruptions en mode plein écran \n- Toujours afficher les aperçus \n\n"<b>"Niveau 3"</b>" \n- Empêcher les interruptions en mode plein écran \n- Ne jamais afficher les aperçus \n\n"<b>"Niveau 2"</b>" \n- Empêcher les interruptions en mode plein écran \n- Ne jamais afficher les aperçus \n- Ne pas autoriser les sons et les vibrations \n\n"<b>"Niveau 1"</b>" \n- Empêcher les interruptions en mode plein écran \n- Ne jamais afficher les aperçus \n- Ne pas autoriser les sons et les vibrations \n- Masquer de l\'écran de verrouillage et de la barre d\'état status bar \n- Afficher dans le bas de la liste des notifications \n\n"<b>"Level 0"</b>" \n- Bloquer toutes les notifications de l\'application"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Vous ne verrez plus ces notifications"</string>
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Vous ignorez habituellement ces notifications. \nSouhaitez-vous continuer à les afficher?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Continuer à afficher ces notifications?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Arrêter les notifications"</string>
-    <string name="inline_keep_button" msgid="6665940297019018232">"Continuez à afficher"</string>
+    <string name="inline_keep_button" msgid="6665940297019018232">"Continuer à afficher"</string>
     <string name="inline_keep_showing_app" msgid="1723113469580031041">"Continuer à afficher les notifications de cette application?"</string>
     <string name="notification_unblockable_desc" msgid="1037434112919403708">"Ces notifications ne peuvent pas être désactivées"</string>
     <string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Les paramètres des notifications pour <xliff:g id="APP_NAME">%1$s</xliff:g> sont ouverts"</string>
@@ -658,7 +694,8 @@
     <item msgid="1545641631806817203">"Presse-papiers"</item>
     <item msgid="5742013440802239414">"Code de touche"</item>
     <item msgid="8802889973626281575">"Sélecteur de clavier"</item>
-    <item msgid="8175437057325747277">"Aucun"</item>
+    <item msgid="7095517796293767867">"Suggestion de rotation"</item>
+    <item msgid="8494159969042135235">"Aucun"</item>
   </string-array>
   <string-array name="nav_bar_layouts">
     <item msgid="8077901629964902399">"Normale"</item>
@@ -782,4 +819,10 @@
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"Touchez pour afficher des détails sur l\'utilisation de la pile et des données"</string>
     <string name="data_usage_disable_mobile" msgid="5116269981510015864">"Désactiver les données cellulaires?"</string>
     <string name="touch_filtered_warning" msgid="8671693809204767551">"Une application obscurcit une demande d\'autorisation, alors Paramètres ne peut pas vérifier votre réponse."</string>
+    <string name="slice_permission_title" msgid="7465009437851044444">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches?"</string>
+    <string name="slice_permission_text_1" msgid="3514586565609596523">"- Il peut lire de l\'information de <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="slice_permission_text_2" msgid="3146758297471143723">"- Il peut effectuer des actions dans <xliff:g id="APP">%1$s</xliff:g>"</string>
+    <string name="slice_permission_checkbox" msgid="7986504458640562900">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à afficher des tranches de n\'importe quelle application"</string>
+    <string name="slice_permission_allow" msgid="2340244901366722709">"Autoriser"</string>
+    <string name="slice_permission_deny" msgid="7683681514008048807">"Refuser"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 27d3ba8..7c530cd 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"કૅમેરો ખોલો"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"નવું કાર્ય લેઆઉટ પસંદ કરો"</string>
     <string name="cancel" msgid="6442560571259935130">"રદ કરો"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ફિંગરપ્રિન્ટનું આઇકન"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ઍપ્લિકેશનનું આઇકન"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"સહાય સંદેશનું ક્ષેત્ર"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"સુસંગતતા ઝૂમ બટન."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"નાનીથી મોટી સ્ક્રીન પર ઝૂમ કરો."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"બ્લૂટૂથ કનેક્ટ થયું."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"વાઇ-ફાઇ બંધ"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"વાઇ-ફાઇ ચાલુ"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"કોઈ વાઇ-ફાઇ નેટવર્ક્સ ઉપલબ્ધ નથી"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"કાસ્ટ કરો"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"કાસ્ટ કરી રહ્યાં છે"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"અનામાંકિત ઉપકરણ"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"કનેક્ટ કરી રહ્યું છે..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ટિથરિંગ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"હૉટસ્પૉટ"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"ચાલુ કરી રહ્યાં છીએ…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d ઉપકરણ</item>
+      <item quantity="other">%d ઉપકરણો</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"નોટિફિકેશનો"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ફ્લેશલાઇટ"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"મોબાઇલ ડેટા"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> વાપર્યો"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> મર્યાદા"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ચેતવણી"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"કાર્યાલયની પ્રોફાઇલ"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"નોટિફિકેશન અને ઍપ બંધ છે"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"રાત્રિ પ્રકાશ"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"સૂર્યાસ્ત વખતે"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"સૂર્યોદય સુધી"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"સુરક્ષિત મોડમાં <xliff:g id="APP">%s</xliff:g> અક્ષમ કરેલ છે."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"બધું સાફ કરો"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"વિભાજિત સ્ક્રીનનો ઉપયોગ કરવા માટે અહીં ખેંચો"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"ઍપ સ્વિચ કરવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"આડું વિભક્ત કરો"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ઊભું વિભક્ત કરો"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"કસ્ટમ વિભક્ત કરો"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"હમણાં બંધ કરો"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"વિસ્તૃત કરો"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"સંકુચિત કરો"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"સ્ક્રીન પિન કરેલ છે"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે પાછળ અને ઝલકને સ્પર્શ કરી રાખો."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે ઝલકને સ્પર્શ કરી રાખો."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"સમજાઈ ગયું"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ના, આભાર"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ને છુપાવીએ?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"તે સેટિંગ્સમાં તમે તેને ચાલુ કરશો ત્યારે આગલી વખતે ફરીથી દેખાશે."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"છુપાવો"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"પાવર સૂચના નિયંત્રણો સાથે, તમે ઍપની સૂચનાઓ માટે 0 થી 5 સુધીના મહત્વના સ્તરને સેટ કરી શકો છો. \n\n"<b>"સ્તર 5"</b>" \n- સૂચના સૂચિની ટોચ પર બતાવો \n- પૂર્ણ સ્ક્રીન અવરોધની મંજૂરી આપો \n- હંમેશાં ત્વરિત દૃષ્ટિ કરો \n\n"<b>"સ્તર 4"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- હંમેશાં ત્વરિત દૃષ્ટિ કરો \n\n"<b>"સ્તર 3"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n\n"<b>"સ્તર 2"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n- ક્યારેય અવાજ અથવા વાઇબ્રેટ કરશો નહીં \n\n"<b>"સ્તર 1"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધની મંજૂરી આપો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n- ક્યારેય અવાજ અથવા વાઇબ્રેટ કરશો નહીં \n- લૉક સ્ક્રીન અને સ્ટેટસ બારથી છુપાવો \n- સૂચના સૂચિના તળિયા પર બતાવો \n\n"<b>"સ્તર 0"</b>" \n- ઍપની તમામ સૂચનાઓને બ્લૉક કરો"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"નોટિફિકેશનો"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"તમને હવેથી આ નોટિફિકેશન દેખાશે નહીં"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"તમે સામાન્ય રીતે આ નોટીફિકેશનને છોડી દો છો. \nતેમને બતાવવાનું ચાલુ રાખીએ?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"આ નોટિફિકેશન બતાવવાનું ચાલુ રાખીએ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"નોટિફિકેશન બંધ કરો"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"બતાવવાનું ચાલુ રાખો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index bb2e897..379d1ab 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"कैमरा खोलें"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"नया कार्य लेआउट चुनें"</string>
     <string name="cancel" msgid="6442560571259935130">"रद्द करें"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"फ़िंगरप्रिंट आइकॉन"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ऐप्लिकेशन आइकॉन"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"सहायता का मैसेज दिखाने की जगह"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्‍क्रीन पर ज़ूम करें."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लूटूथ कनेक्ट किया गया."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाई-फ़ाई  बंद"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"वाई-फ़ाई चालू है"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"कोई भी वाई-फ़ाई नेटवर्क उपलब्‍ध नहीं है"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"कास्ट करें"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"कास्टिंग"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"अनाम डिवाइस"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट हो रहा है..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदरिंग"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हॉटस्पॉट"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"चालू किया जा रहा है..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d डिवाइस</item>
+      <item quantity="other">%d डिवाइस</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"सूचनाएं"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"फ़्लैशलाइट"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"मोबाइल डेटा"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> उपयोग किया गया"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> सीमा"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"कार्य प्रोफ़ाइल"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"सूचनाएं और ऐप्लिकेशन बंद हैं"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"नाइट लाइट"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"शाम को चालू की जाएगी"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"सुबह तक चालू रहेगी"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> को सुरक्षित-मोड में बंद किया गया."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Clear all"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"स्क्रीन के दो हिस्से में बंट जाने, स्पिल्ट स्क्रीन, का इस्तेमाल करने के लिए यहां खींचें और छोडें"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"ऐप्लिकेशन बदलने के लिए ऊपर स्वाइप करें"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज रूप से विभाजित करें"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"लम्बवत रूप से विभाजित करें"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"अपने मुताबिक बांटें"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"अभी बंद करें"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तार करें"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"छोटा करें"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"स्‍क्रीन पिन कर दी गई है"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'खास जानकारी\' को दबाकर रखें."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ठीक है"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"नहीं, रहने दें"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> को छिपाएं?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"जब आप उसे अगली बार सेटिंग में चालू करेंगे तो वह फिर से दिखाई देगी."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"छिपाएं"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"पावर सूचना नियंत्रण के ज़रिये, आप किसी ऐप की सूचना को उसकी अहमियत के हिसाब से 0 से 5 के लेवल पर सेट कर सकते हैं.\n\n"<b>"लेवल 5"</b>" \n- सूचना सूची में सबसे ऊपर दिखाएं \n- पूरे स्क्रीन को ढंकने की अनुमति दें \n- लगातार देखते रहें \n\n"<b>" लेवल 4"</b>" \n- पूरे स्क्रीन को ढंकें \n- लगातार देखते रहें \n\n"<b>"लेवल 3"</b>" \n- पूरे स्क्रीन को ढंकने से रोकें \n-कभी भी न देखें \n\n"<b>"लेवल 2"</b>" \n- पूरे स्क्रीन को ढंकने से रोकें \n- कभी भी देखें \n- कभी भी आवाज़ या कंपन (वाइब्रेशन) न करें \n\n"<b>"लेवल 1"</b>" \n- पूरे स्क्रीन को ढंकने से रोकें \n- कभी भी न देखें \n- कभी भी आवाज़ या कंपन (वाइब्रेशन) न करें \n- लॉक स्क्रीन और स्टेटस बार से छिपाएं \n- सूचना सूची के नीचे दिखाएं \n\n"<b>"लेवल 0"</b>" \n- ऐप्लिकेशन की सभी सूचनाएं रोक दें"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"सूचना"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"अब आपको ये सूचनाएं दिखाई नहीं देंगी"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"अाप अक्सर इन सूचनाओं को खारिज कर देते हैं. \nआगे भी इन्हें देखना जारी रखना चाहते हैं?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ये सूचनाएं दिखाना जारी रखें?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"सूचनाएं दिखाना बंद करें"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"दिखाना जारी रखें"</string>
@@ -807,10 +818,10 @@
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"बैटरी और डेटा खर्च की जानकारी के लिए छूएं"</string>
     <string name="data_usage_disable_mobile" msgid="5116269981510015864">"मोबाइल डेटा बंद करना चाहते हैं?"</string>
     <string name="touch_filtered_warning" msgid="8671693809204767551">"ऐप की वजह से मंज़ूरी के अनुरोध को समझने में दिक्कत हो रही है, इसलिए सेटिंग से आपके जवाब की पुष्टि नहीं हो पा रही है."</string>
-    <string name="slice_permission_title" msgid="7465009437851044444">"<xliff:g id="APP_0">%1$s</xliff:g> को <xliff:g id="APP_2">%2$s</xliff:g> से हिस्से (स्लाइस) दिखाने की मंज़ूरी दें?"</string>
+    <string name="slice_permission_title" msgid="7465009437851044444">"<xliff:g id="APP_0">%1$s</xliff:g> को <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाने की मंज़ूरी दें?"</string>
     <string name="slice_permission_text_1" msgid="3514586565609596523">"- यह <xliff:g id="APP">%1$s</xliff:g> से सूचना पढ़ सकता है"</string>
     <string name="slice_permission_text_2" msgid="3146758297471143723">"- यह <xliff:g id="APP">%1$s</xliff:g> में कार्रवाई कर सकता है"</string>
-    <string name="slice_permission_checkbox" msgid="7986504458640562900">"<xliff:g id="APP">%1$s</xliff:g> को किसी भी ऐप्लिकेशन से हिस्से (स्लाइस) दिखाने की मंज़ूरी दें."</string>
+    <string name="slice_permission_checkbox" msgid="7986504458640562900">"<xliff:g id="APP">%1$s</xliff:g> को किसी भी ऐप्लिकेशन के हिस्से (स्लाइस) दिखाने की मंज़ूरी दें"</string>
     <string name="slice_permission_allow" msgid="2340244901366722709">"मंज़ूरी दें"</string>
     <string name="slice_permission_deny" msgid="7683681514008048807">"नामंज़ूर करें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 880da63..89e9cc1 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"apri fotocamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Seleziona un nuovo layout per le attività"</string>
     <string name="cancel" msgid="6442560571259935130">"Annulla"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona dell\'impronta digitale"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Icona dell\'applicazione"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Area dei messaggi di assistenza"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Pulsante zoom compatibilità."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom inferiore per schermo più grande."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth collegato."</string>
@@ -313,6 +310,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi disattivato"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi attivo"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nessuna rete Wi-Fi disponibile"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Trasmetti"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"In trasmissione"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo senza nome"</string>
@@ -329,9 +328,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Connessione..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Attivazione…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d dispositivi</item>
+      <item quantity="one">%d dispositivo</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifiche"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Torcia"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Dati mobili"</string>
@@ -501,11 +502,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Disattiva ora"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Espandi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Comprimi"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Cambia dispositivo di uscita"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"La schermata è fissata"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Indietro e Panoramica."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Panoramica."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, grazie"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Nascondere <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Verranno visualizzate di nuovo quando le riattiverai nelle impostazioni."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Nascondi"</string>
@@ -585,8 +599,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"I controlli di gestione delle notifiche ti consentono di impostare un livello di importanza compreso tra 0 e 5 per le notifiche di un\'app. \n\n"<b>"Livello 5"</b>" \n- Mostra in cima all\'elenco di notifiche \n- Consenti l\'interruzione a schermo intero \n- Visualizza sempre \n\n"<b>"Livello 4"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Visualizza sempre \n\n"<b>"Livello 3"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n\n"<b>"Livello 2"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n- Non emettere mai suoni e vibrazioni \n\n"<b>"Livello 1"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n- Non emettere mai suoni e vibrazioni \n- Nascondi da schermata di blocco e barra di stato \n- Mostra in fondo all\'elenco di notifiche \n\n"<b>"Livello 0"</b>" \n- Blocca tutte le notifiche dell\'app"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifiche"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Non vedrai più queste notifiche"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"In genere ignori queste notifiche. \nVuoi continuare a riceverle?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Continuare a ricevere queste notifiche?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Interrompi la ricezione di notifiche"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Continua a mostrare"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index a8b3007..4b638f5 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"ಕ್ಯಾಮರಾ ತೆರೆಯಿರಿ"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"ಹೊಸ ಕಾರ್ಯ ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="cancel" msgid="6442560571259935130">"ರದ್ದುಮಾಡಿ"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಐಕಾನ್"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ಅಪ್ಲಿಕೇಶನ್‌ ಐಕಾನ್‌"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"ಸಹಾಯ ಸಂದೇಶ ಪ್ರದೇಶ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ಹೊಂದಾಣಿಕೆಯ ಝೂಮ್ ಬಟನ್."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ಚಿಕ್ಕ ಪರದೆಯಿಂದ ದೊಡ್ಡ ಪರದೆಗೆ ಝೂಮ್ ಮಾಡು."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ಬ್ಲೂಟೂತ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ವೈ-ಫೈ ಆಫ್"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"ವೈ-ಫೈ ಆನ್ ಆಗಿದೆ"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"ಯಾವುದೇ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"ಬಿತ್ತರಿಸುವಿಕೆ"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ಹೆಸರಿಸದಿರುವ ಸಾಧನ"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ಟೆಥರಿಂಗ್‌"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"ಆನ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d ಸಾಧನಗಳು</item>
+      <item quantity="other">%d ಸಾಧನಗಳು</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"ಅಧಿಸೂಚನೆಗಳು"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ಫ್ಲಾಶ್‌ಲೈಟ್‌"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"ಮೊಬೈಲ್ ಡೇಟಾ"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ಬಳಸಲಾಗಿದೆ"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಮಿತಿ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಆಫ್‌ ಆಗಿವೆ"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ನೈಟ್ ಲೈಟ್"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"ಸೂರ್ಯಾಸ್ತದಲ್ಲಿ"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"ಸೂರ್ಯೋದಯದ ತನಕ"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ಅನ್ನು ಸುರಕ್ಷಿತ ಮೋಡ್‌ನಲ್ಲಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"ವಿಭಜಿತ ಪರದೆಯನ್ನು ಬಳಸಲು ಇಲ್ಲಿ ಡ್ರ್ಯಾಗ್‌ ಮಾಡಿ"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ಅಡ್ಡಲಾಗಿ ವಿಭಜಿಸಿದ"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ಲಂಬವಾಗಿ ವಿಭಜಿಸಿದ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ಕಸ್ಟಮ್ ವಿಭಜಿಸಿದ"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"ಈಗ ಆಫ್ ಮಾಡಿ"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ವಿಸ್ತರಿಸು"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ಸಂಕುಚಿಸು"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"ಪರದೆಯನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕಿಸಿ."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕನವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ತಿಳಿಯಿತು"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ಧನ್ಯವಾದಗಳು"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ಮರೆಮಾಡುವುದೇ?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ನೀವು ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಅದನ್ನು ಆನ್ ಮಾಡಿದಾಗ ಅದು ಮರುಕಾಣಿಸಿಕೊಳ್ಳುತ್ತದೆ."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ಮರೆಮಾಡಿ"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ಪವರ್ ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳ ಮೂಲಕ, ನೀವು ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಅಧಿಸೂಚನೆಗಳನ್ನು 0 ರಿಂದ 5 ರವರೆಗಿನ ಹಂತಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಬಹುದು. \n\n"<b>"ಹಂತ 5"</b>" \n- ಮೇಲಿನ ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸಿ \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ಅನುಮತಿಸಿ \n- ಯಾವಾಗಲು ಇಣುಕು ನೋಟ \n\n"<b>"ಹಂತ 4"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಯಾವಾಗಲು ಇಣುಕು ನೋಟ\n\n"<b>"ಹಂತ 3"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n\n"<b>"ಹಂತ 2"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n- ಶಬ್ದ ಮತ್ತು ವೈಬ್ರೇಷನ್ ಎಂದಿಗೂ ಮಾಡಬೇಡಿ \n\n"<b>"ಹಂತ 1"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n- ಶಬ್ದ ಮತ್ತು ವೈಬ್ರೇಷನ್ ಎಂದಿಗೂ ಮಾಡಬೇಡಿ \n- ಸ್ಥಿತಿ ಪಟ್ಟಿ ಮತ್ತು ಲಾಕ್ ಪರದೆಯಿಂದ ಮರೆಮಾಡಿ \n- ಕೆಳಗಿನ ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸಿ \n\n"<b>"ಹಂತ 0"</b>" \n- ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"ಅಧಿಸೂಚನೆಗಳು"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಇನ್ನು ಮುಂದೆ ನೋಡುವುದಿಲ್ಲ"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"ನೀವು ಸಾಮಾನ್ಯವಾಗಿ ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಜಾಗೊಳಿಸಿದ್ದೀರಿ. \nಅವುಗಳನ್ನು ತೋರಿಸುತ್ತಲೇ ಇರಬೇಕೆ?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸುತ್ತಲೇ ಇರಬೇಕೆ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿಲ್ಲಿಸಿ"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"ತೋರಿಸುತ್ತಲಿರಿ"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 338da6c..1b56074 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"ເປີດ​ກ້ອງ"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"ເລືອກ​ແຜນ​ຜັງ​ໜ້າ​ວຽກ​ໃໝ່"</string>
     <string name="cancel" msgid="6442560571259935130">"ຍົກເລີກ"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ໄອຄອນລາຍນິ້ວມື"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ໄອຄອນແອັບພລິເຄຊັນ"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"ຊ່ວຍພື້ນທີ່ຂໍ້ຄວາມ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi​-Fi ປິດ"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi ເປີດ"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"ບໍ່​ມີ​ເຄືອ​ຂ່າຍ Wi-Fi ຢູ່"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"ການສົ່ງສັນຍານ"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"​ກຳ​ລັງ​ສົ່ງ​ສັນ​ຍານ"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"​ອຸ​ປະ​ກອນບໍ່​ມີ​ຊື່"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"ກຳລັງເຊື່ອມຕໍ່..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"​ການ​ປ່ອນ​ສັນ​ຍານ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"​ຮັອດ​ສະ​ປອດ"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"ກຳລັງເປີດ..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d ອຸປະກອນ</item>
+      <item quantity="one">%d ອຸປະກອນ</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"ການແຈ້ງເຕືອນ"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"​ໄຟ​ສາຍ"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"ອິນເຕີເນັດມືຖື"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"ໃຊ້​ໄປ​ແລ້ວ <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"ຈຳ​ກັດ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"ຄຳ​ເຕືອນ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"ການແຈ້ງເຕືອນ ແລະ ແອັບຖືກປິດໄວ້"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ແສງກາງຄືນ"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"ເປີດຕອນຕາເວັນຕົກ"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"ຈົນກວ່າຕາເວັນຂຶ້ນ"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ຖືກປິດໃຊ້ໃນໂໝດຄວາມມປອດໄພ."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ລຶບລ້າງທັງໝົດ"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"ລາກມາບ່ອນນີ້ເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"ປັດຂື້ນເພື່ອສະຫຼັບແອັບ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ການ​ແຍກ​ລວງ​ຂວາງ"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ການ​ແຍກ​ລວງ​ຕັ້ງ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ການ​ແຍກ​ກຳ​ນົດ​ເອງ"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"ປິດດຽວນີ້"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ຂະຫຍາຍ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ຫຍໍ້ລົງ"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"ປັກ​ໝຸດໜ້າ​ຈໍ​ແລ້ວ"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ເຂົ້າໃຈແລ້ວ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ບໍ່, ຂອບໃຈ"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ເຊື່ອງ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ຫຼື​ບໍ່?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"​ມັນ​ຈະ​ສະ​ແດງ​ຄືນ​ໃໝ່​ເມື່ອ​ທ່ານ​ເປີດ​ນຳ​ໃຊ້​ມັນ​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ຄັ້ງ​ຕໍ່​ໄປ."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ເຊື່ອງ"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ດ້ວຍການຄວບຄຸມການແຈ້ງເຕືອນ, ທ່ານສາມາດຕັ້ງລະດັບຄວາມສຳຄັນຈາກ 0 ຮອດ 5 ໃຫ້ກັບການແຈ້ງເຕືອນແອັບໃດໜຶ່ງໄດ້. \n\n"<b>"ລະດັບ 5"</b>" \n- ສະແດງຢູ່ເທິງສຸດຂອງລາຍການແຈ້ງເຕືອນ \n- ອະນຸຍາດໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 4"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 3"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n\n"<b>"ລະດັບ 2"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n\n"<b>"ລະດັບ 1"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n- ເຊື່ອງຈາກໜ້າຈໍລັອກ ແລະ ແຖບສະຖານະ \n- ສະແດງຢູ່ລຸ່ມສຸດຂອງລາຍການແຈ້ງເຕືອນ \n\n"<b>"ລະດັບ 0"</b>" \n- ປິດກັ້ນການແຈ້ງເຕືອນທັງໝົດຈາກແອັບ"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"ການແຈ້ງເຕືອນ"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"ທ່ານຈະບໍ່ໄດ້ຮັບການແຈ້ງເຕືອນເຫຼົ່ານີ້ອີກຕໍ່ໄປ"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"ໂດຍປົກກະຕິທ່ານປິດການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄວ້. \nສືບຕໍ່ສະແດງພວກມັນບໍ?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ຕໍ່ໄປບໍ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"ຢຸດການແຈ້ງເຕືອນ"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"ສະແດງຕໍ່ໄປ"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 9808ab6..07ea7aa 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"отвори камера"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Изберете нов распоред на задача"</string>
     <string name="cancel" msgid="6442560571259935130">"Откажи"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Икона за отпечатоци"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Икона за апликацијата"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Поле за пораки за помош"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Копче за компатибилност на зум."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумот е помал на поголем екран."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е поврзан."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi е исклучено"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Вклучено е Wi-Fi"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Нема достапни Wi-Fi мрежи"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Емитувај"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Емитување"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Неименуван уред"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Се поврзува..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Поврзување"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка на пристап"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Се вклучува…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d уред</item>
+      <item quantity="other">%d уреди</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Известувања"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Светилка"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Мобилен интернет"</string>
@@ -499,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Исклучи сега"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Собери"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Префрлете го излезниот уред"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екранот е прикачен"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Краток преглед“ за откачување."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Сфатив"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, фала"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ќе се појави повторно следниот пат кога ќе го вклучите во поставки."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Сокриј"</string>
@@ -583,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Со контролите за известувањата за напојување, може да поставите ниво на важност од 0 до 5 за известувањата на која било апликација. \n\n"<b>"Ниво 5"</b>" \n- Прикажувај на врвот на списокот со известувања \n- Дозволи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 4"</b>" \n- Спречи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 3"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n\n"<b>"Ниво 2"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n\n"<b>"Ниво 1"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n- Сокриј од заклучен екран и статусна лента \n- Прикажувај на дното на списокот со известувања \n\n"<b>"Ниво 0"</b>" \n- Блокирај ги сите известувања од апликацијата"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Известувања"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Веќе нема да ги гледате овие известувања"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Обично ги отфрлате известувањава. \nДа продолжат да се прикажуваат?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Дали да продолжат да се прикажуваат известувањава?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Запри ги известувањата"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Продолжи да ги прикажуваш"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 446f0e4..d4d6297 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"ക്യാമറ തുറക്കുക"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"പുതിയ ടാസ്‌ക് ലേഔട്ട് തിരഞ്ഞെടുക്കുക"</string>
     <string name="cancel" msgid="6442560571259935130">"റദ്ദാക്കുക"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"വിരലടയാള ഐക്കൺ"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ആപ്പ് ഐക്കൺ"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"സഹായ സന്ദേശ ഏരിയ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"അനുയോജ്യതാ സൂം ബട്ടൺ."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ചെറുതിൽ നിന്ന് വലിയ സ്‌ക്രീനിലേക്ക് സൂം ചെയ്യുക."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ബ്ലൂടൂത്ത് കണക്‌റ്റുചെയ്തു."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"വൈഫൈ ഓഫുചെയ്യുക"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"വൈഫൈ ഓണാണ്"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"വൈഫൈ നെറ്റ്‌വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"കാസ്‌റ്റുചെയ്യുക"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"കാസ്റ്റുചെയ്യുന്നു"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"പേരിടാത്ത ഉപകരണം"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"കണക്റ്റുചെയ്യുന്നു..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ടെതറിംഗ്"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ഹോട്ട്‌സ്‌പോട്ട്"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"ഓൺ ചെയ്യുന്നു..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d ഉപകരണങ്ങൾ</item>
+      <item quantity="one">%d ഉപകരണം</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"അറിയിപ്പുകൾ"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ടോർച്ച്"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"മൊബൈൽ ഡാറ്റ"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ഉപയോഗിച്ചു"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> പരിധി"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> മുന്നറിയിപ്പ്"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"അറിയിപ്പുകളും ആപ്പുകളും ഓഫാണ്"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"നൈറ്റ് ലൈറ്റ്"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"സൂര്യാസ്‌തമയത്തിന്"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"സൂര്യോദയം വരെ"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"സുരക്ഷിത മോഡിൽ <xliff:g id="APP">%s</xliff:g> പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"എല്ലാം മായ്‌ക്കുക"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"സ്പ്ലിറ്റ് സ്ക്രീൻ ഉപയോഗിക്കുന്നതിന് ഇവിടെ വലിച്ചിടുക"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"ആപ്പുകൾ മാറാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"തിരശ്ചീനമായി വേർതിരിക്കുക"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ലംബമായി വേർതിരിക്കുക"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ഇഷ്‌ടാനുസൃതമായി വേർതിരിക്കുക"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"ഇപ്പോൾ ഓഫ് ചെയ്യുക"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"വികസിപ്പിക്കുക"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ചുരുക്കുക"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"സ്‌ക്രീൻ പിൻ ചെയ്‌തു"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ\', \'ചുരുക്കവിവരണം\' എന്നിവ സ്‌പർശിച്ച് പിടിക്കുക."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'ചുരുക്കവിവരണം\' സ്‌പർശിച്ച് പിടിക്കുക."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"മനസ്സിലായി"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"വേണ്ട, നന്ദി"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> എന്നത് മറയ്‌ക്കണോ?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"അടുത്ത തവണ നിങ്ങൾ അത് ക്രമീകരണങ്ങളിൽ ഓണാക്കുമ്പോൾ അത് വീണ്ടും ദൃശ്യമാകും."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"മറയ്‌ക്കുക"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"പവർ അറിയിപ്പ് നിയന്ത്രണം ഉപയോഗിച്ച്, ഒരു ആപ്പിനായുള്ള അറിയിപ്പുകൾക്ക് 0 മുതൽ 5 വരെയുള്ള പ്രാധാന്യ ലെവലുകളിലൊന്ന് നിങ്ങൾക്ക് സജ്ജമാക്കാവുന്നതാണ്. \n\n"<b>"ലെവൽ 5"</b>" \n- അറിയിപ്പ് ലിസ്റ്റിന്റെ മുകളിൽ കാണിക്കുക \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം അനുവദിക്കുക \n- എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക \n\n"<b>"ലെവൽ 4"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക \n\n"<b>"ലെവൽ 3"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും സൃശ്യമാക്കരുത് \n\n"<b>"ലെവൽ 2"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും ദൃശ്യമാക്കരുത് \n- ഒരിക്കലും ശബ്ദവും വൈബ്രേഷനും ഉണ്ടാക്കരുത് \n\n"<b>"ലെവൽ 1"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും ദൃശ്യമാക്കരുത് \n- ഒരിക്കലും ശബ്ദവും വൈബ്രേഷനും ഉണ്ടാക്കരുത് \n- ലോക്ക് സ്ക്രീനിൽ നിന്നും സ്റ്റാറ്റസ് ബാറിൽ നിന്നും മറയ്ക്കുക \n- അറിയിപ്പ് ലിസ്റ്റിന്റെ അടിയിൽ കാണിക്കുക \n\n"<b>"ലെവൽ 0"</b>" \n- ആപ്പിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളും ബ്ലോക്കുചെയ്യുക"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"അറിയിപ്പുകൾ"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"നിങ്ങൾ ഇനി ഈ അറിയിപ്പുകൾ കാണില്ല"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"സാധാരണയായി നിങ്ങൾ ഈ അറിയിപ്പുകൾ നിരാകരിക്കുന്നു. \nഅവ തുടർന്നും കാണിക്കണോ?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ഈ അറിയിപ്പുകൾ തുടർന്നും കാണിക്കണോ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"അറിയിപ്പുകൾ നിർത്തുക"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"തുടർന്നും കാണിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 804e916..c348110 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"कॅमेरा उघडा"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"नवीन कार्य लेआउट निवडा"</string>
     <string name="cancel" msgid="6442560571259935130">"रद्द करा"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"फिंगरप्रिंट आयकन"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"अॅप्लिकेशन आयकन"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"मदत संदेश क्षेत्र"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"सुसंगतता झूम बटण."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"लहानपासून मोठ्‍या स्‍क्रीनवर झूम करा."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लूटूथ कनेक्‍ट केले."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाय-फाय बंद"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"वाय-फाय चालू"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"वाय-फाय नेटवर्क उपलब्‍ध नाहीत"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"कास्‍ट करा"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"कास्ट करत आहे"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"निनावी डिव्हाइस"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट करत आहे..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदरिंग"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हॉटस्पॉट"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"चालू करत आहे…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d डिव्हाइस</item>
+      <item quantity="other">%d डिव्हाइस</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"सूचना"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"फ्लॅशलाइट"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"मोबाइल डेटा"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> वापरले"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> मर्यादा"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"कार्य प्रोफाइल"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"सूचना आणि अ‍ॅप्स बंद आहेत"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"रात्रीचा प्रकाश"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"संध्याकाळी चालू असते"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"सूर्योदयापर्यंत"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> सुरक्षित-मोडमध्ये अक्षम केला आहे."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"सर्व साफ करा"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"विभाजित स्क्रीन वापर करण्यासाठी येथे ड्रॅग करा"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"अ‍ॅप्स स्विच करण्यासाठी वर स्वाइप करा"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज विभाजित करा"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"अनुलंब विभाजित करा"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"सानुकूल विभाजित करा"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"आता बंद करा"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तृत करा"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संकुचित करा"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"स्क्रीन पिन केलेली आहे"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"आपण अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"आपण अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"समजले"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"नाही, नको"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> लपवायचे?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"आपण सेटिंग्जमध्ये ते पुढील वेळी चालू कराल तेव्हा ते पुन्हा दिसेल."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"लपवा"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"पॉवर सूचना नियंत्रणांच्या साहाय्याने तुम्ही अॅप सूचनांसाठी 0 ते 5 असे महत्त्व स्तर सेट करू शकता. \n\n"<b>"स्तर 5"</b>" \n- सूचना सूचीच्या शीर्षस्थानी दाखवा \n- पूर्ण स्क्रीन व्यत्ययास अनुमती द्या \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 4"</b>\n" - पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 3"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n\n"<b>"स्तर 2"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा कंपन करू नका \n\n"<b>"स्तर 1"</b>\n"- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा कंपन करू नका \n- लॉक स्क्रीन आणि स्टेटस बार मधून लपवा \n- सूचना सूचीच्या तळाशी दर्शवा \n\n"<b>"स्तर 0"</b>" \n- अॅपमधील सर्व सूचना ब्लॉक करा"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"सूचना"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"आता तुम्हाला या सूचना दिसणार नाहीत"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"तुम्ही या सूचना सामान्यतः डिसमिस करता. \nते दाखवत राहायचे?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"या सूचना दाखवणे सुरू ठेवायचे?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"सूचना थांबवा"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"दाखवणे सुरू ठेवा"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 972f4ee..41f28e2 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"ကင်မရာ ဖွင့်ရန်"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"အလုပ်သစ်စီစဥ်မှုကို ရွေးပါ။"</string>
     <string name="cancel" msgid="6442560571259935130">"မလုပ်တော့"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"လက်ဗွေ သင်္ကေတ"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"အပလီကေးရှင်း သင်္ကေတ"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"အကူအညီမက်ဆေ့ဂျ် နေရာ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"အံဝင်ခွင်ကျ ဇူးမ်ခလုတ်"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ဖန်သားပြင်ပေါ်တွင် အသေးမှအကြီးသို့ ဇူးမ်ဆွဲခြင်း"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ဝိုင်ဖိုင်ပိတ်ရန်"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi ကိုဖွင့်ပါ"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Wi-Fi ကွန်ရက် မရှိပါ"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"ကာစ်တင်"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"အမည်မတပ် ကိရိယာ"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"ဆက်သွယ်နေ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"တွဲချီပေးခြင်း"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ဟော့စပေါ့"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"ဖွင့်နေသည်..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">စက် %d ခု</item>
+      <item quantity="one">စက် %d ခု</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"အကြောင်းကြားချက်များ"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ဖလက်ရှ်မီး"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"မိုဘိုင်းဒေတာ"</string>
@@ -499,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"ပိတ်ရန်"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"တိုးချဲ့ရန်"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ခေါက်သိမ်းရန်..."</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"အထွက် စက်ပစ္စည်းကို ပြောင်းပါ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"မျက်နှာပြင် ပင်ထိုးပြီးပါပြီ"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"သင်ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် Back နှင့် Overview ကို ထိ၍ဖိထားပါ။"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"သင်ပင်မဖြုတ်မချင်း ၎င်းကိုပြသထားပါမည်။ ပင်ဖြုတ်ရန် Overview ကိုထိပြီး ဖိထားပါ။"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ရပါပြီ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"မလိုတော့ပါ"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ဝှက်မည်လား?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"နောက်တစ်ကြိမ်သင် ချိန်ညှိချက်များဖွင့်လျှင် ၎င်းပေါ်လာပါမည်။"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ဖျောက်ထားမည်"</string>
@@ -583,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ပါဝါအကြောင်းကြားချက် ထိန်းချုပ်မှုများကိုအသုံးပြုပြီး အက်ပ်တစ်ခု၏ အကြောင်းကြားချက် အရေးပါမှု ၀ မှ ၅ အထိသတ်မှတ်ပေးနိုင်သည်။ \n\n"<b>"အဆင့် ၅"</b>" \n- အကြောင်းကြားချက်စာရင်း၏ ထိပ်ဆုံးတွင် ပြသည် \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်းကို ခွင့်ပြုသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၄"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၃"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n\n"<b>"အဆင့် ၂"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n\n"<b>"အဆင့် ၁"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n- လော့ခ်ချထားသည့် မျက်နှာပြင်နှင့် အခြေအနေဘားတန်းတို့တွင် မပြပါ \n- အကြောင်းကြားချက်စာရင်း အောက်ဆုံးတွင်ပြသည် \n\n"<b>"အဆင့် ၀"</b>" \n- အက်ပ်မှ အကြောင်းကြားချက်များ အားလုံးကို ပိတ်ဆို့သည်"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"အကြောင်းကြားချက်များ"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"ဤအကြောင်းကြားချက်များကို မြင်ရတော့မည် မဟုတ်ပါ"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"သင်သည် အများအားဖြင့် ဤအကြောင်းကြားချက်များကို ပယ်လေ့ရှိပါသည်။ \n၎င်းတို့ကို ဆက်လက်ပြသလိုပါသလား။"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ဤအကြောင်းကြားချက်များကို ဆက်ပြလိုပါသလား။"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"အကြောင်းကြားချက်များကို ရပ်ရန်"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"ဆက်ပြရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index d4d6160..5bd4f2e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"åpne kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Velg en ny utforming for oppgaver"</string>
     <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ikon for fingeravtrykk"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Appikon"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Område for hjelpemelding"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoomknapp for kompatibilitet."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom fra mindre til større skjerm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth er tilkoblet."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi er av"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi er på"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Ingen tilgjengelige Wi-Fi-nettverk"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Casting"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Enhet uten navn"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Kobler til …"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internettdeling"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Wi-Fi-sone"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Slår på …"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d enheter</item>
+      <item quantity="one">%d enhet</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Varsler"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lommelykt"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobildata"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> brukt"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Grense på <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel for <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Jobbprofil"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Varsler og apper er slått av"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattlys"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"På ved solnedgang"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Til soloppgang"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> er slått av i sikker modus."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tøm alt"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Dra hit for å bruke delt skjerm"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Sveip opp for å bytte apper"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Del horisontalt"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Del vertikalt"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Del tilpasset"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Slå av nå"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utvid"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skjermen er låst"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Tilbake og Oversikt for å løsne den."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Oversikt for å løsne den."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Skjønner"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei takk"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Den vises igjen neste gang du slår den på i innstillingene."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Skjul"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Med effektive varselinnstillinger kan du angi viktighetsnivåer fra 0 til 5 for appvarsler. \n\n"<b>"Nivå 5"</b>" \n– Vis øverst på varsellisten \n– Tillat forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 4"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 3"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n\n"<b>"Nivå 2"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri fort \n– Tillat aldri lyder eller vibrering \n\n"<b>"Nivå 1"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n– Tillat aldri lyder eller vibrering \n– Skjul fra låseskjermen og statusfeltet \n– Vis nederst på varsellisten \n\n"<b>"Nivå 0"</b>" \n– Blokkér alle varsler fra appen"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Varsler"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Du ser ikke disse varslene lenger"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Du avviser vanligvis disse varslene. \nVil du fortsette å vise dem?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsette å vise disse varslene?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Stopp varsler"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Fortsett å vise"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index e3efe1b..ca81f44 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -41,7 +41,7 @@
     <string name="invalid_charger" msgid="4549105996740522523">"USB चार्ज गर्न समर्थित छैन।\n आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्ज समर्थित छैन।"</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"आपूर्ति गरिएको चार्जर मात्र प्रयोग गर्नुहोस्।"</string>
-    <string name="battery_low_why" msgid="4553600287639198111">"सेटिङ्हरू"</string>
+    <string name="battery_low_why" msgid="4553600287639198111">"सेटिङहरू"</string>
     <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ब्याट्री सेभर सक्रिय गर्ने हो?"</string>
     <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"खोल्नुहोस्"</string>
     <string name="battery_saver_start_action" msgid="8187820911065797519">"ब्याट्री सेभर सक्रिय गर्नुहोस्"</string>
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"क्यामेरा खोल्नुहोस्"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"नयाँ कार्य लेआउट चयन गर्नुहोस्"</string>
     <string name="cancel" msgid="6442560571259935130">"रद्द गर्नुहोस्"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"फिंगरप्रिन्ट जनाउने आइकन"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"अनुप्रयोग जनाउने आइकन"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"मद्दतसम्बन्धी सन्देशको क्षेत्र"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"मिलाउने जुम बटन।"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"स्क्रिनलाई सानोबाट ठूलो पार्नुहोस्।"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लुटुथ जडान भयो।"</string>
@@ -264,8 +261,8 @@
       <item quantity="other">भित्र थप <xliff:g id="NUMBER_1">%s</xliff:g> सूचनाहरू छन्।</item>
       <item quantity="one">भित्र थप <xliff:g id="NUMBER_0">%s</xliff:g> सूचना छ।</item>
     </plurals>
-    <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"अधिसूचना सेटिङ्हरू"</string>
-    <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिङ्हरू"</string>
+    <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"अधिसूचना सेटिङहरू"</string>
+    <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> सेटिङहरू"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्क्रिन स्वतः घुम्ने छ।"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"स्क्रिनलाई ल्यान्डस्केप अवस्थामा बन्द गरिएको छ।"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"स्क्रिन पोर्टेट अभिमूखमा लक गरिएको छ।"</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi बन्द"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi सक्रिय छ"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Wi-Fi नेटवर्क अनुपलब्ध"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"प्रसारण गर्दै"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"बेनाम उपकरण"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"जडान हुँदै..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदर गर्दै"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हटस्पट"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"सक्रिय गर्दै…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d यन्त्रहरू</item>
+      <item quantity="one">%d यन्त्र</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"अधिसूचनाहरू"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"फ्ल्यासलाइट"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"मोबाइल डेटा"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> प्रयोग गरियो"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> सीमा"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी दिँदै"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"कार्य प्रोफाइल"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"सूचना तथा अनुप्रयोगहरू निष्क्रिय छन्‌"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"रात्रिको प्रकाश"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"सूर्यास्तमा सक्रिय"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"सूर्योदयसम्म"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> लाई सुरक्षित-मोडमा असक्षम गरिएको छ।"</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"सबै हटाउनुहोस्"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"विभाजित स्क्रिनको प्रयोग गर्नका लागि यहाँ तान्नुहोस्"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"अनुप्रयोगहरू बदल्न माथितिर स्वाइप गर्नुहोस्"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"तेर्सो रूपमा विभाजन गर्नुहोस्"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ठाडो रूपमा विभाजन गर्नुहोस्"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"आफू अनुकूल विभाजन गर्नुहोस्"</string>
@@ -376,11 +374,11 @@
     <string name="description_target_search" msgid="3091587249776033139">"खोज्नुहोस्"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>को लागि माथि धिसार्नुहोस्"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"स्लाइड <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>को लागि बायाँ।"</string>
-    <string name="zen_priority_introduction" msgid="1149025108714420281">"तपाईंलाई अलार्म, रिमाइन्डर, कार्यक्रम र तपाईंले निर्दिष्ट गर्नुभएका कलरहरू बाहेकका ध्वनि र कम्पनहरूले बाधा पुऱ्याउने छैनन्। तपाईंले अझै संगीत, भिडियो र खेलहरू लगायत आफूले प्ले गर्न छनौट गरेका जुनसुकै कुरा सुन्न सक्नुहुनेछ।"</string>
-    <string name="zen_alarms_introduction" msgid="4934328096749380201">"तपाईंलाई अलार्महरू बाहेकका ध्वनि र कम्पनहरूले बाधा पुऱ्याउने छैनन्। तपाईंले अझै संगीत, भिडियो र खेलहरू लगायत आफूले प्ले गर्न छनौट गरेका जुनसुकै कुरा सुन्न सक्नुहुनेछ।"</string>
+    <string name="zen_priority_introduction" msgid="1149025108714420281">"तपाईंलाई अलार्म, रिमाइन्डर, कार्यक्रम र तपाईंले निर्दिष्ट गर्नुभएका कलरहरू बाहेकका ध्वनि र कम्पनहरूले बाधा पुऱ्याउने छैनन्। तपाईंले अझै सङ्गीत, भिडियो र खेलहरू लगायत आफूले प्ले गर्न छनौट गरेका जुनसुकै कुरा सुन्न सक्नुहुनेछ।"</string>
+    <string name="zen_alarms_introduction" msgid="4934328096749380201">"तपाईंलाई अलार्महरू बाहेकका ध्वनि र कम्पनहरूले बाधा पुऱ्याउने छैनन्। तपाईंले अझै सङ्गीत, भिडियो र खेलहरू लगायत आफूले प्ले गर्न छनौट गरेका जुनसुकै कुरा सुन्न सक्नुहुनेछ।"</string>
     <string name="zen_priority_customize_button" msgid="7948043278226955063">"आफू अनुकूल बनाउनुहोस्"</string>
-    <string name="zen_silence_introduction_voice" msgid="3948778066295728085">"यसले अलार्म, संगीत, भिडियो, र खेलहरू लगायत सबैका ध्वनि र कम्पनहरूमाथि रोक लगाउँछ। तपाईं अझै पनि फोन कलहरू गर्न सक्नुहुनेछ।"</string>
-    <string name="zen_silence_introduction" msgid="3137882381093271568">"यसले अलार्म, संगीत, भिडियोहरू र खेलहरूसहित सबै ध्वनिहरू र कम्पनहरूलाई रोक्छ।"</string>
+    <string name="zen_silence_introduction_voice" msgid="3948778066295728085">"यसले अलार्म, सङ्गीत, भिडियो, र खेलहरू लगायत सबैका ध्वनि र कम्पनहरूमाथि रोक लगाउँछ। तपाईं अझै पनि फोन कलहरू गर्न सक्नुहुनेछ।"</string>
+    <string name="zen_silence_introduction" msgid="3137882381093271568">"यसले अलार्म, सङ्गीत, भिडियोहरू र खेलहरूसहित सबै ध्वनिहरू र कम्पनहरूलाई रोक्छ।"</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"तल कम जरुरी सूचनाहरू"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"खोल्न पुनः ट्याप गर्नुहोस्"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"अहिले नै निष्क्रिय पार्नुहोस्"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तार गर्नुहोस्"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संक्षिप्त पार्नुहोस्"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"पर्दा राखेका छ"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"बुझेँ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"धन्यवाद पर्दैन"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"लुकाउनुहुन्छ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"यो तपाईं सेटिङ् मा यो बारी अर्को समय देखापर्नेछ।"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"लुकाउनुहोस्"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"सशक्त सूचना नियन्त्रणहरू मार्फत तपाईं अनुप्रयाेगका सूचनाहरूका लागि ० देखि ५ सम्मको महत्व सम्बन्धी स्तर सेट गर्न सक्नुहुन्छ। \n\n"<b>"स्तर ५"</b>" \n- सूचनाको सूचीको माथिल्लो भागमा देखाउने \n- पूर्ण स्क्रिनमा अवरोधका लागि अनुमति दिने \n- सधैँ चियाउने \n\n"<b>"स्तर ४"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- सधैँ चियाउने \n\n"<b>"स्तर ३"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n\n"<b>"स्तर २"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने र कम्पन नगर्ने \n\n"<b>"स्तर १"</b>" \n- पूर्ण स्क्रिनमा अवरोध रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने वा कम्पन नगर्ने \n- लक स्क्रिन र वस्तुस्थिति पट्टीबाट लुकाउने \n- सूचनाको सूचीको तल्लो भागमा देखाउने \n\n"<b>"स्तर ०"</b>" \n- अनुप्रयोगका सबै सूचनाहरूलाई रोक्ने"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"सूचनाहरू"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"तपाईं अब उप्रान्त यी सूचनाहरू देख्नु हुने छैन"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"तपाईं सामान्यतया यी सूचनाहरूलाई खारेज गर्ने गर्नुहुन्छ। \nतिनलाई देखाइरहने हो?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"यी सूचनाहरू देखाउने क्रम जारी राख्ने हो?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"सूचनाहरू देखाउन छाड्नुहोस्"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"देखाउने क्रम जारी राख्नुहोस्"</string>
@@ -656,7 +667,7 @@
     <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"सम्पर्कहरू"</string>
     <string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"इमेल"</string>
     <string name="keyboard_shortcut_group_applications_sms" msgid="638701213803242744">"SMS"</string>
-    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"संगीत"</string>
+    <string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"सङ्गीत"</string>
     <string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
     <string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"पात्रो"</string>
     <string name="tuner_full_zen_title" msgid="4540823317772234308">"भोल्युम नियन्त्रणसहित देखाउनुहोस्"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 4e39106..9308fee 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"ਕੈਮਰਾ ਖੋਲ੍ਹੋ"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"ਨਵਾਂ ਕੰਮ ਲੇਆਉਟ ਚੁਣੋ"</string>
     <string name="cancel" msgid="6442560571259935130">"ਰੱਦ ਕਰੋ"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਪ੍ਰਤੀਕ"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ਐਪਲੀਕੇਸ਼ਨ ਦਾ ਪ੍ਰਤੀਕ"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"ਮਦਦ ਸੁਨੇਹਾ ਖੇਤਰ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ਅਨੁਰੂਪਤਾ ਜ਼ੂਮ ਬਟਨ।"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ਵੱਡੀ ਸਕ੍ਰੀਨ ਤੇ ਛੋਟਾ ਜ਼ੂਮ ਕਰੋ।"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ਕਨੈਕਟ ਕੀਤੀ।"</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ਵਾਈ-ਫਾਈ ਬੰਦ"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"ਵਾਈ-ਫਾਈ ਚਾਲੂ"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"ਕੋਈ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"ਕਾਸਟ"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"ਕਾਸਟਿੰਗ"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ਬਿਨਾਂ ਨਾਮ ਦਾ ਡੀਵਾਈਸ"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ਟੈਦਰਿੰਗ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ਹੌਟਸਪੌਟ"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"ਚਾਲੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d ਡੀਵਾਈਸ</item>
+      <item quantity="other">%d ਡੀਵਾਈਸਾਂ</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"ਸੂਚਨਾਵਾਂ"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ਫਲੈਸ਼ਲਾਈਟ"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"ਮੋਬਾਈਲ ਡਾਟਾ"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ਵਰਤਿਆ"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਸੀਮਾ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"ਸੂਚਨਾਵਾਂ ਅਤੇ ਐਪਾਂ ਬੰਦ ਹਨ"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ਰਾਤਰੀ ਲਾਈਟ"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"ਸੂਰਜ ਛਿਪਣ \'ਤੇ ਚਾਲੂ"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"ਸੂਰਜ ਚੜ੍ਹਨ ਤੱਕ"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਸੁਰੱਖਿਅਤ-ਮੋਡ ਵਿੱਚ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ।"</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਇੱਥੇ ਘਸੀਟੋ"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ਹੌਰੀਜ਼ੌਂਟਲ ਸਪਲਿਟ"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ਵਰਟੀਕਲ ਸਪਲਿਟ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ਵਿਉਂਂਤੀ ਸਪਲਿਟ"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"ਹੁਣੇ ਬੰਦ ਕਰੋ"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ਨਸ਼ਟ ਕਰੋ"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"ਸਕ੍ਰੀਨ ਪਿੰਨ ਕੀਤੀ"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਅਤੇ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ਸਮਝ ਲਿਆ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ਕੀ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ਨੂੰ ਲੁਕਾਉਣਾ ਹੈ?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ਇਹ ਅਗਲੀ ਵਾਰ ਮੁੜ ਪ੍ਰਗਟ ਹੋਵੇਗਾ ਜਦੋਂ ਤੁਸੀਂ ਇਸਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਾਲੂ ਕਰਦੇ ਹੋ।"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ਲੁਕਾਓ"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ਪਾਵਰ ਸੂਚਨਾ ਕੰਟਰੋਲਾਂ ਨਾਲ, ਤੁਸੀਂ ਕਿਸੇ ਐਪ ਦੀਆਂ ਸੂਚਨਾਵਾਂ ਲਈ ਮਹੱਤਤਾ ਪੱਧਰ ਨੂੰ 0 ਤੋਂ 5 ਤੱਕ ਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ। \n\n"<b>"ਪੱਧਰ 5"</b>" \n- ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਦਿਖਾਓ \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਦੀ ਆਗਿਆ ਦਿਓ \n- ਹਮੇਸ਼ਾਂ ਝਲਕ ਦਿਖਾਓ \n\n"<b>"ਪੱਧਰ 4"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਹਮੇਸ਼ਾਂ ਝਲਕ ਦਿਖਾਓ \n\n"<b>"ਪੱਧਰ 3"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਦਿਖਾਓ \n\n"<b>"ਪੱਧਰ 2"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਦਿਖਾਓ \n- ਕਦੇ ਵੀ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਾ ਕਰੋ \n\n"<b>"ਪੱਧਰ 1"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਦਿਖਾਓ \n- ਕਦੇ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਾ ਕਰੋ \n- ਲਾਕ ਸਕ੍ਰੀਨ ਅਤੇ ਸਥਿਤੀ ਪੱਟੀ ਤੋਂ ਲੁਕਾਓ \n- ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਦਿਖਾਓ \n\n"<b>"ਪੱਧਰ 0"</b>" \n- ਐਪ ਤੋਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬਲਾਕ ਕਰੋ"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"ਸੂਚਨਾਵਾਂ"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"ਤੁਹਾਨੂੰ ਹੁਣ ਇਹ ਸੂਚਨਾਵਾਂ ਦਿਖਾਈ ਨਹੀਂ ਦੇਣਗੀਆਂ"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਆਮ ਤੌਰ \'ਤੇ ਖਾਰਜ ਕਰਦੇ ਹੋ। \nਕੀ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਦਿਖਾਉਣਾ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ਕੀ ਇਨ੍ਹਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਦਿਖਾਉਣਾ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"ਸੂਚਨਾਵਾਂ ਬੰਦ ਕਰੋ"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"ਦਿਖਾਉਣਾ ਜਾਰੀ ਰੱਖੋ"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 3472d1d..982b8b7 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir câmera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selecionar novo layout da tarefa"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícone de impressão digital"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ícone do app"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área da mensagem de ajuda"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado."</string>
@@ -313,6 +310,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desligado"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi ativado"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nenhuma rede Wi-Fi disponível"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Transmitir"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Transmitindo"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sem nome"</string>
@@ -329,9 +328,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ponto de acesso"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Ativando…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d dispositivo</item>
+      <item quantity="other">%d dispositivos</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificações"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lanterna"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Dados móveis"</string>
@@ -501,11 +502,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Desativar agora"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Alterar dispositivo de saída"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ela reaparecerá na próxima vez que você ativá-la nas configurações."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
@@ -585,8 +599,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Você deixará de ver essas notificações"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Geralmente você dispensa essas notificações. \nQuer que elas continuem a ser exibidas?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Continuar mostrando essas notificações?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Bloquear notificações"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Continuar mostrando"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a631fcc..2bc1c03 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir câmara"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selecionar novo esquema de tarefa"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícone de impressão digital"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ícone de aplicação"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área da mensagem de ajuda"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão zoom de compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom menor para ecrã maior."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ligado."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Desligado"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi ligado"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Não estão disponíveis redes Wi-Fi"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Transmitir"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Transmissão"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sem nome"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"A ligar..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Associação"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"A ativar…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d dispositivos</item>
+      <item quantity="one">%d dispositivo</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificações"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lanterna"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Dados móveis"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> utilizado(s)"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Perfil de trabalho"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"As notificações e as aplicações estão desativadas"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz noturna"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Ativ. ao pôr-do-sol"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Até ao nascer do sol"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"O <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Limpar tudo"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Arraste aqui para utilizar o ecrã dividido"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Deslizar rapidamente para cima para mudar de aplicação"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
@@ -502,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Desativar agora"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Reduzir"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Mudar de dispositivo de saída"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"O ecrã está fixado"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Vista geral para soltar."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Vista geral para soltar."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Compreendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Pretende ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Reaparecerá da próxima vez que a funcionalidade for ativada nas definições."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
@@ -586,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Com os controlos de notificações do consumo de energia, pode definir um nível de importância de 0 a 5 para as notificações de aplicações. \n\n"<b>"Nível 5"</b>" \n- Mostrar no início da lista de notificações \n- Permitir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre \n\n"<b>"Nível 4"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre\n\n"<b>"Nível 3"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n\n"<b>"Nível 2"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n- Ocultar do ecrã de bloqueio e da barra de estado \n- Mostrar no fim da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações da aplicação"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Nunca mais verá estas notificações."</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Normalmente, ignora estas notificações. \nPretende continuar a mostrá-las?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Pretende continuar a ver estas notificações?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Parar notificações"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Continuar a mostrar"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 3472d1d..982b8b7 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"abrir câmera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selecionar novo layout da tarefa"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Ícone de impressão digital"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ícone do app"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Área da mensagem de ajuda"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado."</string>
@@ -313,6 +310,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desligado"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi ativado"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nenhuma rede Wi-Fi disponível"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Transmitir"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Transmitindo"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sem nome"</string>
@@ -329,9 +328,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ponto de acesso"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Ativando…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d dispositivo</item>
+      <item quantity="other">%d dispositivos</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificações"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lanterna"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Dados móveis"</string>
@@ -501,11 +502,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Desativar agora"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Alterar dispositivo de saída"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ela reaparecerá na próxima vez que você ativá-la nas configurações."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
@@ -585,8 +599,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Você deixará de ver essas notificações"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Geralmente você dispensa essas notificações. \nQuer que elas continuem a ser exibidas?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Continuar mostrando essas notificações?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Bloquear notificações"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Continuar mostrando"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 58b6b75..d765282 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -104,12 +104,9 @@
     <string name="camera_label" msgid="7261107956054836961">"deschideți camera foto"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Selectați noul aspect pentru activitate"</string>
     <string name="cancel" msgid="6442560571259935130">"Anulați"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Pictograma amprentă"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Pictograma aplicației"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Zona mesajelor de ajutor"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceți zoom de la o imagine mai mică la una mai mare."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Conectat prin Bluetooth."</string>
@@ -315,6 +312,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi deconectat"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi activat"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nicio rețea Wi-Fi disponibilă"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Proiectați"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Se proiectează"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispozitiv nedenumit"</string>
@@ -331,9 +330,12 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Se conectează..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Se activează..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="few">%d dispozitive</item>
+      <item quantity="other">%d de dispozitive</item>
+      <item quantity="one">%d dispozitiv</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificări"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lanternă"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Date mobile"</string>
@@ -503,11 +505,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Dezactivați acum"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Extindeți"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Restrângeți"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Comutați dispozitivul de ieșire"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ecranul este fixat"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Recente pentru a anula fixarea."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Recente pentru a anula fixarea."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Am înțeles"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nu, mulțumesc"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ascundeți <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Va reapărea la următoarea activare în setări."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ascundeți"</string>
@@ -587,8 +602,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Folosind comenzile de gestionare a notificărilor, puteți să setați un nivel de importanță de la 0 la 5 pentru notificările unei aplicații. \n\n"<b>"Nivelul 5"</b>" \n– Se afișează la începutul listei de notificări \n– Se permite întreruperea pe ecranul complet \n– Se afișează întotdeauna scurt \n\n"<b>"Nivelul 4"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Se afișează întotdeauna scurt \n\n"<b>"Nivelul 3"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n\n"<b>"Nivelul 2"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n– Nu se emit sunete și nu vibrează niciodată \n\n"<b>"Nivelul 1"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n– Nu se emit sunete și nu vibrează niciodată \n– Se ascunde în ecranul de blocare și în bara de stare \n– Se afișează la finalul listei de notificări \n\n"<b>"Nivelul 0"</b>" \n– Se blochează toate notificările din aplicație"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificări"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Nu veți mai vedea aceste notificări"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"De regulă respingeți aceste notificări. \nDoriți să fie afișate în continuare?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Doriți să continuați afișarea acestor notificări?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Opriți notificările"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Continuați afișarea"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 3bda5eb..9cd9082 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -105,12 +105,9 @@
     <string name="camera_label" msgid="7261107956054836961">"Открыть камеру."</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Выберите другой макет"</string>
     <string name="cancel" msgid="6442560571259935130">"Отмена"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Значок отпечатка пальца"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Значок приложения"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Справочное сообщение"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-соединение установлено."</string>
@@ -317,6 +314,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi выкл."</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi включен"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Не удалось найти доступные сети Wi-Fi"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Трансляция"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Передача изображения"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Безымянное устройство"</string>
@@ -333,9 +332,13 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Соединение..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Режим модема"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка доступа"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Подождите…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d устройство</item>
+      <item quantity="few">%d устройства</item>
+      <item quantity="many">%d устройств</item>
+      <item quantity="other">%d устройства</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Уведомления"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Фонарик"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Мобильный Интернет"</string>
@@ -345,10 +348,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Использовано: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ограничение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Рабочий профиль"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Уведомления и приложения отключены"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ночной режим"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Включить на закате"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"До рассвета"</string>
@@ -366,8 +367,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" отключено в безопасном режиме."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Очистить все"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Перетащите сюда, чтобы разделить экран"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Чтобы переключиться между приложениями, проведите по экрану вверх."</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Разделить по горизонтали"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Разделить по вертикали"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Разделить по-другому"</string>
@@ -508,11 +508,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Отключить"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Развернуть"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Свернуть"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Сменить устройство аудиовыхода"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Блокировка в приложении включена"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Обзор\"."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопку \"Обзор\"."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ОК"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Нет, спасибо"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Скрыть параметр \"<xliff:g id="TILE_LABEL">%1$s</xliff:g>\"?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Этот параметр появится в следующий раз, когда вы включите его."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Скрыть"</string>
@@ -592,8 +605,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"С помощью этой функции вы можете устанавливать уровень важности уведомлений от 0 до 5 для каждого приложения.\n\n"<b>"Уровень 5"</b>\n"‒ Помещать уведомления в начало списка.\n‒ Показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 4\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 3\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\nУровень 2\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\nУровень 1\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\n‒ Не показывать на экране блокировки и в строке состояния.\n‒ Помещать уведомления в конец списка.\nУровень 0\n"<b></b>\n"‒ Блокировать все уведомления приложения."</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Уведомления"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Вы больше не будете получать эти уведомления."</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Обычно вы скрываете эти уведомления.\nПоказывать их?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Показывать эти уведомления?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Отключить уведомления"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Показывать"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 8c9208b..b041d48 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"කැමරාව විවෘත කරන්න"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"නව කාර්යය සැකැස්ම තෝරන්න"</string>
     <string name="cancel" msgid="6442560571259935130">"අවලංගු කරන්න"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"ඇඟිලි සලකුණු නිරූපකය"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"යෙදුම් නිරූපකය"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"උදවු පණිවිඩ ප්‍රදේශය"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ගැළපෙන විශාලන බොත්තම."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"විශාල තිරය වෙත කුඩාව විශාලනය කරන්න."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"බ්ලූටූත් සම්බන්ධිතයි."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi අක්‍රියයි"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi ක්‍රියාත්මකයි"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Wi-Fi ජාල ලබා ගත නොහැකිය"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"කාස්ට් කිරීම"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"නම් නොකළ උපාංගය"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"සම්බන්ධ වෙමින්..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ටෙදරින්"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"හොට්ස්පොට්"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"ක්‍රියාත්මක කරමින්…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">උපාංග %d</item>
+      <item quantity="other">උපාංග %d</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"දැනුම්දීම්"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"සැණෙළි ආලෝකය"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"ජංගම දත්ත"</string>
@@ -499,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"දැන් ක්‍රියාවිරහිත කරන්න"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"දිග හරින්න"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"හකුළන්න"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"ප්‍රතිදාන උපාංගය මාරු කරන්න"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"තීරය අමුණන ලදි"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"මෙය ඔබ ගලවන තෙක් එය දසුන තුළ තබයි. ගැලවීමට දළ විශ්ලේෂණය ස්පර්ශ කර ආපසු අල්ලාගෙන සිටින්න."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"මෙය ඔබ ගලවන තෙක් එය දසුන තුළ තබයි. ගැලවීමට දළ විශ්ලේෂණය ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"හරි, තේරුණා"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"එපා ස්තූතියි"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> සඟවන්නද?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"ඊළඟ අවස්ථාවේ සැකසීම් තුළ ඔබ එය සක්‍රිය කළ විට එය නැවත දිසිවේ."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"සඟවන්න"</string>
@@ -583,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"බල දැනුම්දීම් පාලන සමගින්, ඔබට යෙදුමක දැනුම්දීම් සඳහා වැදගත්කම 0 සිට 5 දක්වා සැකසිය හැකිය. \n\n"<b>"5 මට්ටම"</b>" \n- දැනුම්දීම් ලැයිස්තුවේ ඉහළින්ම පෙන්වන්න \n- පූර්ණ තිර බාධාවට ඉඩ දෙන්න \n- සැම විට එබී බලන්න \n\n"<b>"4 මට්ටම"</b>" \n- පූර්ණ තිර බාධාව වළක්වන්න \n- සැම විට එබී බලන්න \n\n"<b>"3 මට්ටම"</b>" \n- පූර්ණ තිර බාධාව වළක්වන්න \n- කිසි විටක එබී නොබලන්න \n\n"<b>"2 මට්ටම"</b>" \n- පූර්ණ තිර බාධාව වළක්වන්න \n- කිසි විටක එබී නොබලන්න \n- කිසි විටක හඬ සහ කම්පනය සිදු නොකරන්න \n\n"<b>"1 මට්ටම"</b>" \n- පූර්ණ තිර බාධාව වළක්වන්න \n- කිසි විටක එබී නොබලන්න \n- කිසි විටක හඬ සහ කම්පනය සිදු නොකරන්න \n- අගුලු තිරය සහ තත්ත්ව තීරුව වෙතින් සඟවන්න \n- දැනුම්දීම් ලැයිස්තුවේ පහළින්ම පෙන්වන්න \n\n"<b>"0 මට්ටම"</b>" \n- යෙදුම වෙතින් වන සියලු දැනුම් දීම් සඟවන්න."</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"දැනුම් දීම්"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"ඔබට තවදුරටත් මෙම දැනුම්දීම් නොදකිනු ඇත"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"ඔබ සාමාන්‍යයෙන් මෙවැනි දැනුම්දීම් ඉවත දමයි. \nඒවා දිගටම පෙන්වන්නද?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"මෙම දැනුම්දීම් පෙන්වමින් තබන්නද?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"දැනුම්දීම් නවත්වන්න"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"පෙන්වමින් තබන්න"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 3880540..a74f8a4 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"fungua kamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Chagua muundo mpya wa kazi"</string>
     <string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Aikoni ya alama ya kidole"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Aikoni ya programu"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Sehemu ya ujumbe wa usaidizi"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kichupo cha kukuza kwa utangamanifu"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kuza kidogo kwa skrini kubwa."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth imeunganishwa."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Imezimwa"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Imewasha Wi-Fi"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Hakuna mitandao ya Wi-Fi inayopatikana"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Tuma"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Inatuma"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Kifaa hakina jina"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Inaunganisha..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Kusambaza mtandao"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Mtandao-hewa"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Inawasha..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">Vifaa %d</item>
+      <item quantity="one">Kifaa %d</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Arifa"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Tochi"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Data ya mtandao wa simu"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> imetumika"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"kikomo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Onyo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Wasifu wa kazini"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Umezima kipengele cha arifa na programu"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Mwanga wa Usiku"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Itawashwa machweo"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Hadi macheo"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> imezimwa katika hali salama."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Futa zote"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Buruta hapa ili utumie skrini iliyogawanywa"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Telezesha kidole juu ili ubadilishe programu"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gawanya Mlalo"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Gawanya Wima"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Maalum Iliyogawanywa"</string>
@@ -502,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Izime sasa"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Panua"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Kunja"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Badilisha kifaa cha kutoa sauti"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skrini imebandikwa"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Nyuma na Muhtasari ili ubandue."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Muhtasari ili ubandue."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Nimeelewa"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Hapana, asante"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ungependa kuficha <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Itaonekana tena wakati mwingine utakapoiwasha katika mipangilio."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ficha"</string>
@@ -586,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ukiwa na udhibiti wa arifa, unaweza kuweka kiwango cha umuhimu wa arifa za programu kuanzia 0 hadi 5. \n\n"<b>"Kiwango cha 5"</b>" \n- Onyesha katika sehemu ya juu ya orodha ya arifa \n- Ruhusu ukatizaji wa skrini nzima \n- Ruhusu arifa za kuchungulia kila wakati\n\n"<b>"Kiwango cha 4"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Ruhusu arifa za kuchungulia kila wakati \n\n"<b>"Kiwango cha 3"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Usiruhusu kamwe arifa za kuchungulia\n\n"<b>"Kiwango cha 2"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Usiruhusu kamwe arifa za kuchungulia \n- Usiruhusu kamwe sauti au mtetemo \n\n"<b>"Kiwango cha 1"</b>" \n- Zuia ukatizaji wa skrini nzima \n- Usiruhusu kamwe arifa za kuchungulia \n- Usiruhusu kamwe sauti na mtetemo \n- Usionyeshe skrini iliyofungwa na sehemu ya arifa \n- Onyesha katika sehemu ya chini ya orodha ya arifa \n\n"<b>"Kiwango cha 0"</b>" \n- Zuia arifa zote kutoka programu"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Arifa"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Hutaona tena arifa hizi"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Wewe huondoa arifa hizi. \nUngependa kuzionyesha?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Ungependa kuendelea kuonyesha arifa hizi?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Acha kuonyesha arifa"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Endelea kuonyesha"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 774b2f2..c8ff5a1 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"கேமராவைத் திற"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"புதிய பணி தளவமைப்பைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="cancel" msgid="6442560571259935130">"ரத்துசெய்"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"கைரேகை ஐகான்"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"பயன்பாட்டு ஐகான்"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"உதவிச் செய்திக்கான பகுதி"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"பொருந்துமாறு அளவை மாற்றும் பொத்தான்."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"சிறியதிலிருந்து பெரிய திரைக்கு அளவை மாற்றும்."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"புளூடூத் இணைக்கப்பட்டது."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"வைஃபையை முடக்கு"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"வைஃபை இயக்கத்தில்"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"வைஃபை நெட்வொர்க்குகள் இல்லை"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"அனுப்புகிறது"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"பெயரிடப்படாத சாதனம்"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"இணைக்கிறது..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"டெதெரிங்"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ஹாட்ஸ்பாட்"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"ஆன் செய்கிறது..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d சாதனங்கள்</item>
+      <item quantity="one">%d சாதனம்</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"அறிவிப்புகள்"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"டார்ச் லைட்"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"மொபைல் டேட்டா"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"பயன்படுத்தியது - <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> வரம்பு"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> எச்சரிக்கை"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"பணிச் சுயவிவரம்"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"அறிவிப்புகள் &amp; ஆப்ஸ் ஆஃப் செய்யப்பட்டுள்ளன"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"இரவு ஒளி"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"மாலையில் ஆன் செய்"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"சூரிய உதயம் வரை"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"பாதுகாப்புப் பயன்முறையில் <xliff:g id="APP">%s</xliff:g> முடக்கப்பட்டது."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"அனைத்தையும் அழி"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"திரைப் பிரிப்பைப் பயன்படுத்த, இங்கே இழுக்கவும்"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"ஆப்ஸிற்கு இடையே மாற்றுவதற்கு, மேல்நோக்கி ஸ்வைப் செய்க"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"செங்குத்தாகப் பிரி"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"தனிவிருப்பத்தில் பிரி"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"இப்போதே முடக்கு"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"விரிவாக்கு"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"சுருக்கு"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"திரை பொருத்தப்பட்டது"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"புரிந்தது"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"வேண்டாம்"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ஐ மறைக்கவா?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"அடுத்த முறை அமைப்புகளில் மீண்டும் இயக்கும்போது, இது மீண்டும் தோன்றும்."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"மறை"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ஆற்றல்மிக்க அறிவிப்புக் கட்டுப்பாடுகள் மூலம், பயன்பாட்டின் அறிவிப்புகளுக்கு முக்கியத்துவ நிலையை (0-5) அமைக்கலாம். \n\n"<b>"நிலை 5"</b>" \n- அறிவிப்புப் பட்டியலின் மேலே காட்டும் \n- முழுத் திரைக் குறுக்கீட்டை அனுமதிக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 4"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 3"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n\n"<b>"நிலை 2"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது, அதிர்வுறாது \n\n"<b>"நிலை 1"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது அல்லது அதிர்வுறாது \n- பூட்டுத்திரை மற்றும் நிலைப்பட்டியிலிருந்து மறைக்கும் \n- அறிவிப்புகள் பட்டியலின் கீழே காட்டும் \n\n"<b>"நிலை 0"</b>" \n- பயன்பாட்டின் எல்லா அறிவிப்புகளையும் தடுக்கும்"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"அறிவிப்புகள்"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"இந்த அறிவிப்புகளை இனி பார்க்கமாட்டீர்கள்"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"வழக்கமாக, இந்த அறிவிப்புகளை நிராகரிக்கிறீர்கள். \nதொடர்ந்து இவற்றைக் காட்டலாமா?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"இந்த அறிவிப்புகளைத் தொடர்ந்து காட்டவா?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"அறிவிப்புகளை நிறுத்து"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"அறிவிப்புகளைத் தொடர்ந்து காட்டு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index e143b90..292fddd 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"కెమెరాను తెరువు"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"కొత్త విధి లేఅవుట్‌ను ఎంచుకోండి"</string>
     <string name="cancel" msgid="6442560571259935130">"రద్దు చేయి"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"వేలిముద్ర చిహ్నం"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"అప్లికేషన్ చిహ్నం"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"సహాయ సందేశ ప్రాంతం"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"అనుకూలత జూమ్ బటన్."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"చిన్న స్క్రీన్ నుండి పెద్దదానికి జూమ్ చేయండి."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ఆఫ్‌లో ఉంది"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi ఆన్‌లో ఉంది"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Wi-Fi నెట్‌వర్క్‌లు ఏవీ అందుబాటులో లేవు"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"ప్రసారం చేయండి"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"ప్రసారం చేస్తోంది"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"పేరులేని పరికరం"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"కనెక్ట్ అవుతోంది..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"టీథరింగ్"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"హాట్‌స్పాట్"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"ఆన్ చేస్తోంది…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d పరికరాలు</item>
+      <item quantity="one">%d పరికరం</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"నోటిఫికేషన్‌లు"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"ఫ్లాష్‌లైట్"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"మొబైల్ డేటా"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> వినియోగించబడింది"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> పరిమితి"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> హెచ్చరిక"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"కార్యాలయ ప్రొఫైల్"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"నోటిఫికేషన్‌లు &amp; యాప్‌లు ఆఫ్ చేయి"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"రాత్రి కాంతి"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"సూర్యాస్తమయానికి"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"సూర్యోదయం వరకు"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> సురక్షిత-మోడ్‌లో నిలిపివేయబడింది."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"అన్నీ తీసివేయి"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"విభజన స్క్రీన్‌ను ఉపయోగించడానికి ఇక్కడ లాగండి"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"యాప్‌లను మార్చడం కోసం ఎగువకు స్వైప్ చేయండి"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"సమతలంగా విభజించు"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"లంబంగా విభజించు"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"అనుకూలంగా విభజించు"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"ఇప్పుడు ఆఫ్ చేయండి"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"విస్తరింపజేయండి"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"కుదించండి"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"స్క్రీన్ పిన్ చేయబడింది"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టి తాకి &amp; అలాగే పట్టుకోండి."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి స్థూలదృష్టిని తాకి &amp; అలాగే పట్టుకోండి."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"అర్థమైంది"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"వద్దు, ధన్యవాదాలు"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ని దాచాలా?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"మీరు సెట్టింగ్‌ల్లో దీన్ని ఆన్ చేసిన తదుపరిసారి ఇది కనిపిస్తుంది."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"దాచు"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"పవర్ నోటిఫికేషన్ నియంత్రణలతో, మీరు యాప్ నోటిఫికేషన్‌ల కోసం ప్రాముఖ్యత స్థాయిని 0 నుండి 5 వరకు సెట్ చేయవచ్చు. \n\n"<b>"స్థాయి 5"</b>" \n- నోటిఫికేషన్ జాబితా పైభాగంలో చూపబడతాయి \n- పూర్తి స్క్రీన్ అంతరాయం అనుమతించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 4"</b>\n"- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 3"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n\n"<b>"స్థాయి 2"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం మరియు వైబ్రేషన్ చేయవు \n\n"<b>"స్థాయి 1"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం లేదా వైబ్రేట్ చేయవు \n- లాక్ స్క్రీన్ మరియు స్థితి పట్టీ నుండి దాచబడతాయి \n- నోటిఫికేషన్ జాబితా దిగువ భాగంలో చూపబడతాయి \n\n"<b>"స్థాయి 0"</b>" \n- యాప్ నుండి అన్ని నోటిఫికేషన్‌లు బ్లాక్ చేయబడతాయి"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"నోటిఫికేషన్‌లు"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"ఇకపై మీకు ఈ నోటిఫికేషన్‌లు కనిపించవు"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"మీరు సాధారణంగా ఈ నోటిఫికేషన్‌లను విస్మరిస్తారు. \nవాటి ప్రదర్శనను కొనసాగించాలా?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"ఈ నోటిఫికేషన్‌లను చూపిస్తూ ఉండాలా?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"నోటిఫికేషన్‌లను ఆపివేయి"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"చూపిస్తూనే ఉండు"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 8a289be..9adc141 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"kamerayı aç"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Yeni görev düzenini seçin"</string>
     <string name="cancel" msgid="6442560571259935130">"İptal"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Parmak izi simgesi"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Uygulama simgesi"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Yardım mesajı alanı"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyumluluk zum düğmesi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha büyük ekrana daha küçük yakınlaştır."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth bağlandı."</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Kablosuz Kapalı"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Kablosuz Bağlantı Açık"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Kullanılabilir kablosuz ağ yok"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Yayınla"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Yayınlanıyor"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Adsız cihaz"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Bağlanılıyor..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Açılıyor..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d cihaz</item>
+      <item quantity="one">%d cihaz</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Bildirimler"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Fener"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobil veri"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> kullanıldı"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Sınır: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> uyarısı"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"İş profili"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Bildirimler ve uygulamalar kapalı"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gece Işığı"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Gün batımı açılacak"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Gün doğumuna kadar"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g>, güvenli modda devre dışıdır."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Tümünü temizle"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Ekranı bölünmüş olarak kullanmak için burayı sürükleyin"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Uygulamalar arasında geçiş yapmak için yukarı kaydırın"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Yatay Ayırma"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dikey Ayırma"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Özel Ayırma"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Şimdi kapat"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişlet"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Daralt"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran sabitlendi"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Genel Bakış\'a dokunup basılı tutun."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Genel bakış\'a dokunup basılı tutun."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Hayır, teşekkürler"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ayarlardan etkinleştirdiğiniz bir sonraki sefer tekrar görünür."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Gizle"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Güç bildirim kontrolleriyle, bir uygulamanın bildirimleri için 0 ile 5 arasında bir önem düzeyi ayarlayabilirsiniz. \n\n"<b>"5. Düzey"</b>" \n- Bildirim listesinin en üstünde gösterilsin \n- Tam ekran kesintisine izin verilsin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"4. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"3. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n\n"<b>"2. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman belirmesin \n- Hiçbir zaman ses çıkarmasın ve titreştirmesin \n\n"<b>"1. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n- Hiçbir zaman ses çıkarmasın veya titreştirmesin \n- Kilit ekranından ve durum çubuğundan gizlensin \n- Bildirim listesinin en altında gösterilsin \n\n"<b>"0. Düzey"</b>" \n- Uygulamadan gelen tüm bildirimler engellensin"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirimler"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Bu bildirimleri artık görmeyeceksiniz"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Bu bildirimleri genellikle kapatıyorsunuz. \nBildirimler gösterilmeye devam edilsin mi?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Bu bildirimler gösterilmeye devam edilsin mi?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Bildirimleri durdur"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Göstermeye devam et"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index f296143..3834753 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -105,12 +105,9 @@
     <string name="camera_label" msgid="7261107956054836961">"відкрити камеру"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Виберіть новий макет завдання"</string>
     <string name="cancel" msgid="6442560571259935130">"Скасувати"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Значок відбитка пальця"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Значок додатка"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Область довідкового повідомлення"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабування сумісності."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth під’єднано."</string>
@@ -317,6 +314,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi вимкнено"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi увімкнено"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Немає доступних мереж Wi-Fi"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Трансляція"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Трансляція"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Пристрій без назви"</string>
@@ -333,9 +332,13 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"З’єднання…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Режим модема"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Точка доступу"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Увімкнення…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d пристрій</item>
+      <item quantity="few">%d пристрої</item>
+      <item quantity="many">%d пристроїв</item>
+      <item quantity="other">%d пристрою</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Сповіщення"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Ліхтарик"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Мобільне передавання даних"</string>
@@ -345,10 +348,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Використовується: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Обмеження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Застереження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Робочий профіль"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Сповіщення й додатки вимкнено"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Нічний режим"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Вмикається ввечері"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"До сходу сонця"</string>
@@ -366,8 +367,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Додаток <xliff:g id="APP">%s</xliff:g> вимкнено в безпечному режимі."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Очистити все"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Перетягніть сюди, щоб увімкнути режим розділеного екрана"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Проводьте пальцем угору, щоб переходити між додатками"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Розділити горизонтально"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Розділити вертикально"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Розділити (власний варіант)"</string>
@@ -508,11 +508,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Вимкнути"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Розгорнути"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Згорнути"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Увімкніть пристрій виведення"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екран закріплено"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопки \"Назад\" та \"Огляд\"."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопку \"Огляд\"."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Зрозуміло"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ні, дякую"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сховати <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"З’явиться знову, коли ви ввімкнете його в налаштуваннях."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Сховати"</string>
@@ -592,8 +605,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"За допомогою елементів керування сповіщеннями ви можете налаштувати пріоритет сповіщень додатка – від 0 до 5 рівня. \n\n"<b>"Рівень 5"</b>\n"- Показувати сповіщення вгорі списку \n- Виводити на весь екран \n- Завжди показувати короткі сповіщення \n\n"<b>"Рівень 4"</b>\n"- Не виводити на весь екран \n- Завжди показувати короткі сповіщення \n\n"<b>"Рівень 3"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n\n"<b>"Рівень 2"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n- Вимкнути звук і вібросигнал \n\n"<b>"Рівень 1"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n- Вимкнути звук і вібросигнал \n- Не показувати на заблокованому екрані та в рядку стану \n- Показувати сповіщення внизу списку \n\n"<b>"Рівень 0"</b>\n"- Блокувати всі сповіщення з додатка"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Сповіщення"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Ви більше не бачитимете цих сповіщень"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Ви зазвичай закриваєте ці сповіщення. \nПоказувати їх?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Чи показувати ці сповіщення надалі?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Не показувати сповіщення"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Показувати надалі"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 8099ef4..9ebdfeb 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"کیمرا کھولیں"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"نئے کام کا لے آؤٹ منتخب کریں"</string>
     <string name="cancel" msgid="6442560571259935130">"منسوخ کریں"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"فنگر پرنٹ آئیکن"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"ایپلیکیشن کا آئیکن"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"امدادی پیغام کا علاقہ"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"مطابقت پذیری زوم بٹن۔"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"چھوٹی سے بڑی اسکرین پر زوم کریں۔"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوٹوتھ مربوط ہے۔"</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‏Wi-Fi آف ہے"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"‏Wi-Fi آن ہے"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"‏کوئی WI-FI نیٹ ورک دستیاب نہیں"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"کاسٹ کریں"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"کاسٹنگ"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"بغیر نام والا آلہ"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"مربوط ہو رہا ہے…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"ٹیدرنگ"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ہاٹ اسپاٹ"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"آن ہو رہا ہے…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">‏%d آلات</item>
+      <item quantity="one">‏%d آلہ</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"اطلاعات"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"فلیش لائٹ"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"موبائل ڈیٹا"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> استعمال کردہ"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> حد"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> وارننگ"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"دفتری پروفائل"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"اطلاعات اور ایپس آف ہیں"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"نائٹ لائٹ"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"غروب آفتاب کے وقت آن ہوگی"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"طلوع آفتاب تک"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"محفوظ موڈ میں <xliff:g id="APP">%s</xliff:g> غیر فعال ہوتی ہے۔"</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"سبھی کو صاف کریں"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"اسپلٹ اسکرین استعمال کرنے کیلئے یہاں گھسیٹیں"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"ایپس سوئچ کرنے کیلئے اوپر سوائپ کریں"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"بلحاظ افقی الگ کریں"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"بلحاظ عمودی الگ کریں"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"بلحاظ حسب ضرورت الگ کریں"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"ابھی بند کریں"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"پھیلائیں"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"سکیڑیں"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"اسکرین پن کردہ ہے"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے مجموعی جائزہ بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"سمجھ آ گئی"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"نہیں شکریہ"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> کو چھپائیں؟"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"اگلی بار جب آپ اسے ترتیبات میں آن کریں گے تو یہ ظاہر ہوگی۔"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"چھپائیں"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"پاور اطلاع کنٹرولز کے ساتھ آپ کسی ایپ کی اطلاعات کیلئے 0 سے 5 تک اہمیت کی سطح سیٹ کر سکتے ہیں۔ \n\n"<b>"سطح 5"</b>\n"- اطلاعات کی فہرست کے اوپر دکھائیں \n- پوری اسکرین کی مداخلت کی اجازت دیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 4"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 3"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n\n"<b>"سطح 2"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n- کبھی آواز اور ارتعاش پیدا نہ کرنا \n\n"<b>" سطح 1"</b>\n"- پوری اسکرین کی مداخلت کو روکنا \n- کبھی نہ جھانکنا \n- کبھی بھی آواز یا ارتعاش پیدا نہ کرنا\n- مقفل اسکرین اور اسٹیٹس بار سے چھپانا \n - اطلاع کی فہرست کی نیچے دکھانا \n\n"<b>"سطح 0"</b>\n"- ایپ سے تمام اطلاعات مسدود کریں"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"اطلاعات"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"آپ کو یہ اطلاعات مزید دکھائی نہیں دیں گی"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"آپ عام طور پر ان اطلاعات کو مسترد کرتے ہیں۔ \nان کو دکھاتے رہیں؟"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"یہ اطلاعات دکھانا جاری رکھیں؟"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"اطلاعات روک دیں"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"دکھانا جاری رکھیں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 612859b..37d8118 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"kamerani ochish"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Yangi vazifa tartibini tanlash"</string>
     <string name="cancel" msgid="6442560571259935130">"Bekor qilish"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Barmoq izi belgisi"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Ilova ikonkasi"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Yordam xabari"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kattalashtirish tugmasi mosligi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kattaroq ekran uchun kichikroqni kattalashtirish."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ulandi."</string>
@@ -288,7 +285,7 @@
     <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="7106697106764717416">"Batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
     <string name="quick_settings_bluetooth_secondary_label_audio" msgid="5673845963301132071">"Audio"</string>
     <string name="quick_settings_bluetooth_secondary_label_headset" msgid="1880572731276240588">"Garnitura"</string>
-    <string name="quick_settings_bluetooth_secondary_label_input" msgid="2173322305072945905">"Matn kiritish"</string>
+    <string name="quick_settings_bluetooth_secondary_label_input" msgid="2173322305072945905">"Kirish"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Yorqinlik"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Avtomatik burilish"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Ekranning avtomatik burilishi"</string>
@@ -313,6 +310,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi o‘chiq"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi yoqilgan"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Hech qanday Wi-Fi tarmog‘i mavjud emas"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Translatsiya"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Translatsiya qilinmoqda"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nomsiz qurilma"</string>
@@ -329,9 +328,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Ulanmoqda…"</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Modem rejimi"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Yoqilmoqda…"</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d ta qurilma</item>
+      <item quantity="one">%d ta qurilma</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Bildirishnomalar"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Fonar"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobil internet"</string>
@@ -341,10 +342,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> ishlatilgan"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Cheklov: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ogohlantirish: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Ishchi profil"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Bildirishnomalar va ilovalar o‘chiq"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Tungi rejim"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Kunbotarda yoqish"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Quyosh chiqqunicha"</string>
@@ -362,8 +361,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Xavfsiz rejimda <xliff:g id="APP">%s</xliff:g> ilovasi o‘chirib qo‘yildi."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Hammasini tozalash"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Ekranni bo‘lish xususiyatidan foydalanish uchun bu yerga torting"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Ilovalarni almashtirish uchun ekranni tepaga suring"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikal yo‘nalishda bo‘lish"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Boshqa usulda bo‘lish"</string>
@@ -504,11 +502,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"O‘chiring"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Yoyish"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yig‘ish"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran qadaldi"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy ma’lumot” tugmalarini bosib turing."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Umumiy ma’lumot” tugmasini bosib turing."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Yo‘q, kerakmas"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Keyingi safar sozlamalardan yoqilgan paydo bo‘ladi."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Berkitish"</string>
@@ -588,8 +600,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Bildirishnomalar uchun kengaytirilgan boshqaruv yordamida ilova bildirishnomalarining muhimlik darajasini (0-5) sozlash mumkin. \n\n"<b>"5-daraja"</b>" \n- Bildirishnomani ro‘yxatning boshida ko‘rsatish \n- To‘liq ekranli bildirishnomalarni ko‘rsatish \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"4-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"3-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n\n"<b>"2-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n\n"<b>"1-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n- Ekran qulfi va holat qatorida ko‘rsatmaslik \n- Bildirishnomani ro‘yxatning oxirida ko‘rsatish \n\n"<b>"0-daraja"</b>" \n- Ilovadan keladigan barcha bildirishnomalarni bloklash"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirishnomalar"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Bu bildirishnomalar endi chiqmaydi"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Odatda bunday bildirishnomalarni yopasiz. \nUlar ochiq tursinmi?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Mazkur bildirishnomalar chiqaversinmi?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Chiqmasin"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Ha"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index e08bf69..9c425b0 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"開啟攝影機"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"選取新工作版面配置"</string>
     <string name="cancel" msgid="6442560571259935130">"取消"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指紋圖示"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"應用程式圖示"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"說明訊息區域"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 已關閉"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"已開啟 Wi-Fi"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"沒有 Wi-Fi 網路"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"投放"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"投放"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"未命名的裝置"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"連線中..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"網路共用"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"無線基地台"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"開啟中..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="other">%d 個裝置</item>
+      <item quantity="one">%d 個裝置</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"通知"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"手電筒"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"行動數據"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"已使用 <xliff:g id="DATA_USED">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"上限為 <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Work 設定檔"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"已關閉通知和應用程式"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜燈"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"於日落時開啟"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"於日出時關閉"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"「<xliff:g id="APP">%s</xliff:g>」在安全模式中為停用狀態。"</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"全部清除"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"拖曳到這裡即可使用分割畫面"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"向上滑動即可切換應用程式"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
@@ -502,11 +500,25 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"立即停用"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"展開"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"收合"</string>
+    <!-- no translation found for accessibility_output_chooser (8185317493017988680) -->
+    <skip />
     <string name="screen_pinning_title" msgid="3273740381976175811">"螢幕已固定"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [總覽] 按鈕即可取消固定。"</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"知道了"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"不用了,謝謝"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"只要在設定頁面中重新啟用,就能再次看到快捷設定選項。"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隱藏"</string>
@@ -586,8 +598,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"只要使用電源通知控制項,你就能為應用程式通知設定從 0 到 5 的重要性等級。\n\n"<b>"等級 5"</b>" \n- 顯示在通知清單頂端 \n- 允許全螢幕通知 \n- 一律允許短暫顯示通知 \n\n"<b>"等級 4"</b>" \n- 禁止全螢幕通知 \n- 一律允許短暫顯示通知 \n\n"<b>"等級 3"</b>" \n- 禁止全螢幕通知 \n- 一律不允許短暫顯示通知 \n\n"<b>"等級 2"</b>" \n- 禁止全螢幕通知 \n- 一律不允許短暫顯示通知 \n- 一律不發出音效或震動 \n\n"<b>"等級 1"</b>" \n- 禁止全螢幕通知 \n- 一律不允許短暫顯示通知 \n- 一律不發出音效或震動 \n- 在鎖定畫面和狀態列中隱藏 \n- 顯示在通知清單底端 \n\n"<b>"等級 0"</b>" \n- 封鎖應用程式的所有通知"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"你不會再看到這些通知"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"你通常會關閉這些通知。\n要繼續顯示通知嗎?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"要繼續顯示這些通知嗎?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"停止顯示通知"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"繼續顯示"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index a99b8cc..d291a19 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -103,12 +103,9 @@
     <string name="camera_label" msgid="7261107956054836961">"vula ikhamera"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Khetha isakhiwo somsebenzi omusha"</string>
     <string name="cancel" msgid="6442560571259935130">"Khansela"</string>
-    <!-- no translation found for accessibility_fingerprint_dialog_fingerprint_icon (3125122495414253226) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_app_icon (3228052542929174609) -->
-    <skip />
-    <!-- no translation found for accessibility_fingerprint_dialog_help_area (5730471601819225159) -->
-    <skip />
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Isithonjana sezigxivizo zeminwe"</string>
+    <string name="accessibility_fingerprint_dialog_app_icon" msgid="3228052542929174609">"Isithonjana sohlelo lokusebenza"</string>
+    <string name="accessibility_fingerprint_dialog_help_area" msgid="5730471601819225159">"Indawo yosizo lomlayezo"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Inkinobho evumelekile yokusondeza"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Sondeza kancane esikrinini esikhudlwana"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ixhunyiwe"</string>
@@ -311,6 +308,8 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"I-Wi-Fi icimile"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"I-Wi-Fi ivuliwe"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Awekho amanethiwekhi we-Wi-Fi atholakalayo"</string>
+    <!-- no translation found for quick_settings_alarm_title (2416759007342260676) -->
+    <skip />
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Abalingisi"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Ukusakaza"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Idivayisi engenalo igama"</string>
@@ -327,9 +326,11 @@
     <string name="quick_settings_connecting" msgid="47623027419264404">"Iyaxhuma..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ukusebenzisa njengemodemu"</string>
     <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"I-Hotspot"</string>
-    <!-- no translation found for quick_settings_hotspot_secondary_label_transient (7161046712706277215) -->
-    <skip />
-    <!-- no translation found for quick_settings_hotspot_secondary_label_num_devices (2324635800672199428) -->
+    <string name="quick_settings_hotspot_secondary_label_transient" msgid="7161046712706277215">"Iyavula..."</string>
+    <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="2324635800672199428">
+      <item quantity="one">%d amadivayisi</item>
+      <item quantity="other">%d amadivayisi</item>
+    </plurals>
     <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Izaziso"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"I-Flashlight"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Idatha yeselula"</string>
@@ -339,10 +340,8 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> isetshenzisiwe"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"<xliff:g id="DATA_LIMIT">%s</xliff:g> umkhawulo"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> isexwayiso"</string>
-    <!-- no translation found for quick_settings_work_mode_on_label (3421274215098764735) -->
-    <skip />
-    <!-- no translation found for quick_settings_work_mode_off_label (8856918707867192186) -->
-    <skip />
+    <string name="quick_settings_work_mode_on_label" msgid="3421274215098764735">"Iphrofayela yomsebenzi"</string>
+    <string name="quick_settings_work_mode_off_label" msgid="8856918707867192186">"Izaziso nezinhlelo zokusebenza kuvaliwe"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ukukhanya kwasebusuku"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="8483259341596943314">"Kuvulwe ekushoneni kwelanga"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4453017157391574402">"Kuze kube sekuphumeni kwelanga"</string>
@@ -360,8 +359,7 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"I-<xliff:g id="APP">%s</xliff:g> ikhutshaziwe kumodi yokuphepha."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Sula konke"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Hudulela lapha ukuze usebenzise ukuhlukanisa kwesikrini"</string>
-    <!-- no translation found for recents_swipe_up_onboarding (3824607135920170001) -->
-    <skip />
+    <string name="recents_swipe_up_onboarding" msgid="3824607135920170001">"Swayiphela phezulu ukuze ushintshe izinhlelo zokusebenza"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Hlukanisa okuvundlile"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Hlukanisa okumile"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Hlukanisa kwezifiso"</string>
@@ -502,11 +500,24 @@
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Vala manje"</string>
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Nweba"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Goqa"</string>
+    <string name="accessibility_output_chooser" msgid="8185317493017988680">"Shintsha idivayisi yokukhipha"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Isikrini siphiniwe"</string>
     <string name="screen_pinning_description" msgid="8909878447196419623">"Lokhu kuyigcina ibukeka uze ususe ukuphina. Thinta uphinde ubambe okuthi Emuva Nokubuka konke ukuze ususe ukuphina."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible (8281145542163727971) -->
+    <skip />
     <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Lokhu kuyigcina ibukeka uze ususe ukuphina. Thinta uphinde ubambe Ukubuka konke ukuze ususe ukuphina."</string>
+    <!-- no translation found for screen_pinning_description_recents_invisible_accessible (6134833683151189507) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast (2266705122951934150) -->
+    <skip />
+    <!-- no translation found for screen_pinning_toast_recents_invisible (8252402309499161281) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ngiyitholile"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Cha ngiyabonga"</string>
+    <!-- no translation found for screen_pinning_start (1022122128489278317) -->
+    <skip />
+    <!-- no translation found for screen_pinning_exit (5187339744262325372) -->
+    <skip />
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fihla i-<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Izovela ngesikhathi esilandelayo uma uvule lesi silungiselelo."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Fihla"</string>
@@ -586,8 +597,7 @@
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ngezilawuli zesaziso zamandla, ungasetha ileveli ebalulekile kusuka ku-0 kuya ku-5 kusuka kuzaziso zohlelo lokusebenza. \n\n"<b>"Ileveli 5"</b>" \n- Ibonisa phezulu kuhlu lwesaziso \n- Vumela ukuphazamiseka kwesikrini esigcwele \n- Ukuhlola njalo \n\n"<b>"Ileveli 4"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukuhlola njalo \n\n"<b>"Ileveli 3"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n\n"<b>"Ileveli 2"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n- Ungenzi umsindo nokudlidliza \n\n"<b>"Ileveli 1"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n- Ungenzi umsindo noma ukudlidliza \n- Fihla kusuka kusikrini sokukhiya nebha yesimo \n- Bonisa phansi kohlu lwesaziso \n\n"<b>"Ileveli 0"</b>" \n- Vimbela zonke izaziso kusuka kuhlelo lokusebenza"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"Izaziso"</string>
     <string name="notification_channel_disabled" msgid="344536703863700565">"Ngeke usabona lezi zaziso"</string>
-    <!-- no translation found for inline_blocking_helper (3055064577771478591) -->
-    <skip />
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Uvamise ukucashisa lezi zaziso. \nQhubeka ulokhu uzibonisa?"</string>
     <string name="inline_keep_showing" msgid="8945102997083836858">"Qhubeka nokubonisa lezi zaziso?"</string>
     <string name="inline_stop_button" msgid="4172980096860941033">"Misa izaziso"</string>
     <string name="inline_keep_button" msgid="6665940297019018232">"Qhubeka nokubonisa"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f2e5d3b..cf0659a 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -475,4 +475,11 @@
         <item>60</item>
         <item>120</item>
     </integer-array>
+
+    <!-- Smart replies in notifications: Whether smart replies in notifications are enabled. -->
+    <bool name="config_smart_replies_in_notifications_enabled">true</bool>
+
+    <!-- Smart replies in notifications: Maximum number of times SmartReplyView will try to find a
+         better (narrower) line-break for a double-line smart reply button. -->
+    <integer name="config_smart_replies_in_notifications_max_squeeze_remeasure_attempts">3</integer>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2e279be..3f6c85f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -704,6 +704,8 @@
     <dimen name="volume_expander_margin_end">2dp</dimen>
     <dimen name="volume_expander_margin_top">6dp</dimen>
 
+    <dimen name="volume_panel_elevation">8dp</dimen>
+
     <!-- Padding between icon and text for managed profile toast -->
     <dimen name="managed_profile_toast_padding">4dp</dimen>
 
@@ -894,13 +896,28 @@
     <dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen>
     <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
 
-    <!-- WirelessCharging Animation values -->
-    <!-- Starting text size of batteryLevel for wireless charging animation -->
-    <dimen name="config_batteryLevelTextSizeStart" format="float">5.0</dimen>
-    <!-- Ending text size of batteryLevel for wireless charging animation -->
-    <dimen name="config_batteryLevelTextSizeEnd" format="float">32.0</dimen>
-    <!-- Wireless Charging battery level text animation duration -->
-    <integer name="config_batteryLevelTextAnimationDuration">400</integer>
+    <!-- Wireless Charging Animation values -->
+    <dimen name="wireless_charging_dots_radius_start">0dp</dimen>
+    <dimen name="wireless_charging_dots_radius_end">4dp</dimen>
+    <dimen name="wireless_charging_circle_radius_start">28dp</dimen>
+    <dimen name="wireless_charging_circle_radius_end">92dp</dimen>
+    <integer name="wireless_charging_angle_offset">20</integer>
+    <integer name="wireless_charging_scale_dots_duration">83</integer>
+    <integer name="wireless_charging_num_dots">20</integer>
+    <!-- Starting text size in dp of batteryLevel for wireless charging animation -->
+    <dimen name="wireless_charging_anim_battery_level_text_size_start">0dp</dimen>
+    <!-- Ending text size in dp of batteryLevel for wireless charging animation -->
+    <dimen name="wireless_charging_anim_battery_level_text_size_end">14dp</dimen>
+    <!-- time until battery info is at full opacity-->
+    <integer name="wireless_charging_anim_opacity_offset">80</integer>
+    <!-- duration batteryLevel opacity goes from 0 to 1 duration -->
+    <integer name="wireless_charging_battery_level_text_opacity_duration">117</integer>
+    <!-- battery text scale animation duration -->
+    <integer name="wireless_charging_battery_level_text_scale_animation_duration">367</integer>
+    <!--time until wireless charging animation starts to fade-->
+    <integer name="wireless_charging_fade_offset">920</integer>
+    <!-- duration wireless charging animation takes to full fade to 0 opacity -->
+    <integer name="wireless_charging_fade_duration">200</integer>
 
     <!-- Wired charging on AOD, text animation duration -->
     <integer name="wired_charging_aod_text_animation_duration_down">500</integer>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index f9aa821..2d30f4c 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -47,7 +47,6 @@
     <item type="id" name="qs_icon_tag"/>
     <item type="id" name="qs_slash_tag"/>
     <item type="id" name="scrim"/>
-    <item type="id" name="scrim_blanking"/>
     <item type="id" name="scrim_target"/>
     <item type="id" name="scrim_alpha_start"/>
     <item type="id" name="scrim_alpha_end"/>
@@ -58,6 +57,8 @@
     <item type="id" name="notification_plugin"/>
     <item type="id" name="transformation_start_x_tag"/>
     <item type="id" name="transformation_start_y_tag"/>
+    <item type="id" name="transformation_start_actual_width"/>
+    <item type="id" name="transformation_start_actual_height"/>
     <item type="id" name="transformation_start_scale_x_tag"/>
     <item type="id" name="transformation_start_scale_y_tag"/>
     <item type="id" name="continuous_clipping_tag"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fadcbcd..fc5ea45 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -842,8 +842,6 @@
     <string name="recents_stack_action_button_label">Clear all</string>
     <!-- Recents: Hint text that shows on the drop targets to start multiwindow. [CHAR LIMIT=NONE] -->
     <string name="recents_drag_hint_message">Drag here to use split screen</string>
-    <!-- Recents: Text that shows above the nav bar after launching a few apps. [CHAR LIMIT=NONE] -->
-    <string name="recents_swipe_up_onboarding">Swipe up to switch apps</string>
 
     <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
     <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 64fa9c6..7f382ac 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -21,9 +21,40 @@
 
 oneway interface IOverviewProxy {
     void onBind(in ISystemUiProxy sysUiProxy);
+
+    /**
+     * Proxies motion events from the nav bar in SystemUI to the OverviewProxyService. The sender
+     * guarantees the following order of events:
+     *
+     * Normal gesture: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, UP
+     * Quick switch: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SWITCH
+     * Quick scrub: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SCRUB_START, SCRUB_PROGRESS*, SCRUB_END
+     *
+     * Once quick switch/scrub is sent, then no further motion events will be provided.
+     */
     void onMotionEvent(in MotionEvent event);
+
+    /**
+     * Sent when a user has quickly flinged on the nav bar to switch tasks. Once this event is sent
+     * the caller will stop sending any motion events and will no longer preemptively cancel any
+     * recents animations started as a part of the motion event handling.
+     */
     void onQuickSwitch();
+
+    /**
+     * Sent when the user starts to actively scrub the nav bar to switch tasks. Once this event is
+     * sent the caller will stop sending any motion events and will no longer preemptively cancel
+     * any recents animations started as a part of the motion event handling.
+     */
     void onQuickScrubStart();
+
+    /**
+     * Sent when the user stops actively scrubbing the nav bar to switch tasks.
+     */
     void onQuickScrubEnd();
+
+    /**
+     * Sent for each movement over the nav bar while the user is scrubbing it to switch tasks.
+     */
     void onQuickScrubProgress(float progress);
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 98ede4e..4cf817e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -39,4 +39,9 @@
      * Called when the overview service has started the recents animation.
      */
     void onRecentsAnimationStarted();
+
+    /**
+     * Specifies the text to be shown for onboarding the new swipe-up gesture to access recents.
+     */
+    void setRecentsOnboardingText(CharSequence text);
 }
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 90e3b1e..62bd72f 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
@@ -43,6 +43,7 @@
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -57,6 +58,7 @@
 import android.view.IRecentsAnimationRunner;
 
 import android.view.RemoteAnimationTarget;
+import android.view.WindowManagerGlobal;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -271,11 +273,20 @@
                 runner = new IRecentsAnimationRunner.Stub() {
                     public void onAnimationStart(IRecentsAnimationController controller,
                             RemoteAnimationTarget[] apps) {
+                        final Rect stableInsets = new Rect();
+                        WindowManagerWrapper.getInstance().getStableInsets(stableInsets);
+                        onAnimationStart_New(controller, apps, stableInsets, null);
+                    }
+
+                    public void onAnimationStart_New(IRecentsAnimationController controller,
+                            RemoteAnimationTarget[] apps, Rect homeContentInsets,
+                            Rect minimizedHomeBounds) {
                         final RecentsAnimationControllerCompat controllerCompat =
                                 new RecentsAnimationControllerCompat(controller);
                         final RemoteAnimationTargetCompat[] appsCompat =
                                 RemoteAnimationTargetCompat.wrap(apps);
-                        animationHandler.onAnimationStart(controllerCompat, appsCompat);
+                        animationHandler.onAnimationStart(controllerCompat, appsCompat,
+                                homeContentInsets, minimizedHomeBounds);
                     }
 
                     public void onAnimationCanceled() {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index bf6179d..a473db1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -16,13 +16,15 @@
 
 package com.android.systemui.shared.system;
 
+import android.graphics.Rect;
+
 public interface RecentsAnimationListener {
 
     /**
      * Called when the animation into Recents can start. This call is made on the binder thread.
      */
     void onAnimationStart(RecentsAnimationControllerCompat controller,
-            RemoteAnimationTargetCompat[] apps);
+            RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, Rect minimizedHomeBounds);
 
     /**
      * Called when the animation into Recents was canceled. This call is made on the binder thread.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 3871980..b8c5049 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.shared.system;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+
+import android.app.WindowConfiguration;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.RemoteAnimationTarget;
@@ -37,7 +40,10 @@
     public final Point position;
     public final Rect sourceContainerBounds;
 
+    private final RemoteAnimationTarget mTarget;
+
     public RemoteAnimationTargetCompat(RemoteAnimationTarget app) {
+        mTarget = app;
         taskId = app.taskId;
         mode = app.mode;
         leash = new SurfaceControlCompat(app.leash);
@@ -56,4 +62,18 @@
         }
         return appsCompat;
     }
+
+    /**
+     * TODO: Get as a method for compatibility (will move into ctor once Launcher updates)
+     */
+    public Rect getContentInsets() {
+        return mTarget.contentInsets;
+    }
+
+    /**
+     * TODO: Get as a method for compatibility (will move into ctor once Launcher updates)
+     */
+    public boolean isAssistantActivityType() {
+        return mTarget.windowConfiguration.getActivityType() == ACTIVITY_TYPE_ASSISTANT;
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/shared/tests/Android.mk b/packages/SystemUI/shared/tests/Android.mk
index 239a4e3..1715983 100644
--- a/packages/SystemUI/shared/tests/Android.mk
+++ b/packages/SystemUI/shared/tests/Android.mk
@@ -41,7 +41,7 @@
     testables \
     truth-prebuilt \
 
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
 
 # sign this with platform cert, so this test is allowed to inject key events into
 # UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index b7e1d67..d0128ef 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -66,6 +66,7 @@
 
     private IOverviewProxy mOverviewProxy;
     private int mConnectionBackoffAttempts;
+    private CharSequence mOnboardingText;
 
     private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
 
@@ -98,13 +99,15 @@
         public void onRecentsAnimationStarted() {
             long token = Binder.clearCallingIdentity();
             try {
-                mHandler.post(() -> {
-                    notifyRecentsAnimationStarted();
-                });
+                mHandler.post(OverviewProxyService.this::notifyRecentsAnimationStarted);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        public void setRecentsOnboardingText(CharSequence text) {
+            mOnboardingText = text;
+        }
     };
 
     private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
@@ -223,8 +226,8 @@
         return mOverviewProxy;
     }
 
-    public ComponentName getLauncherComponent() {
-        return mLauncherComponentName;
+    public CharSequence getOnboardingText() {
+        return mOnboardingText;
     }
 
     private void disconnectFromLauncherService() {
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 9319bc6..adb4e33 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -49,7 +49,7 @@
         Key.QS_NIGHTDISPLAY_ADDED,
         Key.SEEN_MULTI_USER,
         Key.NUM_APPS_LAUNCHED,
-        Key.HAS_SWIPED_UP_FOR_RECENTS,
+        Key.HAS_SEEN_RECENTS_ONBOARDING,
     })
     public @interface Key {
         @Deprecated
@@ -78,7 +78,7 @@
         String QS_NIGHTDISPLAY_ADDED = "QsNightDisplayAdded";
         String SEEN_MULTI_USER = "HasSeenMultiUser";
         String NUM_APPS_LAUNCHED = "NumAppsLaunched";
-        String HAS_SWIPED_UP_FOR_RECENTS = "HasSwipedUpForRecents";
+        String HAS_SEEN_RECENTS_ONBOARDING = "HasSeenRecentsOnboarding";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 0f3daf5..d1834e9 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -52,6 +52,7 @@
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
 
 import java.util.function.Consumer;
 
@@ -130,6 +131,8 @@
         providers.put(NotificationGutsManager.class, () -> new NotificationGutsManager(context));
         providers.put(NotificationRemoteInputManager.class,
                 () -> new NotificationRemoteInputManager(context));
+        providers.put(SmartReplyConstants.class,
+                () -> new SmartReplyConstants(Dependency.get(Dependency.MAIN_HANDLER), context));
         providers.put(NotificationListener.class, () -> new NotificationListener(context));
         providers.put(NotificationLogger.class, NotificationLogger::new);
         providers.put(NotificationViewHierarchyManager.class,
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index 348855b..afc9629 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.Looper;
@@ -36,13 +35,18 @@
  */
 public class WirelessChargingAnimation {
 
-    public static final long DURATION = 1400;
+    public static final long DURATION = 1133;
     private static final String TAG = "WirelessChargingView";
     private static final boolean LOCAL_LOGV = false;
 
     private final WirelessChargingView mCurrentWirelessChargingView;
     private static WirelessChargingView mPreviousWirelessChargingView;
 
+    public interface Callback {
+        void onAnimationStarting();
+        void onAnimationEnded();
+    }
+
     /**
      * Constructs an empty WirelessChargingAnimation object.  If looper is null,
      * Looper.myLooper() is used.  Must set
@@ -51,9 +55,9 @@
      * @hide
      */
     public WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper, int
-            batteryLevel) {
+            batteryLevel, Callback callback) {
         mCurrentWirelessChargingView = new WirelessChargingView(context, looper,
-                batteryLevel);
+                batteryLevel, callback);
     }
 
     /**
@@ -61,8 +65,8 @@
      * @hide
      */
     public static WirelessChargingAnimation makeWirelessChargingAnimation(@NonNull Context context,
-            @Nullable Looper looper, int batteryLevel) {
-        return new WirelessChargingAnimation(context, looper, batteryLevel);
+            @Nullable Looper looper, int batteryLevel, Callback callback) {
+        return new WirelessChargingAnimation(context, looper, batteryLevel, callback);
     }
 
     /**
@@ -95,8 +99,11 @@
         private View mView;
         private View mNextView;
         private WindowManager mWM;
+        private Callback mCallback;
 
-        public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel) {
+        public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel,
+                Callback callback) {
+            mCallback = callback;
             mNextView = new WirelessChargingLayout(context, batteryLevel);
             mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER;
 
@@ -149,6 +156,8 @@
         }
 
         public void hide(long duration) {
+            mHandler.removeMessages(HIDE);
+
             if (LOCAL_LOGV) Log.v(TAG, "HIDE: " + this);
             mHandler.sendMessageDelayed(Message.obtain(mHandler, HIDE), duration);
         }
@@ -169,18 +178,6 @@
                     context = mView.getContext();
                 }
                 mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-                // We can resolve the Gravity here by using the Locale for getting
-                // the layout direction
-                final Configuration config = mView.getContext().getResources().getConfiguration();
-                final int gravity = Gravity.getAbsoluteGravity(mGravity,
-                        config.getLayoutDirection());
-                mParams.gravity = gravity;
-                if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
-                    mParams.horizontalWeight = 1.0f;
-                }
-                if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
-                    mParams.verticalWeight = 1.0f;
-                }
                 mParams.packageName = packageName;
                 mParams.hideTimeoutMilliseconds = DURATION;
 
@@ -191,6 +188,9 @@
                 if (LOCAL_LOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
 
                 try {
+                    if (mCallback != null) {
+                        mCallback.onAnimationStarting();
+                    }
                     mWM.addView(mView, mParams);
                 } catch (WindowManager.BadTokenException e) {
                     Slog.d(TAG, "Unable to add wireless charging view. " + e);
@@ -203,6 +203,9 @@
             if (mView != null) {
                 if (mView.getParent() != null) {
                     if (LOCAL_LOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
+                    if (mCallback != null) {
+                        mCallback.onAnimationEnded();
+                    }
                     mWM.removeViewImmediate(mView);
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index c78ea56..8f87d64 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -16,13 +16,16 @@
 
 package com.android.systemui.charging;
 
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
 import java.text.NumberFormat;
@@ -52,10 +55,9 @@
         init(c, attrs, -1);
     }
 
-    private void init(Context c, AttributeSet attrs, int batteryLevel) {
+    private void init(Context context, AttributeSet attrs, int batteryLevel) {
         final int mBatteryLevel = batteryLevel;
-
-        inflate(c, R.layout.wireless_charging_layout, this);
+        inflate(context, R.layout.wireless_charging_layout, this);
 
         // where the circle animation occurs:
         final WirelessChargingView mChargingView = findViewById(R.id.wireless_charging_view);
@@ -68,14 +70,57 @@
 
         if (batteryLevel != UNKNOWN_BATTERY_LEVEL) {
             mPercentage.setText(NumberFormat.getPercentInstance().format(mBatteryLevel / 100f));
-
-            ValueAnimator animator = ObjectAnimator.ofFloat(mPercentage, "textSize",
-                    getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeStart),
-                    getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeEnd));
-
-            animator.setDuration((long) getContext().getResources().getInteger(
-                    R.integer.config_batteryLevelTextAnimationDuration));
-            animator.start();
+            mPercentage.setAlpha(0);
         }
+
+        final long chargingAnimationFadeStartOffset = (long) context.getResources().getInteger(
+                R.integer.wireless_charging_fade_offset);
+        final long chargingAnimationFadeDuration = (long) context.getResources().getInteger(
+                R.integer.wireless_charging_fade_duration);
+        final int batteryLevelTextSizeStart = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_anim_battery_level_text_size_start);
+        final int batteryLevelTextSizeEnd = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_anim_battery_level_text_size_end);
+
+        // Animation Scale: battery percentage text scales from 0% to 100%
+        ValueAnimator textSizeAnimator = ObjectAnimator.ofFloat(mPercentage, "textSize",
+                batteryLevelTextSizeStart, batteryLevelTextSizeEnd);
+        textSizeAnimator.setInterpolator(new PathInterpolator(0, 0, 0, 1));
+        textSizeAnimator.setDuration((long) context.getResources().getInteger(
+                R.integer.wireless_charging_battery_level_text_scale_animation_duration));
+
+        // Animation Opacity: battery percentage text transitions from 0 to 1 opacity
+        ValueAnimator textOpacityAnimator = ObjectAnimator.ofFloat(mPercentage, "alpha", 0, 1);
+        textOpacityAnimator.setInterpolator(Interpolators.LINEAR);
+        textOpacityAnimator.setDuration((long) context.getResources().getInteger(
+                R.integer.wireless_charging_battery_level_text_opacity_duration));
+        textOpacityAnimator.setStartDelay((long) context.getResources().getInteger(
+                R.integer.wireless_charging_anim_opacity_offset));
+
+        // Animation Opacity: battery percentage text fades from 1 to 0 opacity
+        ValueAnimator textFadeAnimator = ObjectAnimator.ofFloat(mPercentage, "alpha", 1, 0);
+        textFadeAnimator.setDuration(chargingAnimationFadeDuration);
+        textFadeAnimator.setInterpolator(Interpolators.LINEAR);
+        textFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
+
+        // Animation Opacity: wireless charging circle animation fades from 1 to 0 opacity
+        ValueAnimator circleFadeAnimator = ObjectAnimator.ofFloat(mChargingView, "alpha",
+                1, 0);
+        circleFadeAnimator.setDuration(chargingAnimationFadeDuration);
+        circleFadeAnimator.setInterpolator(Interpolators.LINEAR);
+        circleFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
+
+        // Animation Opacity: secondary text animation fades from 1 to 0 opacity
+        ValueAnimator secondaryTextFadeAnimator = ObjectAnimator.ofFloat(mSecondaryText, "alpha",
+                1, 0);
+        circleFadeAnimator.setDuration(chargingAnimationFadeDuration);
+        secondaryTextFadeAnimator.setInterpolator(Interpolators.LINEAR);
+        secondaryTextFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
+
+        // play all animations together
+        AnimatorSet animatorSet = new AnimatorSet();
+        animatorSet.playTogether(textSizeAnimator, textOpacityAnimator, textFadeAnimator,
+                circleFadeAnimator, secondaryTextFadeAnimator);
+        animatorSet.start();
     }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.java
index f5edf52..19c6dc1 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.java
@@ -21,10 +21,10 @@
 import android.graphics.Paint;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
 import com.android.settingslib.Utils;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
 final class WirelessChargingView extends View {
@@ -33,21 +33,21 @@
     private float mPathGone;
     private float mInterpolatedPathGone;
     private long mAnimationStartTime;
-    private long mStartSpinCircleAnimationTime;
-    private long mAnimationOffset = 500;
-    private long mTotalAnimationDuration = WirelessChargingAnimation.DURATION - mAnimationOffset;
-    private long mExpandingCircle = (long) (mTotalAnimationDuration * .9);
-    private long mSpinCircleAnimationTime = mTotalAnimationDuration - mExpandingCircle;
+    private long mScaleDotsDuration;
 
-    private boolean mFinishedAnimatingSpinningCircles = false;
+    private boolean mFinishedAnimatingDots = false;
+    private int mNumDots;
 
-    private int mStartAngle = -90;
-    private int mNumSmallCircles = 20;
-    private int mSmallCircleRadius = 10;
+    private double mAngleOffset;
+    private double mCurrAngleOffset;
 
-    private int mMainCircleStartRadius = 100;
-    private int mMainCircleEndRadius = 230;
-    private int mMainCircleCurrentRadius = mMainCircleStartRadius;
+    private int mDotsRadiusStart;
+    private int mDotsRadiusEnd;
+    private int mCurrDotRadius;
+
+    private int mMainCircleStartRadius;
+    private int mMainCircleEndRadius;
+    private int mMainCircleCurrentRadius;
 
     private int mCenterX;
     private int mCenterY;
@@ -72,8 +72,25 @@
 
     public void init(Context context, AttributeSet attr) {
         mContext = context;
+
+        mDotsRadiusStart = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_dots_radius_start);
+        mDotsRadiusEnd = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_dots_radius_end);
+
+        mMainCircleStartRadius = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_circle_radius_start);
+        mMainCircleEndRadius = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_circle_radius_end);
+        mMainCircleCurrentRadius = mMainCircleStartRadius;
+
+        mAngleOffset = context.getResources().getInteger(R.integer.wireless_charging_angle_offset);
+        mScaleDotsDuration = (long) context.getResources().getInteger(
+                R.integer.wireless_charging_scale_dots_duration);
+        mNumDots = context.getResources().getInteger(R.integer.wireless_charging_num_dots);
+
         setupPaint();
-        mInterpolator = new DecelerateInterpolator();
+        mInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
     }
 
     private void setupPaint() {
@@ -92,64 +109,62 @@
         updateDrawingParameters();
         drawCircles(canvas);
 
-        if (!mFinishedAnimatingSpinningCircles) {
+        if (!mFinishedAnimatingDots) {
             invalidate();
         }
     }
 
     /**
      * Draws a larger circle of radius {@link WirelessChargingView#mMainCircleEndRadius} composed of
-     * {@link WirelessChargingView#mNumSmallCircles} smaller circles
+     * {@link WirelessChargingView#mNumDots} smaller circles
      * @param canvas
      */
     private void drawCircles(Canvas canvas) {
         mCenterX = canvas.getWidth() / 2;
         mCenterY = canvas.getHeight() / 2;
 
-        // angleOffset makes small circles look like they're moving around the main circle
-        float angleOffset = mPathGone * 10;
-
-        // draws mNumSmallCircles to compose a larger, main circle
-        for (int circle = 0; circle < mNumSmallCircles; circle++) {
-            double angle = ((mStartAngle + angleOffset) * Math.PI / 180) + (circle * ((2 * Math.PI)
-                    / mNumSmallCircles));
+        // draws mNumDots to compose a larger, main circle
+        for (int circle = 0; circle < mNumDots; circle++) {
+            double angle = ((mCurrAngleOffset) * Math.PI / 180) + (circle * ((2 * Math.PI)
+                    / mNumDots));
 
             int x = (int) (mCenterX + Math.cos(angle) * (mMainCircleCurrentRadius +
-                    mSmallCircleRadius));
+                    mCurrDotRadius));
             int y = (int) (mCenterY + Math.sin(angle) * (mMainCircleCurrentRadius +
-                    mSmallCircleRadius));
+                    mCurrDotRadius));
 
-            canvas.drawCircle(x, y, mSmallCircleRadius, mPaint);
+            canvas.drawCircle(x, y, mCurrDotRadius, mPaint);
         }
 
-        if (mMainCircleCurrentRadius >= mMainCircleEndRadius && !isSpinCircleAnimationStarted()) {
-            mStartSpinCircleAnimationTime = System.currentTimeMillis();
+        if (mMainCircleCurrentRadius >= mMainCircleEndRadius) {
+            mFinishedAnimatingDots = true;
         }
-
-        if (isSpinAnimationFinished()) {
-            mFinishedAnimatingSpinningCircles = true;
-        }
-    }
-
-    private boolean isSpinCircleAnimationStarted() {
-        return mStartSpinCircleAnimationTime != 0;
-    }
-
-    private boolean isSpinAnimationFinished() {
-        return isSpinCircleAnimationStarted() && System.currentTimeMillis() -
-                mStartSpinCircleAnimationTime > mSpinCircleAnimationTime;
     }
 
     private void updateDrawingParameters() {
-        mPathGone = getPathGone(System.currentTimeMillis());
+        long now = System.currentTimeMillis();
+        long timeSinceStart = now - mAnimationStartTime;
+        mPathGone = getPathGone(now);
         mInterpolatedPathGone = mInterpolator.getInterpolation(mPathGone);
 
+        // Position Dots: update main circle radius (that the dots compose)
         if (mPathGone < 1.0f) {
             mMainCircleCurrentRadius = mMainCircleStartRadius + (int) (mInterpolatedPathGone *
                     (mMainCircleEndRadius - mMainCircleStartRadius));
         } else {
             mMainCircleCurrentRadius = mMainCircleEndRadius;
         }
+
+        // Scale Dots: update dot radius
+        if (timeSinceStart < mScaleDotsDuration) {
+            mCurrDotRadius = mDotsRadiusStart + (int) (mInterpolator.getInterpolation((float)
+                    timeSinceStart / mScaleDotsDuration) * (mDotsRadiusEnd - mDotsRadiusStart));
+        } else {
+            mCurrDotRadius = mDotsRadiusEnd;
+        }
+
+        // Rotation Dot Group: dots rotate from 0 to 20 degrees
+        mCurrAngleOffset = mAngleOffset * mPathGone;
     }
 
     /**
@@ -158,6 +173,6 @@
      * For values > 1.0 the larger circle has been drawn and further animation can occur
      */
     private float getPathGone(long now) {
-        return (float) (now - mAnimationStartTime) / (mExpandingCircle);
+        return (float) (now - mAnimationStartTime) / (WirelessChargingAnimation.DURATION);
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index bfb3a6e..092f3d2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -64,7 +64,7 @@
                 createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
                         handler, wakeLock, machine),
                 createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params),
-                new DozeScreenState(wrappedService, handler),
+                new DozeScreenState(wrappedService, handler, params),
                 createDozeScreenBrightness(context, wrappedService, sensorManager, host, handler),
                 new DozeWallpaperState(context)
         });
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 8ec6afc..6ff8e3d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -24,6 +24,7 @@
 
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.internal.util.Preconditions;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.wakelock.WakeLock;
 
@@ -87,12 +88,11 @@
             }
         }
 
-        int screenState() {
+        int screenState(DozeParameters parameters) {
             switch (this) {
                 case UNINITIALIZED:
                 case INITIALIZED:
                 case DOZE:
-                case DOZE_REQUEST_PULSE:
                 case DOZE_AOD_PAUSED:
                     return Display.STATE_OFF;
                 case DOZE_PULSING:
@@ -100,6 +100,9 @@
                 case DOZE_AOD:
                 case DOZE_AOD_PAUSING:
                     return Display.STATE_DOZE_SUSPEND;
+                case DOZE_REQUEST_PULSE:
+                    return parameters.getDisplayNeedsBlanking() ? Display.STATE_OFF
+                            : Display.STATE_ON;
                 default:
                     return Display.STATE_UNKNOWN;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index bef9cb3..3053de3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -19,6 +19,8 @@
 import android.os.Handler;
 import android.view.Display;
 
+import com.android.systemui.statusbar.phone.DozeParameters;
+
 /**
  * Controls the screen when dozing.
  */
@@ -26,17 +28,20 @@
     private final DozeMachine.Service mDozeService;
     private final Handler mHandler;
     private final Runnable mApplyPendingScreenState = this::applyPendingScreenState;
+    private final DozeParameters mParameters;
 
     private int mPendingScreenState = Display.STATE_UNKNOWN;
 
-    public DozeScreenState(DozeMachine.Service service, Handler handler) {
+    public DozeScreenState(DozeMachine.Service service, Handler handler,
+            DozeParameters parameters) {
         mDozeService = service;
         mHandler = handler;
+        mParameters = parameters;
     }
 
     @Override
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
-        int screenState = newState.screenState();
+        int screenState = newState.screenState(mParameters);
 
         if (newState == DozeMachine.State.FINISH) {
             // Make sure not to apply the screen state after DozeService was destroyed.
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index aa56694..3a2b12f 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -26,10 +26,6 @@
 import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.icu.text.MeasureFormat;
-import android.icu.text.MeasureFormat.FormatWidth;
-import android.icu.util.Measure;
-import android.icu.util.MeasureUnit;
 import android.media.AudioAttributes;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -37,11 +33,11 @@
 import android.os.PowerManager;
 import android.os.UserHandle;
 import android.support.annotation.VisibleForTesting;
-import android.text.format.DateUtils;
 import android.util.Slog;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.settingslib.Utils;
+import com.android.settingslib.utils.PowerUtil;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -49,8 +45,6 @@
 
 import java.io.PrintWriter;
 import java.text.NumberFormat;
-import java.util.Locale;
-import java.util.concurrent.TimeUnit;
 
 public class PowerNotificationWarnings implements PowerUI.WarningsUI {
     private static final String TAG = PowerUI.TAG + ".Notification";
@@ -200,12 +194,7 @@
         // override notification copy if hybrid notification enabled
         if (mEstimate != null) {
             title = mContext.getString(R.string.battery_low_title_hybrid);
-            contentText = mContext.getString(
-                    mEstimate.isBasedOnUsage
-                            ? R.string.battery_low_percent_format_hybrid
-                            : R.string.battery_low_percent_format_hybrid_short,
-                    percentage,
-                    getTimeRemainingFormatted());
+            contentText = getHybridContentString(percentage);
         }
 
         final Notification.Builder nb =
@@ -239,21 +228,12 @@
         mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, n, UserHandle.ALL);
     }
 
-    @VisibleForTesting
-    String getTimeRemainingFormatted() {
-        final Locale currentLocale = mContext.getResources().getConfiguration().getLocales().get(0);
-        MeasureFormat frmt = MeasureFormat.getInstance(currentLocale, FormatWidth.NARROW);
-
-        final long remainder = mEstimate.estimateMillis % DateUtils.HOUR_IN_MILLIS;
-        final long hours = TimeUnit.MILLISECONDS.toHours(
-                mEstimate.estimateMillis - remainder);
-        // round down to the nearest 15 min for now to not appear overly precise
-        final long minutes = TimeUnit.MILLISECONDS.toMinutes(
-                remainder - (remainder % TimeUnit.MINUTES.toMillis(15)));
-        final Measure hoursMeasure = new Measure(hours, MeasureUnit.HOUR);
-        final Measure minutesMeasure = new Measure(minutes, MeasureUnit.MINUTE);
-
-        return frmt.formatMeasures(hoursMeasure, minutesMeasure);
+    private String getHybridContentString(String percentage) {
+        return PowerUtil.getBatteryRemainingStringFormatted(
+            mContext,
+            mEstimate.estimateMillis,
+            percentage,
+            mEstimate.isBasedOnUsage);
     }
 
     private PendingIntent pendingBroadcast(String action) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index ea2a432..ac86c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -53,7 +53,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
 
 public class PowerUI extends SystemUI {
     static final String TAG = "PowerUI";
@@ -72,10 +71,11 @@
     private final Configuration mLastConfiguration = new Configuration();
     private int mBatteryLevel = 100;
     private long mTimeRemaining = Long.MAX_VALUE;
-    private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
     private int mPlugType = 0;
     private int mInvalidCharger = 0;
     private EnhancedEstimates mEnhancedEstimates;
+    private boolean mLowWarningShownThisChargeCycle;
+    private boolean mSevereWarningShownThisChargeCycle;
 
     private int mLowBatteryAlertCloseLevel;
     private final int[] mLowBatteryReminderLevels = new int[2];
@@ -88,6 +88,8 @@
     private long mNextLogTime;
     private IThermalService mThermalService;
 
+    @VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
+
     // by using the same instance (method references are not guaranteed to be the same object
     // We create a method reference here so that we are guaranteed that we can remove a callback
     // each time they are created).
@@ -218,6 +220,12 @@
 
                 final boolean plugged = mPlugType != 0;
                 final boolean oldPlugged = oldPlugType != 0;
+                // if we are now unplugged but we were previously plugged in we should allow the
+                // time based trigger again.
+                if (!plugged && plugged != oldPlugged) {
+                    mLowWarningShownThisChargeCycle = false;
+                    mSevereWarningShownThisChargeCycle = false;
+                }
 
                 int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
                 int bucket = findBatteryLevelBucket(mBatteryLevel);
@@ -268,7 +276,6 @@
         boolean isPowerSaver = mPowerManager.isPowerSaveMode();
         // only play SFX when the dialog comes up or the bucket changes
         final boolean playSound = bucket != oldBucket || oldPlugged;
-        long oldTimeRemaining = mTimeRemaining;
         if (mEnhancedEstimates.isHybridNotificationEnabled()) {
             final Estimate estimate = mEnhancedEstimates.getEstimate();
             // Turbo is not always booted once SysUI is running so we have ot make sure we actually
@@ -281,10 +288,18 @@
             }
         }
 
-        if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket, oldTimeRemaining,
-                mTimeRemaining,
-                isPowerSaver, mBatteryStatus)) {
+        if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket,
+                mTimeRemaining, isPowerSaver, mBatteryStatus)) {
             mWarnings.showLowBatteryWarning(playSound);
+
+            // mark if we've already shown a warning this cycle. This will prevent the time based
+            // trigger from spamming users since the time remaining can vary based on current
+            // device usage.
+            if (mTimeRemaining < mEnhancedEstimates.getSevereWarningThreshold()) {
+                mSevereWarningShownThisChargeCycle = true;
+            } else {
+                mLowWarningShownThisChargeCycle = true;
+            }
         } else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining,
                 isPowerSaver)) {
             mWarnings.dismissLowBatteryWarning();
@@ -295,22 +310,14 @@
 
     @VisibleForTesting
     boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
-            int bucket, long oldTimeRemaining, long timeRemaining,
-            boolean isPowerSaver, int mBatteryStatus) {
+            int bucket, long timeRemaining, boolean isPowerSaver, int mBatteryStatus) {
         return !plugged
                 && !isPowerSaver
                 && (((bucket < oldBucket || oldPlugged) && bucket < 0)
-                        || (mEnhancedEstimates.isHybridNotificationEnabled()
-                                && timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
-                                && isHourLess(oldTimeRemaining, timeRemaining)))
+                        || isTimeBasedTrigger(timeRemaining))
                 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN;
     }
 
-    private boolean isHourLess(long oldTimeRemaining, long timeRemaining) {
-        final long dif = oldTimeRemaining - timeRemaining;
-        return dif >= TimeUnit.HOURS.toMillis(1);
-    }
-
     @VisibleForTesting
     boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket,
             long timeRemaining, boolean isPowerSaver) {
@@ -323,6 +330,23 @@
                         || hybridWouldDismiss));
     }
 
+    private boolean isTimeBasedTrigger(long timeRemaining) {
+        if (!mEnhancedEstimates.isHybridNotificationEnabled()) {
+            return false;
+        }
+
+        // Only show the time based warning once per charge cycle
+        final boolean canShowWarning = timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
+                && !mLowWarningShownThisChargeCycle;
+
+        // Only show the severe time based warning once per charge cycle
+        final boolean canShowSevereWarning =
+                timeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
+                        && !mSevereWarningShownThisChargeCycle;
+
+        return canShowWarning || canShowSevereWarning;
+    }
+
     private void initTemperatureWarning() {
         ContentResolver resolver = mContext.getContentResolver();
         Resources resources = mContext.getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 001b409..222c6e82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -20,11 +20,12 @@
 import android.view.View.OnLayoutChangeListener;
 
 import com.android.systemui.Dependency;
-import com.android.systemui.plugins.qs.*;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
 import com.android.systemui.qs.PagedTileLayout.PageListener;
-import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSHost.Callback;
+import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.TouchAnimator.Builder;
 import com.android.systemui.qs.TouchAnimator.Listener;
 import com.android.systemui.tuner.TunerService;
@@ -61,6 +62,7 @@
     private TouchAnimator mTranslationXAnimator;
     private TouchAnimator mTranslationYAnimator;
     private TouchAnimator mNonfirstPageAnimator;
+    private TouchAnimator mNonfirstPageDelayedAnimator;
     private TouchAnimator mBrightnessAnimator;
 
     private boolean mOnKeyguard;
@@ -83,10 +85,10 @@
         QSTileLayout tileLayout = mQsPanel.getTileLayout();
         if (tileLayout instanceof PagedTileLayout) {
             mPagedLayout = ((PagedTileLayout) tileLayout);
-            mPagedLayout.setPageListener(this);
         } else {
             Log.w(TAG, "QS Not using page layout");
         }
+        panel.setPageListener(this);
     }
 
     public void onRtlChanged() {
@@ -271,6 +273,9 @@
                 .setListener(mNonFirstPageListener)
                 .setEndDelay(.5f)
                 .build();
+        mNonfirstPageDelayedAnimator = new TouchAnimator.Builder()
+                .setStartDelay(.14f)
+                .addFloat(tileLayout, "alpha", 0, 1).build();
     }
 
     private boolean isIconInAnimatedRow(int count) {
@@ -315,6 +320,7 @@
             }
         } else {
             mNonfirstPageAnimator.setPosition(position);
+            mNonfirstPageDelayedAnimator.setPosition(position);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 7f34acb..fe3ffb9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -87,6 +87,7 @@
     private View mActionsContainer;
     private View mDragHandle;
     private final int mDragHandleExpandOffset;
+    private View mBackground;
 
     public QSFooterImpl(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -99,6 +100,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        mBackground = findViewById(R.id.qs_footer_background);
         mDivider = findViewById(R.id.qs_footer_divider);
         mEdit = findViewById(android.R.id.edit);
         mEdit.setOnClickListener(view ->
@@ -168,6 +170,7 @@
     @Nullable
     private TouchAnimator createFooterAnimator() {
         return new TouchAnimator.Builder()
+                .addFloat(mBackground, "alpha", 0, 0.90f)
                 .addFloat(mDivider, "alpha", 0, 1)
                 .addFloat(mCarrierText, "alpha", 0, 1)
                 .addFloat(mActionsContainer, "alpha", 0, 1)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 00b6c1e..f7c388d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -26,6 +26,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.service.quicksettings.Tile;
+import android.support.v4.widget.Space;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -97,7 +98,10 @@
             R.layout.quick_settings_brightness_dialog, this, false);
         mTileLayout = new TileLayout(mContext);
         mTileLayout.setListening(mListening);
-        mScrollLayout = new QSScrollLayout(mContext, mBrightnessView, (View) mTileLayout);
+        Space space = new Space(mContext);
+        space.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                mContext.getResources().getDimensionPixelSize(R.dimen.qs_footer_height)));
+        mScrollLayout = new QSScrollLayout(mContext, mBrightnessView, (View) mTileLayout, space);
         addView(mScrollLayout);
 
         addDivider();
@@ -281,6 +285,20 @@
         }
     }
 
+    public void setPageListener(final PagedTileLayout.PageListener pageListener) {
+        if (mTileLayout instanceof PagedTileLayout) {
+            ((PagedTileLayout) mTileLayout).setPageListener(pageListener);
+        } else {
+            mScrollLayout.setOnScrollChangeListener(new OnScrollChangeListener() {
+                @Override
+                public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX,
+                        int oldScrollY) {
+                    pageListener.onPageChanged(scrollY == 0);
+                }
+            });
+        }
+    }
+
     public boolean isExpanded() {
         return mExpanded;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java b/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
index 9a74787..7b1509d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
@@ -14,15 +14,21 @@
 
 package com.android.systemui.qs;
 
+import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.graphics.Rect;
+import android.graphics.Canvas;
 import android.support.v4.widget.NestedScrollView;
+import android.util.Property;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
 import android.widget.LinearLayout;
 
+import com.android.systemui.R;
+import com.android.systemui.qs.touch.OverScroll;
+import com.android.systemui.qs.touch.SwipeDetector;
+
 /**
  * Quick setting scroll view containing the brightness slider and the QS tiles.
  *
@@ -32,12 +38,16 @@
  */
 public class QSScrollLayout extends NestedScrollView {
     private final int mTouchSlop;
+    private final int mFooterHeight;
     private int mLastMotionY;
-    private Rect mHitRect = new Rect();
+    private final SwipeDetector mSwipeDetector;
+    private final OverScrollHelper mOverScrollHelper;
+    private float mContentTranslationY;
 
     public QSScrollLayout(Context context, View... children) {
         super(context);
         mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        mFooterHeight = getResources().getDimensionPixelSize(R.dimen.qs_footer_height);
         LinearLayout linearLayout = new LinearLayout(mContext);
         linearLayout.setLayoutParams(new LinearLayout.LayoutParams(
             LinearLayout.LayoutParams.MATCH_PARENT,
@@ -47,12 +57,40 @@
             linearLayout.addView(view);
         }
         addView(linearLayout);
+        setOverScrollMode(OVER_SCROLL_NEVER);
+        mOverScrollHelper = new OverScrollHelper();
+        mSwipeDetector = new SwipeDetector(context, mOverScrollHelper, SwipeDetector.VERTICAL);
+        mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, true);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (!canScrollVertically(1) && !canScrollVertically(-1)) {
+            return false;
+        }
+        mSwipeDetector.onTouchEvent(ev);
+        return super.onInterceptTouchEvent(ev) || mOverScrollHelper.isInOverScroll();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (!canScrollVertically(1) && !canScrollVertically(-1)) {
+            return false;
+        }
+        mSwipeDetector.onTouchEvent(ev);
+        return super.onTouchEvent(ev);
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        canvas.translate(0, mContentTranslationY);
+        super.dispatchDraw(canvas);
+        canvas.translate(0, -mContentTranslationY);
     }
 
     public boolean shouldIntercept(MotionEvent ev) {
-        getHitRect(mHitRect);
-        if (!mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
-            // Do not intercept touches that are not within this view's bounds.
+        if (ev.getY() > (getBottom() - mFooterHeight)) {
+            // Do not intercept touches that are below the divider between QS and the footer.
             return false;
         }
         if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
@@ -80,4 +118,81 @@
             parent.requestDisallowInterceptTouchEvent(disallowIntercept);
         }
     }
+
+    private void setContentTranslationY(float contentTranslationY) {
+        mContentTranslationY = contentTranslationY;
+        invalidate();
+    }
+
+    private static final Property<QSScrollLayout, Float> CONTENT_TRANS_Y =
+            new Property<QSScrollLayout, Float>(Float.class, "qsScrollLayoutContentTransY") {
+                @Override
+                public Float get(QSScrollLayout qsScrollLayout) {
+                    return qsScrollLayout.mContentTranslationY;
+                }
+
+                @Override
+                public void set(QSScrollLayout qsScrollLayout, Float y) {
+                    qsScrollLayout.setContentTranslationY(y);
+                }
+            };
+
+    private class OverScrollHelper implements SwipeDetector.Listener {
+        private boolean mIsInOverScroll;
+
+        // We use this value to calculate the actual amount the user has overscrolled.
+        private float mFirstDisplacement = 0;
+
+        @Override
+        public void onDragStart(boolean start) {}
+
+        @Override
+        public boolean onDrag(float displacement, float velocity) {
+            // Only overscroll if the user is scrolling down when they're already at the bottom
+            // or scrolling up when they're already at the top.
+            boolean wasInOverScroll = mIsInOverScroll;
+            mIsInOverScroll = (!canScrollVertically(1) && displacement < 0) ||
+                    (!canScrollVertically(-1) && displacement > 0);
+
+            if (wasInOverScroll && !mIsInOverScroll) {
+                // Exit overscroll. This can happen when the user is in overscroll and then
+                // scrolls the opposite way. Note that this causes the reset translation animation
+                // to run while the user is dragging, which feels a bit unnatural.
+                reset();
+            } else if (mIsInOverScroll) {
+                if (Float.compare(mFirstDisplacement, 0) == 0) {
+                    // Because users can scroll before entering overscroll, we need to
+                    // subtract the amount where the user was not in overscroll.
+                    mFirstDisplacement = displacement;
+                }
+                float overscrollY = displacement - mFirstDisplacement;
+                setContentTranslationY(getDampedOverScroll(overscrollY));
+            }
+
+            return mIsInOverScroll;
+        }
+
+        @Override
+        public void onDragEnd(float velocity, boolean fling) {
+            reset();
+        }
+
+        private void reset() {
+            if (Float.compare(mContentTranslationY, 0) != 0) {
+                ObjectAnimator.ofFloat(QSScrollLayout.this, CONTENT_TRANS_Y, 0)
+                        .setDuration(100)
+                        .start();
+            }
+            mIsInOverScroll = false;
+            mFirstDisplacement = 0;
+        }
+
+        public boolean isInOverScroll() {
+            return mIsInOverScroll;
+        }
+
+        private float getDampedOverScroll(float y) {
+            return OverScroll.dampedScroll(y, getHeight());
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 3b9e7bc..65135ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -104,6 +104,11 @@
         setMeasuredDimension(width, height);
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     private static int exactly(int size) {
         return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index ea6e174..3597929 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
+import android.support.annotation.StringRes;
 import android.widget.Switch;
 
 import com.android.internal.app.ColorDisplayController;
@@ -30,6 +31,7 @@
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
+import java.time.LocalTime;
 import java.time.format.DateTimeFormatter;
 
 public class NightDisplayTile extends QSTileImpl<BooleanState>
@@ -39,7 +41,9 @@
      * Pattern for {@link java.time.format.DateTimeFormatter} used to approximate the time to the
      * nearest hour and add on the AM/PM indicator.
      */
-    private static final String APPROXIMATE_HOUR_DATE_TIME_PATTERN = "h a";
+    private static final String HOUR_MINUTE_DATE_TIME_PATTERN = "h a";
+    private static final String APPROXIMATE_HOUR_DATE_TIME_PATTERN = "h:m a";
+
 
     private ColorDisplayController mController;
     private boolean mIsListening;
@@ -110,17 +114,26 @@
 
             case ColorDisplayController.AUTO_MODE_CUSTOM:
                 // User-specified time, approximated to the nearest hour.
-                return isNightLightActivated
-                        ? mContext.getString(
-                                R.string.quick_settings_night_secondary_label_until,
-                                mController.getCustomEndTime().format(
-                                        DateTimeFormatter.ofPattern(
-                                                APPROXIMATE_HOUR_DATE_TIME_PATTERN)))
-                        : mContext.getString(
-                                R.string.quick_settings_night_secondary_label_on_at,
-                                mController.getCustomStartTime().format(
-                                        DateTimeFormatter.ofPattern(
-                                                APPROXIMATE_HOUR_DATE_TIME_PATTERN)));
+                final @StringRes int toggleTimeStringRes;
+                final LocalTime toggleTime;
+                final DateTimeFormatter toggleTimeFormat;
+
+                if (isNightLightActivated) {
+                    toggleTime = mController.getCustomEndTime();
+                    toggleTimeStringRes = R.string.quick_settings_night_secondary_label_until;
+                } else {
+                    toggleTime = mController.getCustomStartTime();
+                    toggleTimeStringRes = R.string.quick_settings_night_secondary_label_on_at;
+                }
+
+                // Choose between just showing the hour or also showing the minutes (based on the
+                // user-selected toggle time). This helps reduce how much space the label takes.
+                toggleTimeFormat = DateTimeFormatter.ofPattern(
+                        toggleTime.getMinute() == 0
+                                ? HOUR_MINUTE_DATE_TIME_PATTERN
+                                : APPROXIMATE_HOUR_DATE_TIME_PATTERN);
+
+                return mContext.getString(toggleTimeStringRes, toggleTime.format(toggleTimeFormat));
 
             default:
                 // No secondary label when auto mode is disabled.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/touch/OverScroll.java b/packages/SystemUI/src/com/android/systemui/qs/touch/OverScroll.java
new file mode 100644
index 0000000..0464886
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/touch/OverScroll.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs.touch;
+
+/**
+ * Utility methods for overscroll damping and related effect.
+ *
+ * Copied from packages/apps/Launcher3/src/com/android/launcher3/touch/OverScroll.java
+ */
+public class OverScroll {
+
+    private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
+
+    /**
+     * This curve determines how the effect of scrolling over the limits of the page diminishes
+     * as the user pulls further and further from the bounds
+     *
+     * @param f The percentage of how much the user has overscrolled.
+     * @return A transformed percentage based on the influence curve.
+     */
+    private static float overScrollInfluenceCurve(float f) {
+        f -= 1.0f;
+        return f * f * f + 1.0f;
+    }
+
+    /**
+     * @param amount The original amount overscrolled.
+     * @param max The maximum amount that the View can overscroll.
+     * @return The dampened overscroll amount.
+     */
+    public static int dampedScroll(float amount, int max) {
+        if (Float.compare(amount, 0) == 0) return 0;
+
+        float f = amount / max;
+        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
+
+        // Clamp this factor, f, to -1 < f < 1
+        if (Math.abs(f) >= 1) {
+            f /= Math.abs(f);
+        }
+
+        return Math.round(OVERSCROLL_DAMP_FACTOR * f * max);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/touch/SwipeDetector.java b/packages/SystemUI/src/com/android/systemui/qs/touch/SwipeDetector.java
new file mode 100644
index 0000000..2522052
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/touch/SwipeDetector.java
@@ -0,0 +1,356 @@
+/*
+ * 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.qs.touch;
+
+import static android.view.MotionEvent.INVALID_POINTER_ID;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+/**
+ * One dimensional scroll/drag/swipe gesture detector.
+ *
+ * Definition of swipe is different from android system in that this detector handles
+ * 'swipe to dismiss', 'swiping up/down a container' but also keeps scrolling state before
+ * swipe action happens
+ *
+ * Copied from packages/apps/Launcher3/src/com/android/launcher3/touch/SwipeDetector.java
+ */
+public class SwipeDetector {
+
+    private static final boolean DBG = false;
+    private static final String TAG = "SwipeDetector";
+
+    private int mScrollConditions;
+    public static final int DIRECTION_POSITIVE = 1 << 0;
+    public static final int DIRECTION_NEGATIVE = 1 << 1;
+    public static final int DIRECTION_BOTH = DIRECTION_NEGATIVE | DIRECTION_POSITIVE;
+
+    private static final float ANIMATION_DURATION = 1200;
+
+    protected int mActivePointerId = INVALID_POINTER_ID;
+
+    /**
+     * The minimum release velocity in pixels per millisecond that triggers fling..
+     */
+    public static final float RELEASE_VELOCITY_PX_MS = 1.0f;
+
+    /**
+     * The time constant used to calculate dampening in the low-pass filter of scroll velocity.
+     * Cutoff frequency is set at 10 Hz.
+     */
+    public static final float SCROLL_VELOCITY_DAMPENING_RC = 1000f / (2f * (float) Math.PI * 10);
+
+    /* Scroll state, this is set to true during dragging and animation. */
+    private ScrollState mState = ScrollState.IDLE;
+
+    enum ScrollState {
+        IDLE,
+        DRAGGING,      // onDragStart, onDrag
+        SETTLING       // onDragEnd
+    }
+
+    public static abstract class Direction {
+
+        abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint);
+
+        /**
+         * Distance in pixels a touch can wander before we think the user is scrolling.
+         */
+        abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos);
+    }
+
+    public static final Direction VERTICAL = new Direction() {
+
+        @Override
+        float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) {
+            return ev.getY(pointerIndex) - refPoint.y;
+        }
+
+        @Override
+        float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos) {
+            return Math.abs(ev.getX(pointerIndex) - downPos.x);
+        }
+    };
+
+    public static final Direction HORIZONTAL = new Direction() {
+
+        @Override
+        float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) {
+            return ev.getX(pointerIndex) - refPoint.x;
+        }
+
+        @Override
+        float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos) {
+            return Math.abs(ev.getY(pointerIndex) - downPos.y);
+        }
+    };
+
+    //------------------- ScrollState transition diagram -----------------------------------
+    //
+    // IDLE ->      (mDisplacement > mTouchSlop) -> DRAGGING
+    // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING
+    // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING
+    // SETTLING -> (View settled) -> IDLE
+
+    private void setState(ScrollState newState) {
+        if (DBG) {
+            Log.d(TAG, "setState:" + mState + "->" + newState);
+        }
+        // onDragStart and onDragEnd is reported ONLY on state transition
+        if (newState == ScrollState.DRAGGING) {
+            initializeDragging();
+            if (mState == ScrollState.IDLE) {
+                reportDragStart(false /* recatch */);
+            } else if (mState == ScrollState.SETTLING) {
+                reportDragStart(true /* recatch */);
+            }
+        }
+        if (newState == ScrollState.SETTLING) {
+            reportDragEnd();
+        }
+
+        mState = newState;
+    }
+
+    public boolean isDraggingOrSettling() {
+        return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING;
+    }
+
+    /**
+     * There's no touch and there's no animation.
+     */
+    public boolean isIdleState() {
+        return mState == ScrollState.IDLE;
+    }
+
+    public boolean isSettlingState() {
+        return mState == ScrollState.SETTLING;
+    }
+
+    public boolean isDraggingState() {
+        return mState == ScrollState.DRAGGING;
+    }
+
+    private final PointF mDownPos = new PointF();
+    private final PointF mLastPos = new PointF();
+    private final Direction mDir;
+
+    private final float mTouchSlop;
+
+    /* Client of this gesture detector can register a callback. */
+    private final Listener mListener;
+
+    private long mCurrentMillis;
+
+    private float mVelocity;
+    private float mLastDisplacement;
+    private float mDisplacement;
+
+    private float mSubtractDisplacement;
+    private boolean mIgnoreSlopWhenSettling;
+
+    public interface Listener {
+        void onDragStart(boolean start);
+
+        boolean onDrag(float displacement, float velocity);
+
+        void onDragEnd(float velocity, boolean fling);
+    }
+
+    public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) {
+        this(ViewConfiguration.get(context).getScaledTouchSlop(), l, dir);
+    }
+
+    @VisibleForTesting
+    protected SwipeDetector(float touchSlope, @NonNull Listener l, @NonNull Direction dir) {
+        mTouchSlop = touchSlope;
+        mListener = l;
+        mDir = dir;
+    }
+
+    public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
+        mScrollConditions = scrollDirectionFlags;
+        mIgnoreSlopWhenSettling = ignoreSlop;
+    }
+
+    private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) {
+        // reject cases where the angle or slop condition is not met.
+        if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop)
+                > Math.abs(mDisplacement)) {
+            return false;
+        }
+
+        // Check if the client is interested in scroll in current direction.
+        if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDisplacement > 0) ||
+                ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDisplacement < 0)) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean onTouchEvent(MotionEvent ev) {
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mActivePointerId = ev.getPointerId(0);
+                mDownPos.set(ev.getX(), ev.getY());
+                mLastPos.set(mDownPos);
+                mLastDisplacement = 0;
+                mDisplacement = 0;
+                mVelocity = 0;
+
+                if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
+                    setState(ScrollState.DRAGGING);
+                }
+                break;
+            //case MotionEvent.ACTION_POINTER_DOWN:
+            case MotionEvent.ACTION_POINTER_UP:
+                int ptrIdx = ev.getActionIndex();
+                int ptrId = ev.getPointerId(ptrIdx);
+                if (ptrId == mActivePointerId) {
+                    final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
+                    mDownPos.set(
+                            ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
+                            ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
+                    mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
+                    mActivePointerId = ev.getPointerId(newPointerIdx);
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                int pointerIndex = ev.findPointerIndex(mActivePointerId);
+                if (pointerIndex == INVALID_POINTER_ID) {
+                    break;
+                }
+                mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos);
+                computeVelocity(mDir.getDisplacement(ev, pointerIndex, mLastPos),
+                        ev.getEventTime());
+
+                // handle state and listener calls.
+                if (mState != ScrollState.DRAGGING && shouldScrollStart(ev, pointerIndex)) {
+                    setState(ScrollState.DRAGGING);
+                }
+                if (mState == ScrollState.DRAGGING) {
+                    reportDragging();
+                }
+                mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                // These are synthetic events and there is no need to update internal values.
+                if (mState == ScrollState.DRAGGING) {
+                    setState(ScrollState.SETTLING);
+                }
+                break;
+            default:
+                break;
+        }
+        return true;
+    }
+
+    public void finishedScrolling() {
+        setState(ScrollState.IDLE);
+    }
+
+    private boolean reportDragStart(boolean recatch) {
+        mListener.onDragStart(!recatch);
+        if (DBG) {
+            Log.d(TAG, "onDragStart recatch:" + recatch);
+        }
+        return true;
+    }
+
+    private void initializeDragging() {
+        if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
+            mSubtractDisplacement = 0;
+        }
+        if (mDisplacement > 0) {
+            mSubtractDisplacement = mTouchSlop;
+        } else {
+            mSubtractDisplacement = -mTouchSlop;
+        }
+    }
+
+    private boolean reportDragging() {
+        if (mDisplacement != mLastDisplacement) {
+            if (DBG) {
+                Log.d(TAG, String.format("onDrag disp=%.1f, velocity=%.1f",
+                        mDisplacement, mVelocity));
+            }
+
+            mLastDisplacement = mDisplacement;
+            return mListener.onDrag(mDisplacement - mSubtractDisplacement, mVelocity);
+        }
+        return true;
+    }
+
+    private void reportDragEnd() {
+        if (DBG) {
+            Log.d(TAG, String.format("onScrollEnd disp=%.1f, velocity=%.1f",
+                    mDisplacement, mVelocity));
+        }
+        mListener.onDragEnd(mVelocity, Math.abs(mVelocity) > RELEASE_VELOCITY_PX_MS);
+
+    }
+
+    /**
+     * Computes the damped velocity.
+     */
+    public float computeVelocity(float delta, long currentMillis) {
+        long previousMillis = mCurrentMillis;
+        mCurrentMillis = currentMillis;
+
+        float deltaTimeMillis = mCurrentMillis - previousMillis;
+        float velocity = (deltaTimeMillis > 0) ? (delta / deltaTimeMillis) : 0;
+        if (Math.abs(mVelocity) < 0.001f) {
+            mVelocity = velocity;
+        } else {
+            float alpha = computeDampeningFactor(deltaTimeMillis);
+            mVelocity = interpolate(mVelocity, velocity, alpha);
+        }
+        return mVelocity;
+    }
+
+    /**
+     * Returns a time-dependent dampening factor using delta time.
+     */
+    private static float computeDampeningFactor(float deltaTime) {
+        return deltaTime / (SCROLL_VELOCITY_DAMPENING_RC + deltaTime);
+    }
+
+    /**
+     * Returns the linear interpolation between two values
+     */
+    private static float interpolate(float from, float to, float alpha) {
+        return (1.0f - alpha) * from + alpha * to;
+    }
+
+    public static long calculateDuration(float velocity, float progressNeeded) {
+        // TODO: make these values constants after tuning.
+        float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity));
+        float travelDistance = Math.max(0.2f, progressNeeded);
+        long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance);
+        if (DBG) {
+            Log.d(TAG, String.format("calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded));
+        }
+        return duration;
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SwipeUpOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
similarity index 87%
rename from packages/SystemUI/src/com/android/systemui/recents/SwipeUpOnboarding.java
rename to packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index b2472bf..0ff8b08 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SwipeUpOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -16,13 +16,11 @@
 
 package com.android.systemui.recents;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 
 import android.annotation.TargetApi;
 import android.app.ActivityManager;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -31,6 +29,8 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.os.Build;
+import android.text.TextUtils;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -41,6 +41,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.systemui.OverviewProxyService;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
@@ -50,9 +51,9 @@
  * Shows onboarding for the new recents interaction in P (codenamed quickstep).
  */
 @TargetApi(Build.VERSION_CODES.P)
-public class SwipeUpOnboarding {
+public class RecentsOnboarding {
 
-    private static final String TAG = "SwipeUpOnboarding";
+    private static final String TAG = "RecentsOnboarding";
     private static final boolean RESET_PREFS_FOR_DEBUG = false;
     private static final long SHOW_DELAY_MS = 500;
     private static final long SHOW_HIDE_DURATION_MS = 300;
@@ -61,6 +62,7 @@
 
     private final Context mContext;
     private final WindowManager mWindowManager;
+    private final OverviewProxyService mOverviewProxyService;
     private final View mLayout;
     private final TextView mTextView;
     private final ImageView mDismissView;
@@ -113,11 +115,12 @@
         }
     };
 
-    public SwipeUpOnboarding(Context context) {
+    public RecentsOnboarding(Context context, OverviewProxyService overviewProxyService) {
         mContext = context;
+        mOverviewProxyService = overviewProxyService;
         final Resources res = context.getResources();
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-        mLayout = LayoutInflater.from(mContext).inflate(R.layout.recents_swipe_up_onboarding, null);
+        mLayout = LayoutInflater.from(mContext).inflate(R.layout.recents_onboarding, null);
         mTextView = mLayout.findViewById(R.id.onboarding_text);
         mDismissView = mLayout.findViewById(R.id.dismiss);
         mDarkBackgroundColor = res.getColor(android.R.color.background_dark);
@@ -135,25 +138,25 @@
         mDismissView.setOnClickListener(v -> hide(true));
 
         if (RESET_PREFS_FOR_DEBUG) {
-            Prefs.putBoolean(mContext, Prefs.Key.HAS_SWIPED_UP_FOR_RECENTS, false);
+            Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_RECENTS_ONBOARDING, false);
             Prefs.putInt(mContext, Prefs.Key.NUM_APPS_LAUNCHED, 0);
         }
     }
 
     public void onConnectedToLauncher() {
-        boolean alreadyLearnedSwipeUpForRecents = Prefs.getBoolean(mContext,
-                Prefs.Key.HAS_SWIPED_UP_FOR_RECENTS, false);
-        if (!mTaskListenerRegistered && !alreadyLearnedSwipeUpForRecents) {
+        boolean alreadySeenRecentsOnboarding = Prefs.getBoolean(mContext,
+                Prefs.Key.HAS_SEEN_RECENTS_ONBOARDING, false);
+        if (!mTaskListenerRegistered && !alreadySeenRecentsOnboarding) {
             ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
             mTaskListenerRegistered = true;
         }
     }
 
     public void onRecentsAnimationStarted() {
-        boolean alreadyLearnedSwipeUpForRecents = Prefs.getBoolean(mContext,
-                Prefs.Key.HAS_SWIPED_UP_FOR_RECENTS, false);
-        if (!alreadyLearnedSwipeUpForRecents) {
-            Prefs.putBoolean(mContext, Prefs.Key.HAS_SWIPED_UP_FOR_RECENTS, true);
+        boolean alreadySeenRecentsOnboarding = Prefs.getBoolean(mContext,
+                Prefs.Key.HAS_SEEN_RECENTS_ONBOARDING, false);
+        if (!alreadySeenRecentsOnboarding) {
+            Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_RECENTS_ONBOARDING, true);
             onDisconnectedFromLauncher();
         }
     }
@@ -173,6 +176,12 @@
     }
 
     public void show() {
+        CharSequence onboardingText = mOverviewProxyService.getOnboardingText();
+        if (TextUtils.isEmpty(onboardingText)) {
+            Log.w(TAG, "Unable to get onboarding text");
+            return;
+        }
+        mTextView.setText(onboardingText);
         // Only show in portrait.
         int orientation = mContext.getResources().getConfiguration().orientation;
         if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) {
@@ -239,7 +248,7 @@
                 flags,
                 PixelFormat.TRANSLUCENT);
         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-        lp.setTitle("SwipeUpOnboarding");
+        lp.setTitle("RecentsOnboarding");
         lp.gravity = Gravity.BOTTOM;
         return lp;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 11bdf6b3..fa177f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -156,7 +156,7 @@
         default void handleShowGlobalActionsMenu() { }
         default void handleShowShutdownUi(boolean isReboot, String reason) { }
 
-        default void showChargingAnimation(int batteryLevel) {  }
+        default void showWirelessChargingAnimation(int batteryLevel) {  }
 
         default void onRotationProposal(int rotation, boolean isValid) { }
 
@@ -497,7 +497,7 @@
     }
 
     @Override
-    public void showChargingAnimation(int batteryLevel) {
+    public void showWirelessChargingAnimation(int batteryLevel) {
         mHandler.removeMessages(MSG_SHOW_CHARGING_ANIMATION);
         mHandler.obtainMessage(MSG_SHOW_CHARGING_ANIMATION, batteryLevel, 0)
                 .sendToTarget();
@@ -784,7 +784,7 @@
                     break;
                 case MSG_SHOW_CHARGING_ANIMATION:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).showChargingAnimation(msg.arg1);
+                        mCallbacks.get(i).showWirelessChargingAnimation(msg.arg1);
                     }
                     break;
                 case MSG_SHOW_PINNING_TOAST_ENTER_EXIT:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index d6beb7f..ab89a52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -249,6 +249,9 @@
                     (GradientDrawable) ((LayerDrawable) mBackground).getDrawable(0);
             gradientDrawable.setXfermode(
                     running ? new PorterDuffXfermode(PorterDuff.Mode.SRC) : null);
+            // Speed optimization: disable AA if transfer mode is not SRC_OVER. AA is not easy to
+            // spot during animation anyways.
+            gradientDrawable.setAntiAlias(!running);
         }
         if (!mExpandAnimationRunning) {
             setDrawableAlpha(mDrawableAlpha);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index e811ed3..c4d0b79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Build;
-import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -36,6 +35,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.HybridGroupManager;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
@@ -44,6 +44,7 @@
 import com.android.systemui.statusbar.notification.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.SmartReplyView;
 
 /**
@@ -75,6 +76,8 @@
 
     private RemoteInputView mExpandedRemoteInput;
     private RemoteInputView mHeadsUpRemoteInput;
+
+    private SmartReplyConstants mSmartReplyConstants;
     private SmartReplyView mExpandedSmartReplyView;
 
     private NotificationViewWrapper mContractedWrapper;
@@ -145,6 +148,7 @@
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mHybridGroupManager = new HybridGroupManager(getContext(), this);
+        mSmartReplyConstants = Dependency.get(SmartReplyConstants.class);
         initView();
     }
 
@@ -1166,8 +1170,7 @@
             return;
         }
 
-        boolean enableSmartReplies = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS, 0) != 0;
+        boolean enableSmartReplies = mSmartReplyConstants.isEnabled();
 
         boolean hasRemoteInput = false;
         RemoteInput remoteInputWithChoices = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index f25379a..3c480d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -299,6 +299,11 @@
                         }
                     }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
                 }
+                try {
+                    mBarService.onNotificationDirectReplied(entry.notification.getKey());
+                } catch (RemoteException e) {
+                    // Nothing to do, system going down
+                }
             }
         });
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 3ebeb4d..3dfb913 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -379,7 +379,7 @@
         // Because space is usually constrained in the auto use-case, there should not be a
         // pinned notification when the shade has been expanded. Ensure this by removing all heads-
         // up notifications.
-        mHeadsUpManager.removeAllHeadsUpEntries();
+        mHeadsUpManager.releaseAllImmediately();
         super.animateExpandNotificationsPanel();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 8227b77..d3a325d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -21,6 +21,8 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import com.android.internal.widget.MessagingImageMessage;
+import com.android.internal.widget.MessagingMessage;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
@@ -117,13 +119,15 @@
 
     @Override
     protected boolean transformScale(TransformState otherState) {
-        return true;
+        return sameAs(otherState);
     }
 
     @Override
     public void recycle() {
         super.recycle();
-        sInstancePool.release(this);
+        if (getClass() == ImageTransformState.class) {
+            sInstancePool.release(this);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingImageTransformState.java
new file mode 100644
index 0000000..b97995d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingImageTransformState.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.util.Pools;
+import android.view.View;
+
+import com.android.internal.widget.MessagingImageMessage;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ViewTransformationHelper;
+
+/**
+ * A transform state of a image view.
+*/
+public class MessagingImageTransformState extends ImageTransformState {
+    private static Pools.SimplePool<MessagingImageTransformState> sInstancePool
+            = new Pools.SimplePool<>(40);
+    private static final int START_ACTUAL_WIDTH = R.id.transformation_start_actual_width;
+    private static final int START_ACTUAL_HEIGHT = R.id.transformation_start_actual_height;
+    private MessagingImageMessage mImageMessage;
+
+    @Override
+    public void initFrom(View view, TransformInfo transformInfo) {
+        super.initFrom(view, transformInfo);
+        mImageMessage = (MessagingImageMessage) view;
+    }
+
+    @Override
+    protected boolean sameAs(TransformState otherState) {
+        if (super.sameAs(otherState)) {
+            return true;
+        }
+        if (otherState instanceof MessagingImageTransformState) {
+            MessagingImageTransformState otherMessage = (MessagingImageTransformState) otherState;
+            return mImageMessage.sameAs(otherMessage.mImageMessage);
+        }
+        return false;
+    }
+
+    public static MessagingImageTransformState obtain() {
+        MessagingImageTransformState instance = sInstancePool.acquire();
+        if (instance != null) {
+            return instance;
+        }
+        return new MessagingImageTransformState();
+    }
+
+    @Override
+    protected boolean transformScale(TransformState otherState) {
+        return false;
+    }
+
+    @Override
+    protected void transformViewFrom(TransformState otherState, int transformationFlags,
+            ViewTransformationHelper.CustomTransformation customTransformation,
+            float transformationAmount) {
+        super.transformViewFrom(otherState, transformationFlags, customTransformation,
+                transformationAmount);
+        float interpolatedValue = mDefaultInterpolator.getInterpolation(
+                transformationAmount);
+        if (otherState instanceof MessagingImageTransformState && sameAs(otherState)) {
+            MessagingImageMessage otherMessage
+                    = ((MessagingImageTransformState) otherState).mImageMessage;
+            if (transformationAmount == 0.0f) {
+                setStartActualWidth(otherMessage.getActualWidth());
+                setStartActualHeight(otherMessage.getActualHeight());
+            }
+            float startActualWidth = getStartActualWidth();
+            mImageMessage.setActualWidth(
+                    (int) NotificationUtils.interpolate(startActualWidth,
+                            mImageMessage.getStaticWidth(),
+                            interpolatedValue));
+            float startActualHeight = getStartActualHeight();
+            mImageMessage.setActualHeight(
+                    (int) NotificationUtils.interpolate(startActualHeight,
+                            mImageMessage.getHeight(),
+                            interpolatedValue));
+        }
+    }
+
+    public int getStartActualWidth() {
+        Object tag = mTransformedView.getTag(START_ACTUAL_WIDTH);
+        return tag == null ? -1 : (int) tag;
+    }
+
+    public void setStartActualWidth(int actualWidth) {
+        mTransformedView.setTag(START_ACTUAL_WIDTH, actualWidth);
+    }
+
+    public int getStartActualHeight() {
+        Object tag = mTransformedView.getTag(START_ACTUAL_HEIGHT);
+        return tag == null ? -1 : (int) tag;
+    }
+
+    public void setStartActualHeight(int actualWidth) {
+        mTransformedView.setTag(START_ACTUAL_HEIGHT, actualWidth);
+    }
+
+    @Override
+    public void recycle() {
+        super.recycle();
+        if (getClass() == MessagingImageTransformState.class) {
+            sInstancePool.release(this);
+        }
+    }
+
+    @Override
+    protected void resetTransformedView() {
+        super.resetTransformedView();
+        mImageMessage.setActualWidth(mImageMessage.getStaticWidth());
+        mImageMessage.setActualHeight(mImageMessage.getHeight());
+    }
+
+    @Override
+    protected void reset() {
+        super.reset();
+        mImageMessage = null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
index 113118a..314a31d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -22,6 +22,7 @@
 import android.view.ViewGroup;
 
 import com.android.internal.widget.MessagingGroup;
+import com.android.internal.widget.MessagingImageMessage;
 import com.android.internal.widget.MessagingLayout;
 import com.android.internal.widget.MessagingLinearLayout;
 import com.android.internal.widget.MessagingMessage;
@@ -30,6 +31,7 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * A transform state of the action list
@@ -156,6 +158,7 @@
         }
         appear(ownGroup.getAvatar(), transformationAmount);
         appear(ownGroup.getSenderView(), transformationAmount);
+        appear(ownGroup.getIsolatedMessage(), transformationAmount);
         setClippingDeactivated(ownGroup.getSenderView(), true);
         setClippingDeactivated(ownGroup.getAvatar(), true);
     }
@@ -187,12 +190,13 @@
         }
         disappear(ownGroup.getAvatar(), transformationAmount);
         disappear(ownGroup.getSenderView(), transformationAmount);
+        disappear(ownGroup.getIsolatedMessage(), transformationAmount);
         setClippingDeactivated(ownGroup.getSenderView(), true);
         setClippingDeactivated(ownGroup.getAvatar(), true);
     }
 
     private void appear(View child, float transformationAmount) {
-        if (child.getVisibility() == View.GONE) {
+        if (child == null || child.getVisibility() == View.GONE) {
             return;
         }
         TransformState ownState = TransformState.createFrom(child, mTransformInfo);
@@ -201,7 +205,7 @@
     }
 
     private void disappear(View child, float transformationAmount) {
-        if (child.getVisibility() == View.GONE) {
+        if (child == null || child.getVisibility() == View.GONE) {
             return;
         }
         TransformState ownState = TransformState.createFrom(child, mTransformInfo);
@@ -224,22 +228,24 @@
 
     private void transformGroups(MessagingGroup ownGroup, MessagingGroup otherGroup,
             float transformationAmount, boolean to) {
+        boolean useLinearTransformation =
+                otherGroup.getIsolatedMessage() == null && !mTransformInfo.isAnimating();
         transformView(transformationAmount, to, ownGroup.getSenderView(), otherGroup.getSenderView(),
-                true /* sameAsAny */);
+                true /* sameAsAny */, useLinearTransformation);
         transformView(transformationAmount, to, ownGroup.getAvatar(), otherGroup.getAvatar(),
-                true /* sameAsAny */);
-        MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
-        MessagingLinearLayout otherMessages = otherGroup.getMessageContainer();
+                true /* sameAsAny */, useLinearTransformation);
+        List<MessagingMessage> ownMessages = ownGroup.getMessages();
+        List<MessagingMessage> otherMessages = otherGroup.getMessages();
         float previousTranslation = 0;
-        for (int i = 0; i < ownMessages.getChildCount(); i++) {
-            View child = ownMessages.getChildAt(ownMessages.getChildCount() - 1 - i);
+        for (int i = 0; i < ownMessages.size(); i++) {
+            View child = ownMessages.get(ownMessages.size() - 1 - i).getView();
             if (isGone(child)) {
                 continue;
             }
-            int otherIndex = otherMessages.getChildCount() - 1 - i;
+            int otherIndex = otherMessages.size() - 1 - i;
             View otherChild = null;
             if (otherIndex >= 0) {
-                otherChild = otherMessages.getChildAt(otherIndex);
+                otherChild = otherMessages.get(otherIndex).getView();
                 if (isGone(otherChild)) {
                     otherChild = null;
                 }
@@ -252,7 +258,12 @@
                     transformationAmount = 1.0f - transformationAmount;
                 }
             }
-            transformView(transformationAmount, to, child, otherChild, false /* sameAsAny */);
+            transformView(transformationAmount, to, child, otherChild, false, /* sameAsAny */
+                    useLinearTransformation);
+            if (transformationAmount == 0.0f
+                    && otherGroup.getIsolatedMessage() == otherChild) {
+                ownGroup.setTransformingImages(true);
+            }
             if (otherChild == null) {
                 child.setTranslationY(previousTranslation);
                 setClippingDeactivated(child, true);
@@ -264,12 +275,13 @@
                 previousTranslation = child.getTranslationY();
             }
         }
+        ownGroup.updateClipRect();
     }
 
     private void transformView(float transformationAmount, boolean to, View ownView,
-            View otherView, boolean sameAsAny) {
+            View otherView, boolean sameAsAny, boolean useLinearTransformation) {
         TransformState ownState = TransformState.createFrom(ownView, mTransformInfo);
-        if (!mTransformInfo.isAnimating()) {
+        if (useLinearTransformation) {
             ownState.setDefaultInterpolator(Interpolators.LINEAR);
         }
         ownState.setIsSameAsAnyView(sameAsAny);
@@ -339,11 +351,15 @@
             if (!isGone(ownGroup)) {
                 MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
                 for (int j = 0; j < ownMessages.getChildCount(); j++) {
-                    MessagingMessage child = (MessagingMessage) ownMessages.getChildAt(j);
+                    View child = ownMessages.getChildAt(j);
                     setVisible(child, visible, force);
                 }
                 setVisible(ownGroup.getAvatar(), visible, force);
                 setVisible(ownGroup.getSenderView(), visible, force);
+                MessagingImageMessage isolatedMessage = ownGroup.getIsolatedMessage();
+                if (isolatedMessage != null) {
+                    setVisible(isolatedMessage, visible, force);
+                }
             }
         }
     }
@@ -375,11 +391,17 @@
                 }
                 resetTransformedView(ownGroup.getAvatar());
                 resetTransformedView(ownGroup.getSenderView());
+                MessagingImageMessage isolatedMessage = ownGroup.getIsolatedMessage();
+                if (isolatedMessage != null) {
+                    resetTransformedView(isolatedMessage);
+                }
                 setClippingDeactivated(ownGroup.getAvatar(), false);
                 setClippingDeactivated(ownGroup.getSenderView(), false);
                 ownGroup.setTranslationY(0);
                 ownGroup.getMessageContainer().setTranslationY(0);
             }
+            ownGroup.setTransformingImages(false);
+            ownGroup.updateClipRect();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 918b6ed..fc8ceb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -26,6 +26,7 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import com.android.internal.widget.MessagingImageMessage;
 import com.android.internal.widget.MessagingPropertyAnimator;
 import com.android.internal.widget.ViewClippingUtil;
 import com.android.systemui.Interpolators;
@@ -80,7 +81,7 @@
     private boolean mSameAsAny;
     private float mTransformationEndY = UNDEFINED;
     private float mTransformationEndX = UNDEFINED;
-    private Interpolator mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN;
+    protected Interpolator mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN;
 
     public void initFrom(View view, TransformInfo transformInfo) {
         mTransformedView = view;
@@ -131,7 +132,7 @@
         transformViewFrom(otherState, TRANSFORM_Y, null, transformationAmount);
     }
 
-    private void transformViewFrom(TransformState otherState, int transformationFlags,
+    protected void transformViewFrom(TransformState otherState, int transformationFlags,
             ViewTransformationHelper.CustomTransformation customTransformation,
             float transformationAmount) {
         final View transformedView = mTransformedView;
@@ -449,6 +450,11 @@
             result.initFrom(view, transformInfo);
             return result;
         }
+        if (view instanceof MessagingImageMessage) {
+            MessagingImageTransformState result = MessagingImageTransformState.obtain();
+            result.initFrom(view, transformInfo);
+            return result;
+        }
         if (view instanceof ImageView) {
             ImageTransformState result = ImageTransformState.obtain();
             result.initFrom(view, transformInfo);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
new file mode 100644
index 0000000..aba5cdf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.support.v4.util.ArraySet;
+import android.util.Log;
+import android.util.Pools;
+import android.view.View;
+import android.view.ViewTreeObserver;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Stack;
+
+/**
+ * A implementation of HeadsUpManager for phone and car.
+ */
+public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
+       ViewTreeObserver.OnComputeInternalInsetsListener, VisualStabilityManager.Callback,
+       OnHeadsUpChangedListener {
+    private static final String TAG = "HeadsUpManagerPhone";
+    private static final boolean DEBUG = false;
+
+    private final View mStatusBarWindowView;
+    private final int mStatusBarHeight;
+    private final NotificationGroupManager mGroupManager;
+    private final StatusBar mBar;
+    private final VisualStabilityManager mVisualStabilityManager;
+
+    private boolean mReleaseOnExpandFinish;
+    private boolean mTrackingHeadsUp;
+    private HashSet<String> mSwipedOutKeys = new HashSet<>();
+    private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
+    private ArraySet<NotificationData.Entry> mEntriesToRemoveWhenReorderingAllowed
+            = new ArraySet<>();
+    private boolean mIsExpanded;
+    private int[] mTmpTwoArray = new int[2];
+    private boolean mHeadsUpGoingAway;
+    private boolean mWaitingOnCollapseWhenGoingAway;
+    private boolean mIsObserving;
+    private int mStatusBarState;
+
+    private final Pools.Pool<HeadsUpEntryPhone> mEntryPool = new Pools.Pool<HeadsUpEntryPhone>() {
+        private Stack<HeadsUpEntryPhone> mPoolObjects = new Stack<>();
+
+        @Override
+        public HeadsUpEntryPhone acquire() {
+            if (!mPoolObjects.isEmpty()) {
+                return mPoolObjects.pop();
+            }
+            return new HeadsUpEntryPhone();
+        }
+
+        @Override
+        public boolean release(@NonNull HeadsUpEntryPhone instance) {
+            mPoolObjects.push(instance);
+            return true;
+        }
+    };
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    //  Constructor:
+
+    public HeadsUpManagerPhone(@NonNull final Context context, @NonNull View statusBarWindowView,
+            @NonNull NotificationGroupManager groupManager, @NonNull StatusBar bar,
+            @NonNull VisualStabilityManager visualStabilityManager) {
+        super(context);
+
+        mStatusBarWindowView = statusBarWindowView;
+        mGroupManager = groupManager;
+        mBar = bar;
+        mVisualStabilityManager = visualStabilityManager;
+
+        Resources resources = mContext.getResources();
+        mStatusBarHeight = resources.getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height);
+
+        addListener(new OnHeadsUpChangedListener() {
+            @Override
+            public void onHeadsUpPinnedModeChanged(boolean hasPinnedNotification) {
+                if (DEBUG) Log.w(TAG, "onHeadsUpPinnedModeChanged");
+                updateTouchableRegionListener();
+            }
+        });
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    //  Public methods:
+
+    /**
+     * Decides whether a click is invalid for a notification, i.e it has not been shown long enough
+     * that a user might have consciously clicked on it.
+     *
+     * @param key the key of the touched notification
+     * @return whether the touch is invalid and should be discarded
+     */
+    public boolean shouldSwallowClick(@NonNull String key) {
+        HeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
+        return entry != null && mClock.currentTimeMillis() < entry.postTime;
+    }
+
+    public void onExpandingFinished() {
+        if (mReleaseOnExpandFinish) {
+            releaseAllImmediately();
+            mReleaseOnExpandFinish = false;
+        } else {
+            for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) {
+                if (isHeadsUp(entry.key)) {
+                    // Maybe the heads-up was removed already
+                    removeHeadsUpEntry(entry);
+                }
+            }
+        }
+        mEntriesToRemoveAfterExpand.clear();
+    }
+
+    /**
+     * Sets the tracking-heads-up flag. If the flag is true, HeadsUpManager doesn't remove the entry
+     * from the list even after a Heads Up Notification is gone.
+     */
+    public void setTrackingHeadsUp(boolean trackingHeadsUp) {
+        mTrackingHeadsUp = trackingHeadsUp;
+    }
+
+    /**
+     * Notify that the status bar panel gets expanded or collapsed.
+     *
+     * @param isExpanded True to notify expanded, false to notify collapsed.
+     */
+    public void setIsPanelExpanded(boolean isExpanded) {
+        if (isExpanded != mIsExpanded) {
+            mIsExpanded = isExpanded;
+            if (isExpanded) {
+                // make sure our state is sane
+                mWaitingOnCollapseWhenGoingAway = false;
+                mHeadsUpGoingAway = false;
+                updateTouchableRegionListener();
+            }
+        }
+    }
+
+    /**
+     * Set the current state of the statusbar.
+     */
+    public void setStatusBarState(int statusBarState) {
+        mStatusBarState = statusBarState;
+    }
+
+    /**
+     * Set that we are exiting the headsUp pinned mode, but some notifications might still be
+     * animating out. This is used to keep the touchable regions in a sane state.
+     */
+    public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+        if (headsUpGoingAway != mHeadsUpGoingAway) {
+            mHeadsUpGoingAway = headsUpGoingAway;
+            if (!headsUpGoingAway) {
+                waitForStatusBarLayout();
+            }
+            updateTouchableRegionListener();
+        }
+    }
+
+    /**
+     * Notifies that a remote input textbox in notification gets active or inactive.
+     * @param entry The entry of the target notification.
+     * @param remoteInputActive True to notify active, False to notify inactive.
+     */
+    public void setRemoteInputActive(
+            @NonNull NotificationData.Entry entry, boolean remoteInputActive) {
+        HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.key);
+        if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) {
+            headsUpEntry.remoteInputActive = remoteInputActive;
+            if (remoteInputActive) {
+                headsUpEntry.removeAutoRemovalCallbacks();
+            } else {
+                headsUpEntry.updateEntry(false /* updatePostTime */);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    public void removeMinimumDisplayTimeForTesting() {
+        mMinimumDisplayTime = 0;
+        mHeadsUpNotificationDecay = 0;
+        mTouchAcceptanceDelay = 0;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    //  HeadsUpManager public methods overrides:
+
+    @Override
+    public boolean isTrackingHeadsUp() {
+        return mTrackingHeadsUp;
+    }
+
+    @Override
+    public void snooze() {
+        super.snooze();
+        mReleaseOnExpandFinish = true;
+    }
+
+    /**
+     * React to the removal of the notification in the heads up.
+     *
+     * @return true if the notification was removed and false if it still needs to be kept around
+     * for a bit since it wasn't shown long enough
+     */
+    @Override
+    public boolean removeNotification(@NonNull String key, boolean ignoreEarliestRemovalTime) {
+        if (wasShownLongEnough(key) || ignoreEarliestRemovalTime) {
+            return super.removeNotification(key, ignoreEarliestRemovalTime);
+        } else {
+            HeadsUpEntryPhone entry = getHeadsUpEntryPhone(key);
+            entry.removeAsSoonAsPossible();
+            return false;
+        }
+    }
+
+    public void addSwipedOutNotification(@NonNull String key) {
+        mSwipedOutKeys.add(key);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    //  Dumpable overrides:
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("HeadsUpManagerPhone state:");
+        dumpInternal(fd, pw, args);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    //  ViewTreeObserver.OnComputeInternalInsetsListener overrides:
+
+    /**
+     * Overridden from TreeObserver.
+     */
+    @Override
+    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+        if (mIsExpanded || mBar.isBouncerShowing()) {
+            // The touchable region is always the full area when expanded
+            return;
+        }
+        if (hasPinnedHeadsUp()) {
+            ExpandableNotificationRow topEntry = getTopEntry().row;
+            if (topEntry.isChildInGroup()) {
+                final ExpandableNotificationRow groupSummary
+                        = mGroupManager.getGroupSummary(topEntry.getStatusBarNotification());
+                if (groupSummary != null) {
+                    topEntry = groupSummary;
+                }
+            }
+            topEntry.getLocationOnScreen(mTmpTwoArray);
+            int minX = mTmpTwoArray[0];
+            int maxX = mTmpTwoArray[0] + topEntry.getWidth();
+            int maxY = topEntry.getIntrinsicHeight();
+
+            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+            info.touchableRegion.set(minX, 0, maxX, maxY);
+        } else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) {
+            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+            info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    //  VisualStabilityManager.Callback overrides:
+
+    @Override
+    public void onReorderingAllowed() {
+        mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(false);
+        for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) {
+            if (isHeadsUp(entry.key)) {
+                // Maybe the heads-up was removed already
+                removeHeadsUpEntry(entry);
+            }
+        }
+        mEntriesToRemoveWhenReorderingAllowed.clear();
+        mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(true);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    //  HeadsUpManager utility (protected) methods overrides:
+
+    @Override
+    protected HeadsUpEntry createHeadsUpEntry() {
+        return mEntryPool.acquire();
+    }
+
+    @Override
+    protected void releaseHeadsUpEntry(HeadsUpEntry entry) {
+        entry.reset();
+        mEntryPool.release((HeadsUpEntryPhone) entry);
+    }
+
+    @Override
+    protected boolean shouldHeadsUpBecomePinned(NotificationData.Entry entry) {
+          return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded
+                  || super.shouldHeadsUpBecomePinned(entry);
+    }
+
+    @Override
+    protected void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
+        super.dumpInternal(fd, pw, args);
+        pw.print("  mStatusBarState="); pw.println(mStatusBarState);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    //  Private utility methods:
+
+    @Nullable
+    private HeadsUpEntryPhone getHeadsUpEntryPhone(@NonNull String key) {
+        return (HeadsUpEntryPhone) getHeadsUpEntry(key);
+    }
+
+    @Nullable
+    private HeadsUpEntryPhone getTopHeadsUpEntryPhone() {
+        return (HeadsUpEntryPhone) getTopHeadsUpEntry();
+    }
+
+    private boolean wasShownLongEnough(@NonNull String key) {
+        if (mSwipedOutKeys.contains(key)) {
+            // We always instantly dismiss views being manually swiped out.
+            mSwipedOutKeys.remove(key);
+            return true;
+        }
+
+        HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(key);
+        HeadsUpEntryPhone topEntry = getTopHeadsUpEntryPhone();
+        return headsUpEntry != topEntry || headsUpEntry.wasShownLongEnough();
+    }
+
+    /**
+     * We need to wait on the whole panel to collapse, before we can remove the touchable region
+     * listener.
+     */
+    private void waitForStatusBarLayout() {
+        mWaitingOnCollapseWhenGoingAway = true;
+        mStatusBarWindowView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+            @Override
+            public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                    int oldLeft,
+                    int oldTop, int oldRight, int oldBottom) {
+                if (mStatusBarWindowView.getHeight() <= mStatusBarHeight) {
+                    mStatusBarWindowView.removeOnLayoutChangeListener(this);
+                    mWaitingOnCollapseWhenGoingAway = false;
+                    updateTouchableRegionListener();
+                }
+            }
+        });
+    }
+
+    private void updateTouchableRegionListener() {
+        boolean shouldObserve = hasPinnedHeadsUp() || mHeadsUpGoingAway
+                || mWaitingOnCollapseWhenGoingAway;
+        if (shouldObserve == mIsObserving) {
+            return;
+        }
+        if (shouldObserve) {
+            mStatusBarWindowView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+            mStatusBarWindowView.requestLayout();
+        } else {
+            mStatusBarWindowView.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+        }
+        mIsObserving = shouldObserve;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    //  HeadsUpEntryPhone:
+
+    protected class HeadsUpEntryPhone extends HeadsUpManager.HeadsUpEntry {
+        public void setEntry(@NonNull final NotificationData.Entry entry) {
+           Runnable removeHeadsUpRunnable = () -> {
+                if (!mVisualStabilityManager.isReorderingAllowed()) {
+                    mEntriesToRemoveWhenReorderingAllowed.add(entry);
+                    mVisualStabilityManager.addReorderingAllowedCallback(
+                            HeadsUpManagerPhone.this);
+                } else if (!mTrackingHeadsUp) {
+                    removeHeadsUpEntry(entry);
+                } else {
+                    mEntriesToRemoveAfterExpand.add(entry);
+                }
+            };
+
+            super.setEntry(entry, removeHeadsUpRunnable);
+        }
+
+        public boolean wasShownLongEnough() {
+            return earliestRemovaltime < mClock.currentTimeMillis();
+        }
+
+        @Override
+        public void updateEntry(boolean updatePostTime) {
+            super.updateEntry(updatePostTime);
+
+            if (mEntriesToRemoveAfterExpand.contains(entry)) {
+                mEntriesToRemoveAfterExpand.remove(entry);
+            }
+            if (mEntriesToRemoveWhenReorderingAllowed.contains(entry)) {
+                mEntriesToRemoveWhenReorderingAllowed.remove(entry);
+            }
+        }
+
+        @Override
+        public void expanded(boolean expanded) {
+            if (this.expanded == expanded) {
+                return;
+            }
+
+            this.expanded = expanded;
+            if (expanded) {
+                removeAutoRemovalCallbacks();
+            } else {
+                updateEntry(false /* updatePostTime */);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index c85571c..2bfdefe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -23,7 +23,7 @@
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 /**
@@ -31,7 +31,7 @@
  */
 public class HeadsUpTouchHelper implements Gefingerpoken {
 
-    private HeadsUpManager mHeadsUpManager;
+    private HeadsUpManagerPhone mHeadsUpManager;
     private NotificationStackScrollLayout mStackScroller;
     private int mTrackingPointer;
     private float mTouchSlop;
@@ -43,7 +43,7 @@
     private NotificationPanelView mPanel;
     private ExpandableNotificationRow mPickedChild;
 
-    public HeadsUpTouchHelper(HeadsUpManager headsUpManager,
+    public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager,
             NotificationStackScrollLayout stackScroller,
             NotificationPanelView notificationPanelView) {
         mHeadsUpManager = headsUpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 0d36efd..d15c771 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -16,6 +16,12 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
+import static com.android.systemui.OverviewProxyService.TAG_OPS;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
@@ -27,26 +33,19 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
-
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
 import com.android.systemui.Dependency;
 import com.android.systemui.OverviewProxyService;
+import com.android.systemui.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
 import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.tuner.TunerService;
 
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_TOP;
-import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
-import static com.android.systemui.OverviewProxyService.TAG_OPS;
-
 /**
  * Class to detect gestures on the navigation bar.
  */
@@ -84,8 +83,16 @@
     private int mTouchDownY;
     private boolean mDownOnRecents;
     private VelocityTracker mVelocityTracker;
-    private OverviewProxyService mOverviewEventSender = Dependency.get(OverviewProxyService.class);
+    private OverviewProxyService mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+    private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
+        @Override
+        public void onRecentsAnimationStarted() {
+            mRecentsAnimationStarted = true;
+            mQuickScrubController.cancelQuickSwitch();
+        }
+    };
 
+    private boolean mRecentsAnimationStarted;
     private boolean mDockWindowEnabled;
     private boolean mDockWindowTouchSlopExceeded;
     private int mDragMode;
@@ -97,10 +104,12 @@
         mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
         mQuickScrubController = new QuickScrubController(context);
         Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
+        mOverviewProxyService.addCallback(mOverviewProxyListener);
     }
 
     public void destroy() {
         Dependency.get(TunerService.class).removeTunable(this);
+        mOverviewProxyService.removeCallback(mOverviewProxyListener);
     }
 
     public void setComponents(RecentsComponent recentsComponent, Divider divider,
@@ -117,7 +126,7 @@
     }
 
     private boolean proxyMotionEvents(MotionEvent event) {
-        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+        final IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
         if (overviewProxy != null) {
             mNavigationBarView.requestUnbufferedDispatch(event);
             event.transform(mTransformGlobalMatrix);
@@ -146,19 +155,41 @@
                 mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
                 mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
                 mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
+                mRecentsAnimationStarted = false;
                 break;
             }
         }
-        if (mStatusBar.isPresenterFullyCollapsed()
-                && !mQuickScrubController.onInterceptTouchEvent(event)) {
+        boolean handledByQuickscrub = mQuickScrubController.onInterceptTouchEvent(event);
+        if (mStatusBar.isPresenterFullyCollapsed() && !handledByQuickscrub) {
+            // Proxy motion events until we start intercepting for quickscrub
             proxyMotionEvents(event);
-            return false;
         }
-        return (mDockWindowEnabled && interceptDockWindowEvent(event));
+
+        boolean result = handledByQuickscrub;
+        result |= mRecentsAnimationStarted;
+        if (mDockWindowEnabled) {
+            result |= interceptDockWindowEvent(event);
+        }
+        return result;
+    }
+
+    public boolean onTouchEvent(MotionEvent event) {
+        // The same down event was just sent on intercept and therefore can be ignored here
+        boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
+                && mOverviewProxyService.getProxy() != null;
+        boolean result = mStatusBar.isPresenterFullyCollapsed()
+                && (mQuickScrubController.onTouchEvent(event)
+                || ignoreProxyDownEvent
+                || proxyMotionEvents(event));
+        result |= mRecentsAnimationStarted;
+        if (mDockWindowEnabled) {
+            result |= handleDockWindowEvent(event);
+        }
+        return result;
     }
 
     public void onDraw(Canvas canvas) {
-        if (mOverviewEventSender.getProxy() != null) {
+        if (mOverviewProxyService.getProxy() != null) {
             mQuickScrubController.onDraw(canvas);
         }
     }
@@ -307,20 +338,6 @@
         return DRAG_MODE_RECENTS;
     }
 
-    public boolean onTouchEvent(MotionEvent event) {
-        // The same down event was just sent on intercept and therefore can be ignored here
-        boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
-                && mOverviewEventSender.getProxy() != null;
-        boolean result = mStatusBar.isPresenterFullyCollapsed()
-                && (mQuickScrubController.onTouchEvent(event)
-                || ignoreProxyDownEvent
-                || proxyMotionEvents(event));
-        if (mDockWindowEnabled) {
-            result |= handleDockWindowEvent(event);
-        }
-        return result;
-    }
-
     @Override
     public void onTuningChanged(String key, String newValue) {
         switch (key) {
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 c37dd55..af0afbd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -50,14 +50,13 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.DockedStackExistsListener;
 import com.android.systemui.OverviewProxyService;
-import com.android.systemui.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.statusbar.phone.NavGesture;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
-import com.android.systemui.recents.SwipeUpOnboarding;
+import com.android.systemui.recents.RecentsOnboarding;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.policy.DeadZone;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -104,7 +103,6 @@
     private DeadZone mDeadZone;
     private final NavigationBarTransitions mBarTransitions;
     private final OverviewProxyService mOverviewProxyService;
-    private boolean mRecentsAnimationStarted;
 
     // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
     final static boolean WORKAROUND_INVALID_LAYOUT = true;
@@ -126,7 +124,7 @@
     private NavigationBarInflaterView mNavigationInflaterView;
     private RecentsComponent mRecentsComponent;
     private Divider mDivider;
-    private SwipeUpOnboarding mSwipeUpOnboarding;
+    private RecentsOnboarding mRecentsOnboarding;
     private NotificationPanelView mPanelView;
 
     private class NavTransitionListener implements TransitionListener {
@@ -236,7 +234,7 @@
                 new ButtonDispatcher(R.id.rotate_suggestion));
 
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
-        mSwipeUpOnboarding = new SwipeUpOnboarding(context);
+        mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
     }
 
     public BarTransitions getBarTransitions() {
@@ -264,9 +262,8 @@
     }
 
     public void setRecentsAnimationStarted(boolean started) {
-        mRecentsAnimationStarted = started;
-        if (mSwipeUpOnboarding != null) {
-            mSwipeUpOnboarding.onRecentsAnimationStarted();
+        if (mRecentsOnboarding != null) {
+            mRecentsOnboarding.onRecentsAnimationStarted();
         }
     }
 
@@ -277,30 +274,16 @@
     }
 
     @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        return mGestureHelper.onInterceptTouchEvent(event);
+    }
+
+    @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (mGestureHelper.onTouchEvent(event)) {
             return true;
         }
-        return mRecentsAnimationStarted || super.onTouchEvent(event);
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        int action = event.getActionMasked();
-        if (action == MotionEvent.ACTION_DOWN) {
-            mRecentsAnimationStarted = false;
-        } else if (action == MotionEvent.ACTION_UP) {
-            // If the overview proxy service has not started the recents animation then clean up
-            // after it to ensure that the nav bar buttons still work
-            if (mOverviewProxyService.getProxy() != null && !mRecentsAnimationStarted) {
-                try {
-                    ActivityManager.getService().cancelRecentsAnimation();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Could not cancel recents animation");
-                }
-            }
-        }
-        return mGestureHelper.onInterceptTouchEvent(event) || mRecentsAnimationStarted;
+        return super.onTouchEvent(event);
     }
 
     public void abortCurrentGesture() {
@@ -674,8 +657,8 @@
         if (mGestureHelper != null) {
             mGestureHelper.onDarkIntensityChange(intensity);
         }
-        if (mSwipeUpOnboarding != null) {
-            mSwipeUpOnboarding.setContentDarkIntensity(intensity);
+        if (mRecentsOnboarding != null) {
+            mRecentsOnboarding.setContentDarkIntensity(intensity);
         }
     }
 
@@ -793,7 +776,7 @@
         updateTaskSwitchHelper();
         updateIcons(getContext(), mConfiguration, newConfig);
         updateRecentsIcon();
-        mSwipeUpOnboarding.onConfigurationChanged(newConfig);
+        mRecentsOnboarding.onConfigurationChanged(newConfig);
         if (uiCarModeChanged || mConfiguration.densityDpi != newConfig.densityDpi
                 || mConfiguration.getLayoutDirection() != newConfig.getLayoutDirection()) {
             // If car mode or density changes, we need to reset the icons.
@@ -897,9 +880,9 @@
 
     private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
         if (connectedToOverviewProxy) {
-            mSwipeUpOnboarding.onConnectedToLauncher();
+            mRecentsOnboarding.onConnectedToLauncher();
         } else {
-            mSwipeUpOnboarding.onDisconnectedFromLauncher();
+            mRecentsOnboarding.onDisconnectedFromLauncher();
         }
     }
 
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 cd2e77a..52d005c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -68,14 +68,12 @@
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 import java.util.List;
-import java.util.Collection;
 
 public class NotificationPanelView extends PanelView implements
         ExpandableView.OnHeightChangedListener,
@@ -1571,7 +1569,7 @@
     private void updatePanelExpanded() {
         boolean isExpanded = !isFullyCollapsed();
         if (mPanelExpanded != isExpanded) {
-            mHeadsUpManager.setIsExpanded(isExpanded);
+            mHeadsUpManager.setIsPanelExpanded(isExpanded);
             mStatusBar.setPanelExpanded(isExpanded);
             mPanelExpanded = isExpanded;
         }
@@ -2338,7 +2336,7 @@
     }
 
     @Override
-    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
+    public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
         super.setHeadsUpManager(headsUpManager);
         mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, mNotificationStackScroller,
                 this);
@@ -2630,8 +2628,8 @@
         }
     }
 
-    public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) {
-        mKeyguardStatusView.setPulsing(pulsing != null);
+    public void setPulsing(boolean pulsing) {
+        mKeyguardStatusView.setPulsing(pulsing);
         positionClockAndNotifications();
         mNotificationStackScroller.setPulsing(pulsing, mKeyguardStatusView.getLocationOnScreen()[1]
                 + mKeyguardStatusView.getClockBottom());
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 2b7e474..6daabed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -50,7 +50,7 @@
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -75,7 +75,7 @@
     }
 
     protected StatusBar mStatusBar;
-    protected HeadsUpManager mHeadsUpManager;
+    protected HeadsUpManagerPhone mHeadsUpManager;
 
     private float mPeekHeight;
     private float mHintDistance;
@@ -1252,7 +1252,7 @@
      */
     protected abstract int getClearAllHeight();
 
-    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
+    public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
         mHeadsUpManager = headsUpManager;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index 001a1a2..dc0835e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -63,7 +63,7 @@
     private static final String TAG = "QuickScrubController";
     private static final int QUICK_SWITCH_FLING_VELOCITY = 0;
     private static final int ANIM_DURATION_MS = 200;
-    private static final long LONG_PRESS_DELAY_MS = 150;
+    private static final long LONG_PRESS_DELAY_MS = 225;
 
     /**
      * For quick step, set a damping value to allow the button to stick closer its origin position
@@ -76,6 +76,7 @@
 
     private boolean mDraggingActive;
     private boolean mQuickScrubActive;
+    private boolean mAllowQuickSwitch;
     private float mDownOffset;
     private float mTranslation;
     private int mTouchDownX;
@@ -95,7 +96,6 @@
     private final Paint mTrackPaint = new Paint();
     private final int mScrollTouchSlop;
     private final OverviewProxyService mOverviewEventSender;
-    private final Display mDisplay;
     private final int mTrackThickness;
     private final int mTrackPadding;
     private final ValueAnimator mTrackAnimator;
@@ -137,7 +137,8 @@
         new GestureDetector.SimpleOnGestureListener() {
             @Override
             public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) {
-                if (!isQuickScrubEnabled() || mQuickScrubActive) {
+                if (!isQuickScrubEnabled() || mQuickScrubActive || !mAllowQuickSwitch ||
+                        !mHomeButtonRect.contains(mTouchDownX, mTouchDownY)) {
                     return false;
                 }
                 float velocityX = mIsRTL ? -velX : velX;
@@ -158,16 +159,15 @@
                     } catch (RemoteException e) {
                         Log.e(TAG, "Failed to send start of quick switch.", e);
                     }
+                    return true;
                 }
-                return true;
+                return false;
             }
         };
 
     public QuickScrubController(Context context) {
         mContext = context;
         mScrollTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-        mDisplay = ((WindowManager) context.getSystemService(
-                Context.WINDOW_SERVICE)).getDefaultDisplay();
         mOverviewEventSender = Dependency.get(OverviewProxyService.class);
         mGestureDetector = new GestureDetector(mContext, mGestureListener);
         mTrackThickness = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_thickness);
@@ -189,6 +189,10 @@
         mNavigationBarView = navigationBarView;
     }
 
+    /**
+     * @return true if we want to intercept touch events for quick scrub/switch and prevent proxying
+     *         the event to the overview service.
+     */
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
         final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
@@ -197,7 +201,26 @@
             homeButton.setDelayTouchFeedback(false);
             return false;
         }
-        mGestureDetector.onTouchEvent(event);
+
+        return handleTouchEvent(event);
+    }
+
+    /**
+     * @return true if we want to handle touch events for quick scrub/switch and prevent proxying
+     *         the event to the overview service.
+     */
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        return handleTouchEvent(event);
+    }
+
+    private boolean handleTouchEvent(MotionEvent event) {
+        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+        final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
+        if (mGestureDetector.onTouchEvent(event)) {
+            // If the fling has been handled on UP, then skip proxying the UP
+            return true;
+        }
         int action = event.getAction();
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
@@ -212,6 +235,7 @@
                     homeButton.setDelayTouchFeedback(false);
                     mTouchDownX = mTouchDownY = -1;
                 }
+                mAllowQuickSwitch = true;
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
@@ -240,8 +264,9 @@
                         offset = pos - mTrackRect.left;
                         trackSize = mTrackRect.width();
                     }
-                    // Do not start scrubbing when dragging in the perpendicular direction
-                    if (!mDraggingActive && exceededPerpendicularTouchSlop) {
+                    // Do not start scrubbing when dragging in the perpendicular direction if we
+                    // haven't already started quickscrub
+                    if (!mDraggingActive && !mQuickScrubActive && exceededPerpendicularTouchSlop) {
                         mHandler.removeCallbacksAndMessages(null);
                         return false;
                     }
@@ -341,14 +366,6 @@
     }
 
     @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_UP) {
-            endQuickScrub();
-        }
-        return false;
-    }
-
-    @Override
     public void setBarState(boolean isVertical, boolean isRTL) {
         mIsVertical = isVertical;
         mIsRTL = isRTL;
@@ -403,6 +420,11 @@
         mDraggingActive = false;
     }
 
+    public void cancelQuickSwitch() {
+        mAllowQuickSwitch = false;
+        mHandler.removeCallbacks(mLongPressRunnable);
+    }
+
     private int getDimensionPixelSize(Context context, @DimenRes int resId) {
         return context.getResources().getDimensionPixelSize(resId);
     }
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 44e0c25..1438763 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -30,6 +30,7 @@
 import android.os.Trace;
 import android.util.Log;
 import android.util.MathUtils;
+import android.view.Choreographer;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
@@ -111,7 +112,6 @@
     protected static final float SCRIM_IN_FRONT_ALPHA_LOCKED = GRADIENT_SCRIM_ALPHA_BUSY;
 
     static final int TAG_KEY_ANIM = R.id.scrim;
-    static final int TAG_KEY_ANIM_BLANK = R.id.scrim_blanking;
     private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target;
     private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
     private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
@@ -167,6 +167,10 @@
     private Callback mCallback;
     private boolean mWallpaperSupportsAmbientMode;
 
+    // Scrim blanking callbacks
+    private Choreographer.FrameCallback mPendingFrameCallback;
+    private Runnable mBlankingTransitionRunnable;
+
     private final WakeLock mWakeLock;
     private boolean mWakeLockHeld;
 
@@ -248,6 +252,16 @@
         mCurrentInFrontAlpha = state.getFrontAlpha();
         mCurrentBehindAlpha = state.getBehindAlpha();
 
+        // Cancel blanking transitions that were pending before we requested a new state
+        if (mPendingFrameCallback != null) {
+            Choreographer.getInstance().removeFrameCallback(mPendingFrameCallback);
+            mPendingFrameCallback = null;
+        }
+        if (getHandler().hasCallbacks(mBlankingTransitionRunnable)) {
+            getHandler().removeCallbacks(mBlankingTransitionRunnable);
+            mBlankingTransitionRunnable = null;
+        }
+
         // Showing/hiding the keyguard means that scrim colors have to be switched, not necessary
         // to do the same when you're just showing the brightness mirror.
         mNeedsDrawableColorUpdate = state != ScrimState.BRIGHTNESS_MIRROR;
@@ -276,13 +290,18 @@
             mWallpaperVisibilityTimedOut = false;
         }
 
-        if (!mKeyguardUpdateMonitor.needsSlowUnlockTransition()) {
-            scheduleUpdate();
-        } else {
+        if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
             // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
             // with too many things at this case, in order to not skip the initial frames.
             mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
             mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
+        } else if (!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD) {
+            // Execute first frame immediately when display was completely off.
+            // Scheduling a frame isn't enough because the system may aggressively enter doze,
+            // delaying callbacks or never triggering them until the power button is pressed.
+            onPreDraw();
+        } else {
+            scheduleUpdate();
         }
     }
 
@@ -687,11 +706,12 @@
             }
         }
 
-        final boolean blankingInProgress = mScrimInFront.getTag(TAG_KEY_ANIM_BLANK) != null;
-        if (mBlankScreen || blankingInProgress) {
-            if (!blankingInProgress) {
-                blankDisplay();
-            }
+        if (mPendingFrameCallback != null) {
+            // Display is off and we're waiting.
+            return;
+        } else if (mBlankScreen) {
+            // Need to blank the display before continuing.
+            blankDisplay();
             return;
         } else if (!mScreenBlankingCallbackCalled) {
             // Not blanking the screen. Letting the callback know that we're ready
@@ -745,45 +765,37 @@
     }
 
     private void blankDisplay() {
-        final float initialAlpha = mScrimInFront.getViewAlpha();
-        final int initialTint = mScrimInFront.getTint();
-        ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
-        anim.addUpdateListener(animation -> {
-            final float amount = (float) animation.getAnimatedValue();
-            float animAlpha = MathUtils.lerp(initialAlpha, 1, amount);
-            int animTint = ColorUtils.blendARGB(initialTint, Color.BLACK, amount);
-            updateScrimColor(mScrimInFront, animAlpha, animTint);
-            dispatchScrimsVisible();
-        });
-        anim.setInterpolator(getInterpolator());
-        anim.setDuration(mDozeParameters.getPulseInDuration());
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (mCallback != null) {
-                    mCallback.onDisplayBlanked();
-                    mScreenBlankingCallbackCalled = true;
-                }
-                Runnable blankingCallback = () -> {
-                    mScrimInFront.setTag(TAG_KEY_ANIM_BLANK, null);
-                    mBlankScreen = false;
-                    // Try again.
-                    updateScrims();
-                };
+        updateScrimColor(mScrimInFront, 1, Color.BLACK);
 
-                // Setting power states can happen after we push out the frame. Make sure we
-                // stay fully opaque until the power state request reaches the lower levels.
-                getHandler().postDelayed(blankingCallback, 100);
-
+        // Notify callback that the screen is completely black and we're
+        // ready to change the display power mode
+        mPendingFrameCallback = frameTimeNanos -> {
+            if (mCallback != null) {
+                mCallback.onDisplayBlanked();
+                mScreenBlankingCallbackCalled = true;
             }
-        });
-        anim.start();
-        mScrimInFront.setTag(TAG_KEY_ANIM_BLANK, anim);
 
-        // Finish animation if we're already at its final state
-        if (initialAlpha == 1 && mScrimInFront.getTint() == Color.BLACK) {
-            anim.end();
-        }
+            mBlankingTransitionRunnable = () -> {
+                mBlankingTransitionRunnable = null;
+                mPendingFrameCallback = null;
+                mBlankScreen = false;
+                // Try again.
+                updateScrims();
+            };
+
+            // Setting power states can happen after we push out the frame. Make sure we
+            // stay fully opaque until the power state request reaches the lower levels.
+            if (DEBUG) {
+                Log.d(TAG, "Waiting for the screen to turn on...");
+            }
+            getHandler().postDelayed(mBlankingTransitionRunnable, 500);
+        };
+        doOnTheNextFrame(mPendingFrameCallback);
+    }
+
+    @VisibleForTesting
+    protected void doOnTheNextFrame(Choreographer.FrameCallback callback) {
+        Choreographer.getInstance().postFrameCallback(callback);
     }
 
     @VisibleForTesting
@@ -888,6 +900,20 @@
         }
     }
 
+    /**
+     * Interrupts blanking transitions once the display notifies that it's already on.
+     */
+    public void onScreenTurnedOn() {
+        final Handler handler = getHandler();
+        if (handler.hasCallbacks(mBlankingTransitionRunnable)) {
+            if (DEBUG) {
+                Log.d(TAG, "Shorter blanking because screen turned on. All good.");
+            }
+            handler.removeCallbacks(mBlankingTransitionRunnable);
+            mBlankingTransitionRunnable.run();
+        }
+    }
+
     public interface Callback {
         default void onStart() {
         }
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 314d6aa..381e4af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -48,7 +48,6 @@
                     // set our scrim to black in this frame to avoid flickering and
                     // fade it out afterwards.
                     mBlankScreen = true;
-                    updateScrimColor(mScrimInFront, 1, Color.BLACK);
                 }
             } else {
                 mAnimationDuration = ScrimController.ANIMATION_DURATION;
@@ -86,9 +85,6 @@
     AOD(3) {
         @Override
         public void prepare(ScrimState previousState) {
-            if (previousState == ScrimState.PULSING && !mCanControlScreenOff) {
-                updateScrimColor(mScrimInFront, 1, Color.BLACK);
-            }
             final boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
             final boolean wasPulsing = previousState == ScrimState.PULSING;
             mBlankScreen = wasPulsing && !mCanControlScreenOff;
@@ -115,9 +111,6 @@
                     && !mKeyguardUpdateMonitor.hasLockscreenWallpaper() ? 0f : 1f;
             mCurrentBehindTint = Color.BLACK;
             mBlankScreen = mDisplayRequiresBlanking;
-            if (mDisplayRequiresBlanking) {
-                updateScrimColor(mScrimInFront, 1, Color.BLACK);
-            }
         }
     },
 
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 1bf719a..458518c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -140,7 +140,6 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.ActivityStarterDelegate;
 import com.android.systemui.AutoReinflateContainer;
-import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dependency;
 import com.android.systemui.EventLogTags;
@@ -152,6 +151,7 @@
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -181,6 +181,7 @@
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.EmptyShadeView;
@@ -208,6 +209,7 @@
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -219,6 +221,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
@@ -809,15 +812,14 @@
                 .commit();
         mIconController = Dependency.get(StatusBarIconController.class);
 
-        mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager);
-        mHeadsUpManager.setBar(this);
+        mHeadsUpManager = new HeadsUpManagerPhone(context, mStatusBarWindow, mGroupManager, this,
+                mVisualStabilityManager);
         mHeadsUpManager.addListener(this);
         mHeadsUpManager.addListener(mNotificationPanel);
         mHeadsUpManager.addListener(mGroupManager);
         mHeadsUpManager.addListener(mVisualStabilityManager);
         mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
-        mHeadsUpManager.setVisualStabilityManager(mVisualStabilityManager);
         putComponent(HeadsUpManager.class, mHeadsUpManager);
 
         mEntryManager.setUpWithPresenter(this, mStackScroller, this, mHeadsUpManager);
@@ -1348,7 +1350,8 @@
 
     @Override
     public void onPerformRemoveNotification(StatusBarNotification n) {
-        if (mStackScroller.hasPulsingNotifications() && mHeadsUpManager.getAllEntries().isEmpty()) {
+        if (mStackScroller.hasPulsingNotifications() &&
+                    !mHeadsUpManager.hasHeadsUpNotifications()) {
             // We were showing a pulse for a notification, but no notifications are pulsing anymore.
             // Finish the pulse.
             mDozeScrimController.pulseOutNow();
@@ -2097,9 +2100,8 @@
     }
 
     public void maybeEscalateHeadsUp() {
-        Collection<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getAllEntries();
-        for (HeadsUpManager.HeadsUpEntry entry : entries) {
-            final StatusBarNotification sbn = entry.entry.notification;
+        mHeadsUpManager.getAllEntries().forEach(entry -> {
+            final StatusBarNotification sbn = entry.notification;
             final Notification notification = sbn.getNotification();
             if (notification.fullScreenIntent != null) {
                 if (DEBUG) {
@@ -2109,11 +2111,11 @@
                     EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
                             sbn.getKey());
                     notification.fullScreenIntent.send();
-                    entry.entry.notifyFullScreenIntentLaunched();
+                    entry.notifyFullScreenIntentLaunched();
                 } catch (PendingIntent.CanceledException e) {
                 }
             }
-        }
+        });
         mHeadsUpManager.releaseAllImmediately();
     }
 
@@ -2459,14 +2461,25 @@
     }
 
     @Override
-    public void showChargingAnimation(int batteryLevel) {
-        if (mDozing) {
-            // ambient
-        } else if (mKeyguardManager.isKeyguardLocked()) {
-            // lockscreen
-        } else {
+    public void showWirelessChargingAnimation(int batteryLevel) {
+        if (mDozing || mKeyguardManager.isKeyguardLocked()) {
+            // on ambient or lockscreen, hide notification panel
             WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
-                    batteryLevel).show();
+                    batteryLevel, new WirelessChargingAnimation.Callback() {
+                        @Override
+                        public void onAnimationStarting() {
+                            CrossFadeHelper.fadeOut(mNotificationPanel, 1);
+                        }
+
+                        @Override
+                        public void onAnimationEnded() {
+                            CrossFadeHelper.fadeIn(mNotificationPanel);
+                        }
+                    }).show();
+        } else {
+            // workspace
+            WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
+                    batteryLevel, null).show();
         }
     }
 
@@ -3882,6 +3895,7 @@
 
     private void instantCollapseNotificationPanel() {
         mNotificationPanel.instantCollapse();
+        runPostCollapseRunnables();
     }
 
     @Override
@@ -4393,6 +4407,7 @@
 
         @Override
         public void onScreenTurnedOn() {
+            mScrimController.onScreenTurnedOn();
         }
 
         @Override
@@ -4658,24 +4673,22 @@
                 @Override
                 public void onPulseStarted() {
                     callback.onPulseStarted();
-                    Collection<HeadsUpManager.HeadsUpEntry> pulsingEntries =
-                            mHeadsUpManager.getAllEntries();
-                    if (!pulsingEntries.isEmpty()) {
+                    if (mHeadsUpManager.hasHeadsUpNotifications()) {
                         // Only pulse the stack scroller if there's actually something to show.
                         // Otherwise just show the always-on screen.
-                        setPulsing(pulsingEntries);
+                        setPulsing(true);
                     }
                 }
 
                 @Override
                 public void onPulseFinished() {
                     callback.onPulseFinished();
-                    setPulsing(null);
+                    setPulsing(false);
                 }
 
-                private void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) {
+                private void setPulsing(boolean pulsing) {
                     mNotificationPanel.setPulsing(pulsing);
-                    mVisualStabilityManager.setPulsing(pulsing != null);
+                    mVisualStabilityManager.setPulsing(pulsing);
                     mIgnoreTouchWhilePulsing = false;
                 }
             }, reason);
@@ -4823,7 +4836,7 @@
 
 
     // for heads up notifications
-    protected HeadsUpManager mHeadsUpManager;
+    protected HeadsUpManagerPhone mHeadsUpManager;
 
     private AboveShelfObserver mAboveShelfObserver;
 
@@ -4926,7 +4939,7 @@
                 // Release the HUN notification to the shade.
 
                 if (isPresenterFullyCollapsed()) {
-                    HeadsUpManager.setIsClickedNotification(row, true);
+                    HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
                 }
                 //
                 // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
@@ -5045,6 +5058,8 @@
         } else if (!isPresenterFullyCollapsed()) {
             instantCollapseNotificationPanel();
             visibilityChanged(false);
+        } else {
+            runPostCollapseRunnables();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 1897171..1da50ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -88,7 +88,8 @@
      * Layout is happening from end -> start
      */
     private void calculateIconTranslations() {
-        float translationX = getWidth();
+        float width = getWidth();
+        float translationX = width;
         float contentStart = getPaddingStart();
         int childCount = getChildCount();
         // Underflow === don't show content until that index
@@ -133,6 +134,15 @@
                 }
             }
         }
+
+        // Stole this from NotificationIconContainer. Not optimal but keeps the layout logic clean
+        if (isLayoutRtl()) {
+            for (int i = 0; i < childCount; i++) {
+                View child = getChildAt(i);
+                ViewState state = getViewStateFromChild(child);
+                state.xTranslation = width - state.xTranslation - child.getWidth();
+            }
+        }
     }
 
     private void applyIconStates() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 53dfb24..040d7ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -16,119 +16,69 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.os.SystemClock;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.support.v4.util.ArraySet;
 import android.util.ArrayMap;
+import android.provider.Settings;
 import android.util.Log;
-import android.util.Pools;
-import android.view.View;
-import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.StatusBar;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Iterator;
+import java.util.stream.Stream;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Stack;
 
 /**
  * A manager which handles heads up notifications which is a special mode where
  * they simply peek from the top of the screen.
  */
-public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsListener,
-        VisualStabilityManager.Callback {
+public class HeadsUpManager {
     private static final String TAG = "HeadsUpManager";
     private static final boolean DEBUG = false;
     private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms";
-    private static final int TAG_CLICKED_NOTIFICATION = R.id.is_clicked_heads_up_tag;
 
-    private final int mHeadsUpNotificationDecay;
-    private final int mMinimumDisplayTime;
+    protected final Clock mClock = new Clock();
+    protected final HashSet<OnHeadsUpChangedListener> mListeners = new HashSet<>();
+    protected final Handler mHandler = new Handler(Looper.getMainLooper());
 
-    private final int mTouchAcceptanceDelay;
+    protected final Context mContext;
+
+    protected int mHeadsUpNotificationDecay;
+    protected int mMinimumDisplayTime;
+    protected int mTouchAcceptanceDelay;
+    protected int mSnoozeLengthMs;
+    protected boolean mHasPinnedNotification;
+    protected int mUser;
+
+    private final HashMap<String, HeadsUpEntry> mHeadsUpEntries = new HashMap<>();
     private final ArrayMap<String, Long> mSnoozedPackages;
-    private final HashSet<OnHeadsUpChangedListener> mListeners = new HashSet<>();
-    private final int mDefaultSnoozeLengthMs;
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-    private final Pools.Pool<HeadsUpEntry> mEntryPool = new Pools.Pool<HeadsUpEntry>() {
 
-        private Stack<HeadsUpEntry> mPoolObjects = new Stack<>();
-
-        @Override
-        public HeadsUpEntry acquire() {
-            if (!mPoolObjects.isEmpty()) {
-                return mPoolObjects.pop();
-            }
-            return new HeadsUpEntry();
-        }
-
-        @Override
-        public boolean release(HeadsUpEntry instance) {
-            instance.reset();
-            mPoolObjects.push(instance);
-            return true;
-        }
-    };
-
-    private final View mStatusBarWindowView;
-    private final int mStatusBarHeight;
-    private final Context mContext;
-    private final NotificationGroupManager mGroupManager;
-    private StatusBar mBar;
-    private int mSnoozeLengthMs;
-    private ContentObserver mSettingsObserver;
-    private HashMap<String, HeadsUpEntry> mHeadsUpEntries = new HashMap<>();
-    private HashSet<String> mSwipedOutKeys = new HashSet<>();
-    private int mUser;
-    private Clock mClock;
-    private boolean mReleaseOnExpandFinish;
-    private boolean mTrackingHeadsUp;
-    private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
-    private ArraySet<NotificationData.Entry> mEntriesToRemoveWhenReorderingAllowed
-            = new ArraySet<>();
-    private boolean mIsExpanded;
-    private boolean mHasPinnedNotification;
-    private int[] mTmpTwoArray = new int[2];
-    private boolean mHeadsUpGoingAway;
-    private boolean mWaitingOnCollapseWhenGoingAway;
-    private boolean mIsObserving;
-    private boolean mRemoteInputActive;
-    private float mExpandedHeight;
-    private VisualStabilityManager mVisualStabilityManager;
-    private int mStatusBarState;
-
-    public HeadsUpManager(final Context context, View statusBarWindowView,
-                          NotificationGroupManager groupManager) {
+    public HeadsUpManager(@NonNull final Context context) {
         mContext = context;
-        Resources resources = mContext.getResources();
-        mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
-        mSnoozedPackages = new ArrayMap<>();
-        mDefaultSnoozeLengthMs = resources.getInteger(R.integer.heads_up_default_snooze_length_ms);
-        mSnoozeLengthMs = mDefaultSnoozeLengthMs;
+        Resources resources = context.getResources();
         mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
         mHeadsUpNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay);
-        mClock = new Clock();
+        mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
+        mSnoozedPackages = new ArrayMap<>();
+        int defaultSnoozeLengthMs =
+                resources.getInteger(R.integer.heads_up_default_snooze_length_ms);
 
         mSnoozeLengthMs = Settings.Global.getInt(context.getContentResolver(),
-                SETTING_HEADS_UP_SNOOZE_LENGTH_MS, mDefaultSnoozeLengthMs);
-        mSettingsObserver = new ContentObserver(mHandler) {
+                SETTING_HEADS_UP_SNOOZE_LENGTH_MS, defaultSnoozeLengthMs);
+        ContentObserver settingsObserver = new ContentObserver(mHandler) {
             @Override
             public void onChange(boolean selfChange) {
                 final int packageSnoozeLengthMs = Settings.Global.getInt(
@@ -141,48 +91,27 @@
         };
         context.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false,
-                mSettingsObserver);
-        mStatusBarWindowView = statusBarWindowView;
-        mGroupManager = groupManager;
-        mStatusBarHeight = resources.getDimensionPixelSize(
-                com.android.internal.R.dimen.status_bar_height);
+                settingsObserver);
     }
 
-    private void updateTouchableRegionListener() {
-        boolean shouldObserve = mHasPinnedNotification || mHeadsUpGoingAway
-                || mWaitingOnCollapseWhenGoingAway;
-        if (shouldObserve == mIsObserving) {
-            return;
-        }
-        if (shouldObserve) {
-            mStatusBarWindowView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
-            mStatusBarWindowView.requestLayout();
-        } else {
-            mStatusBarWindowView.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
-        }
-        mIsObserving = shouldObserve;
-    }
-
-    public void setBar(StatusBar bar) {
-        mBar = bar;
-    }
-
-    public void addListener(OnHeadsUpChangedListener listener) {
+    /**
+     * Adds an OnHeadUpChangedListener to observe events.
+     */
+    public void addListener(@NonNull OnHeadsUpChangedListener listener) {
         mListeners.add(listener);
     }
 
-    public void removeListener(OnHeadsUpChangedListener listener) {
+    /**
+     * Removes the OnHeadUpChangedListener from the observer list.
+     */
+    public void removeListener(@NonNull OnHeadsUpChangedListener listener) {
         mListeners.remove(listener);
     }
 
-    public StatusBar getBar() {
-        return mBar;
-    }
-
     /**
      * Called when posting a new notification to the heads up.
      */
-    public void showNotification(NotificationData.Entry headsUp) {
+    public void showNotification(@NonNull NotificationData.Entry headsUp) {
         if (DEBUG) Log.v(TAG, "showNotification");
         addHeadsUpEntry(headsUp);
         updateNotification(headsUp, true);
@@ -192,7 +121,7 @@
     /**
      * Called when updating or posting a notification to the heads up.
      */
-    public void updateNotification(NotificationData.Entry headsUp, boolean alert) {
+    public void updateNotification(@NonNull NotificationData.Entry headsUp, boolean alert) {
         if (DEBUG) Log.v(TAG, "updateNotification");
 
         headsUp.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
@@ -204,14 +133,13 @@
                 // with the groupmanager
                 return;
             }
-            headsUpEntry.updateEntry();
+            headsUpEntry.updateEntry(true /* updatePostTime */);
             setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(headsUp));
         }
     }
 
-    private void addHeadsUpEntry(NotificationData.Entry entry) {
-        HeadsUpEntry headsUpEntry = mEntryPool.acquire();
-
+    private void addHeadsUpEntry(@NonNull NotificationData.Entry entry) {
+        HeadsUpEntry headsUpEntry = createHeadsUpEntry();
         // This will also add the entry to the sortedList
         headsUpEntry.setEntry(entry);
         mHeadsUpEntries.put(entry.key, headsUpEntry);
@@ -223,16 +151,17 @@
         entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
     }
 
-    private boolean shouldHeadsUpBecomePinned(NotificationData.Entry entry) {
-        return mStatusBarState != StatusBarState.KEYGUARD
-                && !mIsExpanded || hasFullScreenIntent(entry);
+    protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationData.Entry entry) {
+        return hasFullScreenIntent(entry);
     }
 
-    private boolean hasFullScreenIntent(NotificationData.Entry entry) {
+    protected boolean hasFullScreenIntent(@NonNull NotificationData.Entry entry) {
         return entry.notification.getNotification().fullScreenIntent != null;
     }
 
-    private void setEntryPinned(HeadsUpEntry headsUpEntry, boolean isPinned) {
+    protected void setEntryPinned(
+            @NonNull HeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned) {
+        if (DEBUG) Log.v(TAG, "setEntryPinned: " + isPinned);
         ExpandableNotificationRow row = headsUpEntry.entry.row;
         if (row.isPinned() != isPinned) {
             row.setPinned(isPinned);
@@ -247,33 +176,35 @@
         }
     }
 
-    private void removeHeadsUpEntry(NotificationData.Entry entry) {
+    protected void removeHeadsUpEntry(@NonNull NotificationData.Entry entry) {
         HeadsUpEntry remove = mHeadsUpEntries.remove(entry.key);
+        onHeadsUpEntryRemoved(remove);
+    }
+
+    protected void onHeadsUpEntryRemoved(@NonNull HeadsUpEntry remove) {
+        NotificationData.Entry entry = remove.entry;
         entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         entry.row.setHeadsUp(false);
         setEntryPinned(remove, false /* isPinned */);
         for (OnHeadsUpChangedListener listener : mListeners) {
             listener.onHeadsUpStateChanged(entry, false);
         }
-        mEntryPool.release(remove);
+        releaseHeadsUpEntry(remove);
     }
 
-    public void removeAllHeadsUpEntries() {
-        for (String key : mHeadsUpEntries.keySet()) {
-            removeHeadsUpEntry(mHeadsUpEntries.get(key).entry);
-        }
-    }
-
-    private void updatePinnedMode() {
+    protected void updatePinnedMode() {
         boolean hasPinnedNotification = hasPinnedNotificationInternal();
         if (hasPinnedNotification == mHasPinnedNotification) {
             return;
         }
+        if (DEBUG) {
+            Log.v(TAG, "Pinned mode changed: " + mHasPinnedNotification + " -> " +
+                       hasPinnedNotification);
+        }
         mHasPinnedNotification = hasPinnedNotification;
         if (mHasPinnedNotification) {
             MetricsLogger.count(mContext, "note_peek", 1);
         }
-        updateTouchableRegionListener();
         for (OnHeadsUpChangedListener listener : mListeners) {
             listener.onHeadsUpPinnedModeChanged(hasPinnedNotification);
         }
@@ -285,47 +216,36 @@
      * @return true if the notification was removed and false if it still needs to be kept around
      * for a bit since it wasn't shown long enough
      */
-    public boolean removeNotification(String key, boolean ignoreEarliestRemovalTime) {
-        if (DEBUG) Log.v(TAG, "remove");
-        if (wasShownLongEnough(key) || ignoreEarliestRemovalTime) {
-            releaseImmediately(key);
-            return true;
-        } else {
-            getHeadsUpEntry(key).removeAsSoonAsPossible();
-            return false;
-        }
+    public boolean removeNotification(@NonNull String key, boolean ignoreEarliestRemovalTime) {
+        if (DEBUG) Log.v(TAG, "removeNotification");
+        releaseImmediately(key);
+        return true;
     }
 
-    private boolean wasShownLongEnough(String key) {
-        HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
-        HeadsUpEntry topEntry = getTopEntry();
-        if (mSwipedOutKeys.contains(key)) {
-            // We always instantly dismiss views being manually swiped out.
-            mSwipedOutKeys.remove(key);
-            return true;
-        }
-        if (headsUpEntry != topEntry) {
-            return true;
-        }
-        return headsUpEntry.wasShownLongEnough();
-    }
-
-    public boolean isHeadsUp(String key) {
+    /**
+     * Returns if the given notification is in the Heads Up Notification list or not.
+     */
+    public boolean isHeadsUp(@NonNull String key) {
         return mHeadsUpEntries.containsKey(key);
     }
 
     /**
-     * Push any current Heads Up notification down into the shade.
+     * Pushes any current Heads Up notification down into the shade.
      */
     public void releaseAllImmediately() {
         if (DEBUG) Log.v(TAG, "releaseAllImmediately");
-        ArrayList<String> keys = new ArrayList<>(mHeadsUpEntries.keySet());
-        for (String key : keys) {
-            releaseImmediately(key);
+        Iterator<HeadsUpEntry> iterator = mHeadsUpEntries.values().iterator();
+        while (iterator.hasNext()) {
+            HeadsUpEntry entry = iterator.next();
+            iterator.remove();
+            onHeadsUpEntryRemoved(entry);
         }
     }
 
-    public void releaseImmediately(String key) {
+    /**
+     * Pushes the given Heads Up notification down into the shade.
+     */
+    public void releaseImmediately(@NonNull String key) {
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
         if (headsUpEntry == null) {
             return;
@@ -334,11 +254,14 @@
         removeHeadsUpEntry(shadeEntry);
     }
 
-    public boolean isSnoozed(String packageName) {
+    /**
+     * Returns if the given notification is snoozed or not.
+     */
+    public boolean isSnoozed(@NonNull String packageName) {
         final String key = snoozeKey(packageName, mUser);
         Long snoozedUntil = mSnoozedPackages.get(key);
         if (snoozedUntil != null) {
-            if (snoozedUntil > SystemClock.elapsedRealtime()) {
+            if (snoozedUntil > mClock.currentTimeMillis()) {
                 if (DEBUG) Log.v(TAG, key + " snoozed");
                 return true;
             }
@@ -347,39 +270,71 @@
         return false;
     }
 
+    /**
+     * Snoozes all current Heads Up Notifications.
+     */
     public void snooze() {
         for (String key : mHeadsUpEntries.keySet()) {
             HeadsUpEntry entry = mHeadsUpEntries.get(key);
             String packageName = entry.entry.notification.getPackageName();
             mSnoozedPackages.put(snoozeKey(packageName, mUser),
-                    SystemClock.elapsedRealtime() + mSnoozeLengthMs);
+                    mClock.currentTimeMillis() + mSnoozeLengthMs);
         }
-        mReleaseOnExpandFinish = true;
     }
 
-    private static String snoozeKey(String packageName, int user) {
+    @NonNull
+    private static String snoozeKey(@NonNull String packageName, int user) {
         return user + "," + packageName;
     }
 
-    private HeadsUpEntry getHeadsUpEntry(String key) {
+    @Nullable
+    protected HeadsUpEntry getHeadsUpEntry(@NonNull String key) {
         return mHeadsUpEntries.get(key);
     }
 
-    public NotificationData.Entry getEntry(String key) {
-        return mHeadsUpEntries.get(key).entry;
+    /**
+     * Returns the entry of given Heads Up Notification.
+     *
+     * @param key Key of heads up notification
+     */
+    @Nullable
+    public NotificationData.Entry getEntry(@NonNull String key) {
+        HeadsUpEntry entry = mHeadsUpEntries.get(key);
+        return entry != null ? entry.entry : null;
     }
 
-    public Collection<HeadsUpEntry> getAllEntries() {
-        return mHeadsUpEntries.values();
+    /**
+     * Returns the stream of all current Heads Up Notifications.
+     */
+    @NonNull
+    public Stream<NotificationData.Entry> getAllEntries() {
+        return mHeadsUpEntries.values().stream().map(headsUpEntry -> headsUpEntry.entry);
     }
 
-    public HeadsUpEntry getTopEntry() {
+    /**
+     * Returns the top Heads Up Notification, which appeares to show at first.
+     */
+    @Nullable
+    public NotificationData.Entry getTopEntry() {
+        HeadsUpEntry topEntry = getTopHeadsUpEntry();
+        return (topEntry != null) ? topEntry.entry : null;
+    }
+
+    /**
+     * Returns if any heads up notification is available or not.
+     */
+    public boolean hasHeadsUpNotifications() {
+        return !mHeadsUpEntries.isEmpty();
+    }
+
+    @Nullable
+    protected HeadsUpEntry getTopHeadsUpEntry() {
         if (mHeadsUpEntries.isEmpty()) {
             return null;
         }
         HeadsUpEntry topEntry = null;
         for (HeadsUpEntry entry: mHeadsUpEntries.values()) {
-            if (topEntry == null || entry.compareTo(topEntry) == -1) {
+            if (topEntry == null || entry.compareTo(topEntry) < 0) {
                 topEntry = entry;
             }
         }
@@ -387,56 +342,22 @@
     }
 
     /**
-     * Decides whether a click is invalid for a notification, i.e it has not been shown long enough
-     * that a user might have consciously clicked on it.
-     *
-     * @param key the key of the touched notification
-     * @return whether the touch is invalid and should be discarded
+     * Sets the current user.
      */
-    public boolean shouldSwallowClick(String key) {
-        HeadsUpEntry entry = mHeadsUpEntries.get(key);
-        if (entry != null && mClock.currentTimeMillis() < entry.postTime) {
-            return true;
-        }
-        return false;
-    }
-
-    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
-        if (mIsExpanded || mBar.isBouncerShowing()) {
-            // The touchable region is always the full area when expanded
-            return;
-        }
-        if (mHasPinnedNotification) {
-            ExpandableNotificationRow topEntry = getTopEntry().entry.row;
-            if (topEntry.isChildInGroup()) {
-                final ExpandableNotificationRow groupSummary
-                        = mGroupManager.getGroupSummary(topEntry.getStatusBarNotification());
-                if (groupSummary != null) {
-                    topEntry = groupSummary;
-                }
-            }
-            topEntry.getLocationOnScreen(mTmpTwoArray);
-            int minX = mTmpTwoArray[0];
-            int maxX = mTmpTwoArray[0] + topEntry.getWidth();
-            int maxY = topEntry.getIntrinsicHeight();
-
-            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
-            info.touchableRegion.set(minX, 0, maxX, maxY);
-        } else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) {
-            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
-            info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
-        }
-    }
-
     public void setUser(int user) {
         mUser = user;
     }
 
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("HeadsUpManager state:");
+        dumpInternal(fd, pw, args);
+    }
+
+    protected void dumpInternal(
+            @NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.print("  mTouchAcceptanceDelay="); pw.println(mTouchAcceptanceDelay);
         pw.print("  mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
-        pw.print("  now="); pw.println(SystemClock.elapsedRealtime());
+        pw.print("  now="); pw.println(mClock.currentTimeMillis());
         pw.print("  mUser="); pw.println(mUser);
         for (HeadsUpEntry entry: mHeadsUpEntries.values()) {
             pw.print("  HeadsUpEntry="); pw.println(entry.entry);
@@ -449,6 +370,9 @@
         }
     }
 
+    /**
+     * Returns if there are any pinned Heads Up Notifications or not.
+     */
     public boolean hasPinnedHeadsUp() {
         return mHasPinnedNotification;
     }
@@ -464,14 +388,8 @@
     }
 
     /**
-     * Notifies that a notification was swiped out and will be removed.
-     *
-     * @param key the notification key
+     * Unpins all pinned Heads Up Notifications.
      */
-    public void addSwipedOutNotification(String key) {
-        mSwipedOutKeys.add(key);
-    }
-
     public void unpinAll() {
         for (String key : mHeadsUpEntries.keySet()) {
             HeadsUpEntry entry = mHeadsUpEntries.get(key);
@@ -481,60 +399,13 @@
         }
     }
 
-    public void onExpandingFinished() {
-        if (mReleaseOnExpandFinish) {
-            releaseAllImmediately();
-            mReleaseOnExpandFinish = false;
-        } else {
-            for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) {
-                if (isHeadsUp(entry.key)) {
-                    // Maybe the heads-up was removed already
-                    removeHeadsUpEntry(entry);
-                }
-            }
-        }
-        mEntriesToRemoveAfterExpand.clear();
-    }
-
-    public void setTrackingHeadsUp(boolean trackingHeadsUp) {
-        mTrackingHeadsUp = trackingHeadsUp;
-    }
-
-    public boolean isTrackingHeadsUp() {
-        return mTrackingHeadsUp;
-    }
-
-    public void setIsExpanded(boolean isExpanded) {
-        if (isExpanded != mIsExpanded) {
-            mIsExpanded = isExpanded;
-            if (isExpanded) {
-                // make sure our state is sane
-                mWaitingOnCollapseWhenGoingAway = false;
-                mHeadsUpGoingAway = false;
-                updateTouchableRegionListener();
-            }
-        }
-    }
-
     /**
-     * @return the height of the top heads up notification when pinned. This is different from the
-     *         intrinsic height, which also includes whether the notification is system expanded and
-     *         is mainly used when dragging down from a heads up notification.
+     * Returns the value of the tracking-heads-up flag. See the doc of {@code setTrackingHeadsUp} as
+     * well.
      */
-    public int getTopHeadsUpPinnedHeight() {
-        HeadsUpEntry topEntry = getTopEntry();
-        if (topEntry == null || topEntry.entry == null) {
-            return 0;
-        }
-        ExpandableNotificationRow row = topEntry.entry.row;
-        if (row.isChildInGroup()) {
-            final ExpandableNotificationRow groupSummary
-                    = mGroupManager.getGroupSummary(row.getStatusBarNotification());
-            if (groupSummary != null) {
-                row = groupSummary;
-            }
-        }
-        return row.getPinnedHeadsUpHeight();
+    public boolean isTrackingHeadsUp() {
+        // Might be implemented in subclass.
+        return false;
     }
 
     /**
@@ -543,7 +414,7 @@
      * @return -1 if the first argument should be ranked higher than the second, 1 if the second
      * one should be ranked higher and 0 if they are equal.
      */
-    public int compare(NotificationData.Entry a, NotificationData.Entry b) {
+    public int compare(@NonNull NotificationData.Entry a, @NonNull NotificationData.Entry b) {
         HeadsUpEntry aEntry = getHeadsUpEntry(a.key);
         HeadsUpEntry bEntry = getHeadsUpEntry(b.key);
         if (aEntry == null || bEntry == null) {
@@ -553,147 +424,62 @@
     }
 
     /**
-     * Set that we are exiting the headsUp pinned mode, but some notifications might still be
-     * animating out. This is used to keep the touchable regions in a sane state.
-     */
-    public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
-        if (headsUpGoingAway != mHeadsUpGoingAway) {
-            mHeadsUpGoingAway = headsUpGoingAway;
-            if (!headsUpGoingAway) {
-                waitForStatusBarLayout();
-            }
-            updateTouchableRegionListener();
-        }
-    }
-
-    /**
-     * We need to wait on the whole panel to collapse, before we can remove the touchable region
-     * listener.
-     */
-    private void waitForStatusBarLayout() {
-        mWaitingOnCollapseWhenGoingAway = true;
-        mStatusBarWindowView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
-            @Override
-            public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                    int oldLeft,
-                    int oldTop, int oldRight, int oldBottom) {
-                if (mStatusBarWindowView.getHeight() <= mStatusBarHeight) {
-                    mStatusBarWindowView.removeOnLayoutChangeListener(this);
-                    mWaitingOnCollapseWhenGoingAway = false;
-                    updateTouchableRegionListener();
-                }
-            }
-        });
-    }
-
-    public static void setIsClickedNotification(View child, boolean clicked) {
-        child.setTag(TAG_CLICKED_NOTIFICATION, clicked ? true : null);
-    }
-
-    public static boolean isClickedHeadsUpNotification(View child) {
-        Boolean clicked = (Boolean) child.getTag(TAG_CLICKED_NOTIFICATION);
-        return clicked != null && clicked;
-    }
-
-    public void setRemoteInputActive(NotificationData.Entry entry, boolean remoteInputActive) {
-        HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(entry.key);
-        if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) {
-            headsUpEntry.remoteInputActive = remoteInputActive;
-            if (remoteInputActive) {
-                headsUpEntry.removeAutoRemovalCallbacks();
-            } else {
-                headsUpEntry.updateEntry(false /* updatePostTime */);
-            }
-        }
-    }
-
-    /**
      * Set an entry to be expanded and therefore stick in the heads up area if it's pinned
      * until it's collapsed again.
      */
-    public void setExpanded(NotificationData.Entry entry, boolean expanded) {
-        HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(entry.key);
-        if (headsUpEntry != null && headsUpEntry.expanded != expanded && entry.row.isPinned()) {
-            headsUpEntry.expanded = expanded;
-            if (expanded) {
-                headsUpEntry.removeAutoRemovalCallbacks();
-            } else {
-                headsUpEntry.updateEntry(false /* updatePostTime */);
-            }
+    public void setExpanded(@NonNull NotificationData.Entry entry, boolean expanded) {
+        HeadsUpManager.HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(entry.key);
+        if (headsUpEntry != null && entry.row.isPinned()) {
+            headsUpEntry.expanded(expanded);
         }
     }
 
-    @Override
-    public void onReorderingAllowed() {
-        mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(false);
-        for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) {
-            if (isHeadsUp(entry.key)) {
-                // Maybe the heads-up was removed already
-                removeHeadsUpEntry(entry);
-            }
-        }
-        mEntriesToRemoveWhenReorderingAllowed.clear();
-        mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(true);
+    @NonNull
+    protected HeadsUpEntry createHeadsUpEntry() {
+        return new HeadsUpEntry();
     }
 
-    public void setVisualStabilityManager(VisualStabilityManager visualStabilityManager) {
-        mVisualStabilityManager = visualStabilityManager;
-    }
-
-    public void setStatusBarState(int statusBarState) {
-        mStatusBarState = statusBarState;
+    protected void releaseHeadsUpEntry(@NonNull HeadsUpEntry entry) {
+        entry.reset();
     }
 
     /**
      * This represents a notification and how long it is in a heads up mode. It also manages its
      * lifecycle automatically when created.
      */
-    public class HeadsUpEntry implements Comparable<HeadsUpEntry> {
-        public NotificationData.Entry entry;
+    protected class HeadsUpEntry implements Comparable<HeadsUpEntry> {
+        @Nullable public NotificationData.Entry entry;
         public long postTime;
-        public long earliestRemovaltime;
-        private Runnable mRemoveHeadsUpRunnable;
         public boolean remoteInputActive;
+        public long earliestRemovaltime;
         public boolean expanded;
 
-        public void setEntry(final NotificationData.Entry entry) {
+        @Nullable private Runnable mRemoveHeadsUpRunnable;
+
+        public void setEntry(@Nullable final NotificationData.Entry entry) {
+            setEntry(entry, null);
+        }
+
+        public void setEntry(@Nullable final NotificationData.Entry entry,
+                @Nullable Runnable removeHeadsUpRunnable) {
             this.entry = entry;
+            this.mRemoveHeadsUpRunnable = removeHeadsUpRunnable;
 
             // The actual post time will be just after the heads-up really slided in
             postTime = mClock.currentTimeMillis() + mTouchAcceptanceDelay;
-            mRemoveHeadsUpRunnable = new Runnable() {
-                @Override
-                public void run() {
-                    if (!mVisualStabilityManager.isReorderingAllowed()) {
-                        mEntriesToRemoveWhenReorderingAllowed.add(entry);
-                        mVisualStabilityManager.addReorderingAllowedCallback(HeadsUpManager.this);
-                    } else if (!mTrackingHeadsUp) {
-                        removeHeadsUpEntry(entry);
-                    } else {
-                        mEntriesToRemoveAfterExpand.add(entry);
-                    }
-                }
-            };
-            updateEntry();
-        }
-
-        public void updateEntry() {
-            updateEntry(true);
+            updateEntry(true /* updatePostTime */);
         }
 
         public void updateEntry(boolean updatePostTime) {
+            if (DEBUG) Log.v(TAG, "updateEntry");
+
             long currentTime = mClock.currentTimeMillis();
             earliestRemovaltime = currentTime + mMinimumDisplayTime;
             if (updatePostTime) {
                 postTime = Math.max(postTime, currentTime);
             }
             removeAutoRemovalCallbacks();
-            if (mEntriesToRemoveAfterExpand.contains(entry)) {
-                mEntriesToRemoveAfterExpand.remove(entry);
-            }
-            if (mEntriesToRemoveWhenReorderingAllowed.contains(entry)) {
-                mEntriesToRemoveWhenReorderingAllowed.remove(entry);
-            }
+
             if (!isSticky()) {
                 long finishTime = postTime + mHeadsUpNotificationDecay;
                 long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
@@ -707,7 +493,7 @@
         }
 
         @Override
-        public int compareTo(HeadsUpEntry o) {
+        public int compareTo(@NonNull HeadsUpEntry o) {
             boolean isPinned = entry.row.isPinned();
             boolean otherPinned = o.entry.row.isPinned();
             if (isPinned && !otherPinned) {
@@ -734,26 +520,29 @@
                             : -1;
         }
 
-        public void removeAutoRemovalCallbacks() {
-            mHandler.removeCallbacks(mRemoveHeadsUpRunnable);
-        }
-
-        public boolean wasShownLongEnough() {
-            return earliestRemovaltime < mClock.currentTimeMillis();
-        }
-
-        public void removeAsSoonAsPossible() {
-            removeAutoRemovalCallbacks();
-            mHandler.postDelayed(mRemoveHeadsUpRunnable,
-                    earliestRemovaltime - mClock.currentTimeMillis());
+        public void expanded(boolean expanded) {
+            this.expanded = expanded;
         }
 
         public void reset() {
-            removeAutoRemovalCallbacks();
             entry = null;
-            mRemoveHeadsUpRunnable = null;
             expanded = false;
             remoteInputActive = false;
+            removeAutoRemovalCallbacks();
+            mRemoveHeadsUpRunnable = null;
+        }
+
+        public void removeAutoRemovalCallbacks() {
+            if (mRemoveHeadsUpRunnable != null)
+                mHandler.removeCallbacks(mRemoveHeadsUpRunnable);
+        }
+
+        public void removeAsSoonAsPossible() {
+            if (mRemoveHeadsUpRunnable != null) {
+                removeAutoRemovalCallbacks();
+                mHandler.postDelayed(mRemoveHeadsUpRunnable,
+                        earliestRemovaltime - mClock.currentTimeMillis());
+            }
         }
     }
 
@@ -762,5 +551,4 @@
             return SystemClock.elapsedRealtime();
         }
     }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
new file mode 100644
index 0000000..1e3c123c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.view.View;
+
+import com.android.systemui.R;
+
+/**
+ * A class of utility static methods for heads up notifications.
+ */
+public final class HeadsUpUtil {
+    private static final int TAG_CLICKED_NOTIFICATION = R.id.is_clicked_heads_up_tag;
+
+    /**
+     * Set the given view as clicked or not-clicked.
+     * @param view The view to be set the flag to.
+     * @param clicked True to set as clicked. False to not-clicked.
+     */
+    public static void setIsClickedHeadsUpNotification(View view, boolean clicked) {
+        view.setTag(TAG_CLICKED_NOTIFICATION, clicked ? true : null);
+    }
+
+    /**
+     * Check if the given view has the flag of "clicked notification"
+     * @param view The view to be checked.
+     * @return True if the view has clicked. False othrewise.
+     */
+    public static boolean isClickedHeadsUpNotification(View view) {
+        Boolean clicked = (Boolean) view.getTag(TAG_CLICKED_NOTIFICATION);
+        return clicked != null && clicked;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 077c6c3..9d1c1e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -27,8 +27,12 @@
 import android.metrics.LogMaker;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.TypedValue;
 import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
@@ -45,6 +49,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
+import com.android.systemui.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
 
@@ -52,18 +57,23 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 
 public class KeyButtonView extends ImageView implements ButtonInterface {
+    private static final String TAG = KeyButtonView.class.getSimpleName();
 
     private final boolean mPlaySounds;
     private int mContentDescriptionRes;
     private long mDownTime;
     private int mCode;
     private int mTouchSlop;
+    private int mTouchDownX;
+    private int mTouchDownY;
     private boolean mSupportsLongpress = true;
     private AudioManager mAudioManager;
     private boolean mGestureAborted;
     private boolean mLongClicked;
     private OnClickListener mOnClickListener;
     private final KeyButtonRipple mRipple;
+    private final OverviewProxyService mOverviewProxyService;
+    private final Vibrator mVibrator;
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     private final Runnable mCheckLongPress = new Runnable() {
@@ -110,6 +120,8 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
         mRipple = new KeyButtonRipple(context, this);
+        mVibrator = mContext.getSystemService(Vibrator.class);
+        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
         setBackground(mRipple);
     }
 
@@ -189,6 +201,7 @@
     }
 
     public boolean onTouchEvent(MotionEvent ev) {
+        final boolean isProxyConnected = mOverviewProxyService.getProxy() != null;
         final int action = ev.getAction();
         int x, y;
         if (action == MotionEvent.ACTION_DOWN) {
@@ -203,23 +216,34 @@
                 mDownTime = SystemClock.uptimeMillis();
                 mLongClicked = false;
                 setPressed(true);
+                mTouchDownX = (int) ev.getX();
+                mTouchDownY = (int) ev.getY();
                 if (mCode != 0) {
                     sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
                 } else {
                     // Provide the same haptic feedback that the system offers for virtual keys.
                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
                 }
-                playSoundEffect(SoundEffectConstants.CLICK);
+                if (isProxyConnected) {
+                    // Provide small vibration for quick step or immediate down feedback
+                    AsyncTask.execute(() ->
+                            mVibrator.vibrate(VibrationEffect
+                                    .get(VibrationEffect.EFFECT_TICK, false)));
+                } else {
+                    playSoundEffect(SoundEffectConstants.CLICK);
+                }
                 removeCallbacks(mCheckLongPress);
                 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
                 break;
             case MotionEvent.ACTION_MOVE:
                 x = (int)ev.getX();
                 y = (int)ev.getY();
-                setPressed(x >= -mTouchSlop
-                        && x < getWidth() + mTouchSlop
-                        && y >= -mTouchSlop
-                        && y < getHeight() + mTouchSlop);
+                boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > mTouchSlop;
+                boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > mTouchSlop;
+                if (exceededTouchSlopX || exceededTouchSlopY) {
+                    setPressed(false);
+                    removeCallbacks(mCheckLongPress);
+                }
                 break;
             case MotionEvent.ACTION_CANCEL:
                 setPressed(false);
@@ -231,13 +255,25 @@
             case MotionEvent.ACTION_UP:
                 final boolean doIt = isPressed() && !mLongClicked;
                 setPressed(false);
-                // Always send a release ourselves because it doesn't seem to be sent elsewhere
-                // and it feels weird to sometimes get a release haptic and other times not.
-                if ((SystemClock.uptimeMillis() - mDownTime) > 150 && !mLongClicked) {
+                if (isProxyConnected) {
+                    if (doIt) {
+                        performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+                        playSoundEffect(SoundEffectConstants.CLICK);
+                    }
+                } else if ((SystemClock.uptimeMillis() - mDownTime) > 150 && !mLongClicked) {
+                    // Always send a release ourselves because it doesn't seem to be sent elsewhere
+                    // and it feels weird to sometimes get a release haptic and other times not.
                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
                 }
                 if (mCode != 0) {
                     if (doIt) {
+                        // If there was a pending remote recents animation, then we need to
+                        // cancel the animation now before we handle the button itself
+                        try {
+                            ActivityManager.getService().cancelRecentsAnimation();
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Could not cancel recents animation", e);
+                        }
                         sendEvent(KeyEvent.ACTION_UP, 0);
                         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                     } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
new file mode 100644
index 0000000..c5067a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Log;
+
+import com.android.systemui.R;
+
+public final class SmartReplyConstants extends ContentObserver {
+
+    private static final String TAG = "SmartReplyConstants";
+
+    private static final String KEY_ENABLED = "enabled";
+    private static final String KEY_MAX_SQUEEZE_REMEASURE_ATTEMPTS =
+            "max_squeeze_remeasure_attempts";
+
+    private final boolean mDefaultEnabled;
+    private final int mDefaultMaxSqueezeRemeasureAttempts;
+
+    private boolean mEnabled;
+    private int mMaxSqueezeRemeasureAttempts;
+
+    private final Context mContext;
+    private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+    public SmartReplyConstants(Handler handler, Context context) {
+        super(handler);
+
+        mContext = context;
+        final Resources resources = mContext.getResources();
+        mDefaultEnabled = resources.getBoolean(
+                R.bool.config_smart_replies_in_notifications_enabled);
+        mDefaultMaxSqueezeRemeasureAttempts = resources.getInteger(
+                R.integer.config_smart_replies_in_notifications_max_squeeze_remeasure_attempts);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS),
+                false, this);
+        updateConstants();
+    }
+
+    @Override
+    public void onChange(boolean selfChange, Uri uri) {
+        updateConstants();
+    }
+
+    private void updateConstants() {
+        synchronized (SmartReplyConstants.this) {
+            try {
+                mParser.setString(Settings.Global.getString(mContext.getContentResolver(),
+                        Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS));
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Bad smart reply constants", e);
+            }
+            mEnabled = mParser.getBoolean(KEY_ENABLED, mDefaultEnabled);
+            mMaxSqueezeRemeasureAttempts = mParser.getInt(
+                    KEY_MAX_SQUEEZE_REMEASURE_ATTEMPTS, mDefaultMaxSqueezeRemeasureAttempts);
+        }
+    }
+
+    /** Returns whether smart replies in notifications are enabled. */
+    public boolean isEnabled() {
+        return mEnabled;
+    }
+
+    /**
+     * Returns the maximum number of times {@link SmartReplyView#onMeasure(int, int)} will try to
+     * find a better (narrower) line-break for a double-line smart reply button.
+     */
+    public int getMaxSqueezeRemeasureAttempts() {
+        return mMaxSqueezeRemeasureAttempts;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 2d829af..57fc03c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -12,6 +12,7 @@
 import android.widget.Button;
 import android.widget.LinearLayout;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 
 /** View which displays smart reply buttons in notifications. */
@@ -19,8 +20,11 @@
 
     private static final String TAG = "SmartReplyView";
 
+    private final SmartReplyConstants mConstants;
+
     public SmartReplyView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mConstants = Dependency.get(SmartReplyConstants.class);
     }
 
     public void setRepliesFromRemoteInput(RemoteInput remoteInput, PendingIntent pendingIntent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 424858a..d7a810e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -64,7 +64,7 @@
     private boolean mPanelTracking;
     private boolean mExpansionChanging;
     private boolean mPanelFullWidth;
-    private Collection<HeadsUpManager.HeadsUpEntry> mPulsing;
+    private boolean mPulsing;
     private boolean mUnlockHintRunning;
     private boolean mQsCustomizerShowing;
     private int mIntrinsicPadding;
@@ -315,23 +315,18 @@
     }
 
     public boolean hasPulsingNotifications() {
-        return mPulsing != null;
+        return mPulsing;
     }
 
-    public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> hasPulsing) {
+    public void setPulsing(boolean hasPulsing) {
         mPulsing = hasPulsing;
     }
 
     public boolean isPulsing(NotificationData.Entry entry) {
-        if (mPulsing == null) {
+        if (!mPulsing || mHeadsUpManager == null) {
             return false;
         }
-        for (HeadsUpManager.HeadsUpEntry e : mPulsing) {
-            if (e.entry == entry) {
-                return true;
-            }
-        }
-        return false;
+        return mHeadsUpManager.getAllEntries().anyMatch(e -> (e == entry));
     }
 
     public boolean isPanelTracking() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index c114a6f..1b55a5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -92,10 +92,11 @@
 import com.android.systemui.statusbar.notification.FakeShadowView;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 
 import android.support.v4.graphics.ColorUtils;
@@ -288,7 +289,7 @@
     private HashSet<View> mClearOverlayViewsWhenFinished = new HashSet<>();
     private HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
             = new HashSet<>();
-    private HeadsUpManager mHeadsUpManager;
+    private HeadsUpManagerPhone mHeadsUpManager;
     private boolean mTrackingHeadsUp;
     private ScrimController mScrimController;
     private boolean mForceNoOverlappingRendering;
@@ -358,7 +359,7 @@
         }
     };
     private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
-    private Collection<HeadsUpManager.HeadsUpEntry> mPulsing;
+    private boolean mPulsing;
     private boolean mDrawBackgroundAsSrc;
     private boolean mFadingOut;
     private boolean mParentNotFullyVisible;
@@ -690,7 +691,7 @@
     }
 
     private void updateAlgorithmHeightAndPadding() {
-        if (mPulsing != null) {
+        if (mPulsing) {
             mTopPadding = mClockBottom;
         } else {
             mTopPadding = mAmbientState.isDark() ? mDarkTopPadding : mRegularTopPadding;
@@ -920,6 +921,27 @@
     }
 
     /**
+     * @return the height of the top heads up notification when pinned. This is different from the
+     *         intrinsic height, which also includes whether the notification is system expanded and
+     *         is mainly used when dragging down from a heads up notification.
+     */
+    private int getTopHeadsUpPinnedHeight() {
+        NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
+        if (topEntry == null) {
+            return 0;
+        }
+        ExpandableNotificationRow row = topEntry.row;
+        if (row.isChildInGroup()) {
+            final ExpandableNotificationRow groupSummary
+                    = mGroupManager.getGroupSummary(row.getStatusBarNotification());
+            if (groupSummary != null) {
+                row = groupSummary;
+            }
+        }
+        return row.getPinnedHeadsUpHeight();
+    }
+
+    /**
      * @return the position from where the appear transition ends when expanding.
      *         Measured in absolute height.
      */
@@ -930,7 +952,7 @@
             int minNotificationsForShelf = 1;
             if (mTrackingHeadsUp
                     || (mHeadsUpManager.hasPinnedHeadsUp() && !mAmbientState.isDark())) {
-                appearPosition = mHeadsUpManager.getTopHeadsUpPinnedHeight();
+                appearPosition = getTopHeadsUpPinnedHeight();
                 minNotificationsForShelf = 2;
             } else {
                 appearPosition = 0;
@@ -1198,9 +1220,9 @@
                 if (slidingChild instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
                     if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
-                            && mHeadsUpManager.getTopEntry().entry.row != row
+                            && mHeadsUpManager.getTopEntry().row != row
                             && mGroupManager.getGroupSummary(
-                                mHeadsUpManager.getTopEntry().entry.row.getStatusBarNotification())
+                                mHeadsUpManager.getTopEntry().row.getStatusBarNotification())
                                 != row) {
                         continue;
                     }
@@ -2120,7 +2142,7 @@
 
     @Override
     public boolean hasPulsingNotifications() {
-        return mPulsing != null;
+        return mPulsing;
     }
 
     private void updateScrollability() {
@@ -2753,7 +2775,7 @@
     }
 
     private boolean isClickedHeadsUp(View child) {
-        return HeadsUpManager.isClickedHeadsUpNotification(child);
+        return HeadsUpUtil.isClickedHeadsUpNotification(child);
     }
 
     /**
@@ -4258,7 +4280,7 @@
         mAnimationFinishedRunnables.add(runnable);
     }
 
-    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
+    public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
         mHeadsUpManager = headsUpManager;
         mAmbientState.setHeadsUpManager(headsUpManager);
     }
@@ -4326,8 +4348,8 @@
         return mIsExpanded;
     }
 
-    public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing, int clockBottom) {
-        if (mPulsing == null && pulsing == null) {
+    public void setPulsing(boolean pulsing, int clockBottom) {
+        if (!mPulsing && !pulsing) {
             return;
         }
         mPulsing = pulsing;
@@ -4466,7 +4488,7 @@
         pw.println(String.format("[%s: pulsing=%s qsCustomizerShowing=%s visibility=%s"
                         + " alpha:%f scrollY:%d]",
                 this.getClass().getSimpleName(),
-                mPulsing != null ?"T":"f",
+                mPulsing ? "T":"f",
                 mAmbientState.isQsCustomizerShowing() ? "T":"f",
                 getVisibility() == View.VISIBLE ? "visible"
                         : getVisibility() == View.GONE ? "gone"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index 682b849..04a7bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -30,7 +30,7 @@
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.HeadsUpUtil;
 
 /**
  * A state of a view. This can be used to apply a set of view properties to a view with
@@ -582,7 +582,7 @@
         animator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                HeadsUpManager.setIsClickedNotification(child, false);
+                HeadsUpUtil.setIsClickedHeadsUpNotification(child, false);
                 child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
                 child.setTag(TAG_START_TRANSLATION_Y, null);
                 child.setTag(TAG_END_TRANSLATION_Y, null);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
index 5c888ac..6ed07f8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
@@ -49,6 +49,8 @@
 import android.view.Window;
 import android.view.WindowManager;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.systemui.Dependency;
@@ -81,6 +83,7 @@
     private final MediaRouterWrapper mRouter;
     private final MediaRouterCallback mRouterCallback;
     private long mLastUpdateTime;
+    static final boolean INCLUDE_MEDIA_ROUTES = false;
     private boolean mIsInCall;
     protected boolean isAttached;
 
@@ -174,7 +177,7 @@
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
 
-        if (!mIsInCall) {
+        if (!mIsInCall && INCLUDE_MEDIA_ROUTES) {
             mRouter.addCallback(mRouteSelector, mRouterCallback,
                     MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
         }
@@ -201,6 +204,7 @@
     @Override
     public void show() {
         super.show();
+        Dependency.get(MetricsLogger.class).visible(MetricsProto.MetricsEvent.OUTPUT_CHOOSER);
         mHardwareLayout.setTranslationX(getAnimTranslation());
         mHardwareLayout.setAlpha(0);
         mHardwareLayout.animate()
@@ -214,6 +218,7 @@
 
     @Override
     public void dismiss() {
+        Dependency.get(MetricsLogger.class).hidden(MetricsProto.MetricsEvent.OUTPUT_CHOOSER);
         mHardwareLayout.setTranslationX(0);
         mHardwareLayout.setAlpha(1);
         mHardwareLayout.animate()
@@ -236,11 +241,15 @@
         if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_BT) {
             final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
             if (device.getMaxConnectionState() == BluetoothProfile.STATE_DISCONNECTED) {
+                Dependency.get(MetricsLogger.class).action(
+                        MetricsProto.MetricsEvent.ACTION_OUTPUT_CHOOSER_CONNECT);
                 mBluetoothController.connect(device);
             }
         } else if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER) {
             final MediaRouter.RouteInfo route = (MediaRouter.RouteInfo) item.tag;
             if (route.isEnabled()) {
+                Dependency.get(MetricsLogger.class).action(
+                        MetricsProto.MetricsEvent.ACTION_OUTPUT_CHOOSER_CONNECT);
                 route.select();
             }
         }
@@ -251,8 +260,12 @@
         if (item == null || item.tag == null) return;
         if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_BT) {
             final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
+            Dependency.get(MetricsLogger.class).action(
+                    MetricsProto.MetricsEvent.ACTION_OUTPUT_CHOOSER_DISCONNECT);
             mBluetoothController.disconnect(device);
         } else if (item.deviceType == OutputChooserLayout.Item.DEVICE_TYPE_MEDIA_ROUTER) {
+            Dependency.get(MetricsLogger.class).action(
+                    MetricsProto.MetricsEvent.ACTION_OUTPUT_CHOOSER_DISCONNECT);
             mRouter.unselect(UNSELECT_REASON_DISCONNECTED);
         }
     }
@@ -272,7 +285,7 @@
         addBluetoothDevices(items);
 
         // Add remote displays
-        if (!mIsInCall) {
+        if (!mIsInCall && INCLUDE_MEDIA_ROUTES) {
             addRemoteDisplayRoutes(items);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index efa8386..0203c43 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -27,16 +27,15 @@
 import android.view.WindowManager.LayoutParams;
 
 import com.android.settingslib.applications.InterestingConfigChanges;
-import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.Dependency;
 import com.android.systemui.SystemUI;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.VolumeDialog;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.ExtensionController.Extension;
 import com.android.systemui.tuner.TunerService;
 
 import java.io.FileDescriptor;
@@ -53,8 +52,8 @@
     public static final String VOLUME_SILENT_DO_NOT_DISTURB = "sysui_do_not_disturb";
 
     public static final boolean DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT = false;
-    public static final boolean DEFAULT_VOLUME_UP_TO_EXIT_SILENT = true;
-    public static final boolean DEFAULT_DO_NOT_DISTURB_WHEN_SILENT = true;
+    public static final boolean DEFAULT_VOLUME_UP_TO_EXIT_SILENT = false;
+    public static final boolean DEFAULT_DO_NOT_DISTURB_WHEN_SILENT = false;
 
     private final SystemUI mSysui;
     private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 9aee00e..3c29b77 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -362,12 +362,15 @@
 
     private boolean shouldShowUI(int flags) {
         updateStatusBar();
-        return mStatusBar != null
-                && mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
-                && mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
+        // if status bar isn't null, check if phone is in AOD, else check flags
+        // since we could be using a different status bar
+        return mStatusBar != null ?
+                mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
+                && mStatusBar.getWakefulnessState() !=
+                        WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
                 && mStatusBar.isDeviceInteractive()
-                && (flags & AudioManager.FLAG_SHOW_UI) != 0
-                && mShowVolumeDialog;
+                && (flags & AudioManager.FLAG_SHOW_UI) != 0 && mShowVolumeDialog
+                : mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0;
     }
 
     boolean onVolumeChangedW(int stream, int flags) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index a131a61..8881ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -37,6 +37,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
 import android.media.AudioManager;
 import android.media.AudioSystem;
@@ -54,6 +55,7 @@
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.view.ContextThemeWrapper;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
@@ -66,6 +68,7 @@
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.ImageButton;
+import android.widget.ImageView;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 import android.widget.TextView;
@@ -107,7 +110,9 @@
     private ViewGroup mDialogRowsView;
     private ViewGroup mFooter;
     private ImageButton mRingerIcon;
+    private ImageView mZenIcon;
     private TextView mRingerStatus;
+    private TextView mRingerTitle;
     private final List<VolumeRow> mRows = new ArrayList<>();
     private ConfigurableTexts mConfigurableTexts;
     private final SparseBooleanArray mDynamic = new SparseBooleanArray();
@@ -176,7 +181,15 @@
         mWindow.setTitle(VolumeDialogImpl.class.getSimpleName());
         mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
         mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
+        final WindowManager.LayoutParams lp = mWindow.getAttributes();
+        lp.format = PixelFormat.TRANSLUCENT;
+        lp.setTitle(VolumeDialogImpl.class.getSimpleName());
+        lp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
+        lp.windowAnimations = -1;
+        mWindow.setAttributes(lp);
+        mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
 
+        mDialog.setCanceledOnTouchOutside(true);
         mDialog.setContentView(R.layout.volume_dialog);
         mDialog.setOnShowListener(dialog -> {
             mDialogView.setTranslationX(mDialogView.getWidth() / 2);
@@ -199,13 +212,15 @@
             rescheduleTimeoutH();
             return true;
         });
-        VolumeUiLayout hardwareLayout = VolumeUiLayout.get(mDialogView);
-        hardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
+        VolumeUiLayout uiLayout = VolumeUiLayout.get(mDialogView);
+        uiLayout.updateRotation();
 
         mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
         mFooter = mDialog.findViewById(R.id.footer);
         mRingerIcon = mFooter.findViewById(R.id.ringer_icon);
         mRingerStatus = mFooter.findViewById(R.id.ringer_status);
+        mRingerTitle = mFooter.findViewById(R.id.ringer_title);
+        mZenIcon = mFooter.findViewById(R.id.dnd_icon);
 
         if (mRows.isEmpty()) {
             addRow(AudioManager.STREAM_MUSIC,
@@ -339,6 +354,7 @@
         if (stream == STREAM_ACCESSIBILITY) {
             row.header.setFilters(new InputFilter[] {new InputFilter.LengthFilter(13)});
         }
+        row.dndIcon = row.view.findViewById(R.id.dnd_icon);
         row.slider =  row.view.findViewById(R.id.volume_row_slider);
         row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
         row.anim = null;
@@ -396,13 +412,9 @@
                 if (hasVibrator) {
                     mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
                 } else {
-                    final boolean wasZero = ss.level == 0;
-                    mController.setStreamVolume(AudioManager.STREAM_RING, wasZero ? 1 : 0);
                     mController.setRingerMode(AudioManager.RINGER_MODE_SILENT, false);
                 }
             } else if (mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) {
-                final boolean wasZero = ss.level == 0;
-                mController.setStreamVolume(AudioManager.STREAM_RING, wasZero ? 1 : 0);
                 mController.setRingerMode(AudioManager.RINGER_MODE_SILENT, false);
             } else {
                 mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
@@ -553,6 +565,8 @@
             if (ss == null) {
                 return;
             }
+
+            enableRingerViewsH(mState.zenMode == Global.ZEN_MODE_OFF || !mState.disallowRinger);
             switch (mState.ringerModeInternal) {
                 case AudioManager.RINGER_MODE_VIBRATE:
                     mRingerStatus.setText(R.string.volume_ringer_status_vibrate);
@@ -597,6 +611,28 @@
         }
     }
 
+    /**
+     * Toggles enable state of views in a VolumeRow (not including seekbar, outputChooser or icon)
+     * Hides/shows zen icon
+     * @param enable whether to enable volume row views and hide dnd icon
+     */
+    private void enableVolumeRowViewsH(VolumeRow row, boolean enable) {
+        row.header.setEnabled(enable);
+        row.dndIcon.setVisibility(enable ? View.GONE : View.VISIBLE);
+    }
+
+    /**
+     * Toggles enable state of footer/ringer views
+     * Hides/shows zen icon
+     * @param enable whether to enable ringer views and hide dnd icon
+     */
+    private void enableRingerViewsH(boolean enable) {
+        mRingerTitle.setEnabled(enable);
+        mRingerStatus.setEnabled(enable);
+        mRingerIcon.setEnabled(enable);
+        mZenIcon.setVisibility(enable ? View.GONE : View.VISIBLE);
+    }
+
     private void trimObsoleteH() {
         if (D.BUG) Log.d(TAG, "trimObsoleteH");
         for (int i = mRows.size() - 1; i >= 0; i--) {
@@ -742,6 +778,7 @@
         if (zenMuted) {
             row.tracking = false;
         }
+        enableVolumeRowViewsH(row, !zenMuted);
 
         // update slider
         final boolean enableSlider = !zenMuted;
@@ -1019,15 +1056,21 @@
         }
 
         @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            if (isShowing()) {
+                if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+                    dismissH(Events.DISMISS_REASON_TOUCH_OUTSIDE);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
         public boolean dispatchPopulateAccessibilityEvent(@NonNull AccessibilityEvent event) {
             event.setClassName(getClass().getSuperclass().getName());
             event.setPackageName(mContext.getPackageName());
 
-            ViewGroup.LayoutParams params = getWindow().getAttributes();
-            boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) &&
-                    (params.height == ViewGroup.LayoutParams.MATCH_PARENT);
-            event.setFullScreen(isFullScreen);
-
             if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
                 if (mShowing) {
                     event.getText().add(mContext.getString(
@@ -1166,5 +1209,6 @@
         private int lastAudibleLevel = 1;
         private View outputChooser;
         private TextView connectedDevice;
+        private ImageView dndIcon;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
index 3d44381..0a3a2ab 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
@@ -37,10 +37,6 @@
 public class VolumeUiLayout extends FrameLayout  {
 
     private View mChild;
-    private int mOldHeight;
-    private boolean mAnimating;
-    private AnimatorSet mAnimation;
-    private boolean mHasOutsideTouch;
     private int mRotation = ROTATION_NONE;
     @Nullable
     private DisplayCutout mDisplayCutout;
@@ -52,13 +48,11 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
         mDisplayCutout = null;
     }
 
@@ -68,16 +62,11 @@
         if (mChild == null) {
             if (getChildCount() != 0) {
                 mChild = getChildAt(0);
-                mOldHeight = mChild.getMeasuredHeight();
                 updateRotation();
             } else {
                 return;
             }
         }
-        int newHeight = mChild.getMeasuredHeight();
-        if (newHeight != mOldHeight) {
-            animateChild(mOldHeight, newHeight);
-        }
     }
 
     @Override
@@ -95,8 +84,13 @@
         }
     }
 
-    private void updateRotation() {
+    public void updateRotation() {
         setDisplayCutout();
+        if (mChild == null) {
+            if (getChildCount() != 0) {
+                mChild = getChildAt(0);
+            }
+        }
         int rotation = RotationUtils.getRotation(getContext());
         if (rotation != mRotation) {
             updateSafeInsets(rotation);
@@ -144,43 +138,11 @@
         return r.bottom - r.top;
     }
 
-
-    private void animateChild(int oldHeight, int newHeight) {
-        if (true) return;
-        if (mAnimating) {
-            mAnimation.cancel();
-        }
-        mAnimating = true;
-        mAnimation = new AnimatorSet();
-        mAnimation.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mAnimating = false;
-            }
-        });
-        int fromTop = mChild.getTop();
-        int fromBottom = mChild.getBottom();
-        int toTop = fromTop - ((newHeight - oldHeight) / 2);
-        int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
-        ObjectAnimator top = ObjectAnimator.ofInt(mChild, "top", fromTop, toTop);
-        mAnimation.playTogether(top,
-                ObjectAnimator.ofInt(mChild, "bottom", fromBottom, toBottom));
-    }
-
-
     @Override
     public ViewOutlineProvider getOutlineProvider() {
         return super.getOutlineProvider();
     }
 
-    public void setOutsideTouchListener(OnClickListener onClickListener) {
-        mHasOutsideTouch = true;
-        requestLayout();
-        setOnClickListener(onClickListener);
-        setClickable(true);
-        setFocusable(true);
-    }
-
     public static VolumeUiLayout get(View v) {
         if (v instanceof VolumeUiLayout) return (VolumeUiLayout) v;
         if (v.getParent() instanceof View) {
@@ -188,16 +150,4 @@
         }
         return null;
     }
-
-    private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
-        if (mHasOutsideTouch || (mChild == null)) {
-            inoutInfo.setTouchableInsets(
-                    ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
-            return;
-        }
-        inoutInfo.setTouchableInsets(
-                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
-        inoutInfo.contentInsets.set(mChild.getLeft(), mChild.getTop(),
-                0, getBottom() - mChild.getBottom());
-    };
 }
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 936ff51..59a7da6 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -65,7 +65,6 @@
 LOCAL_JAVA_LIBRARIES := \
     android.test.runner \
     telephony-common \
-    android.car \
     android.test.base \
 
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
index 521d2e3..8c4fd73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -28,6 +28,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
 
 import android.os.Looper;
 import android.support.test.filters.SmallTest;
@@ -35,11 +36,14 @@
 import android.view.Display;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.utils.os.FakeHandler;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -48,12 +52,16 @@
     DozeServiceFake mServiceFake;
     DozeScreenState mScreen;
     FakeHandler mHandlerFake;
+    @Mock
+    DozeParameters mDozeParameters;
 
     @Before
     public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
         mServiceFake = new DozeServiceFake();
         mHandlerFake = new FakeHandler(Looper.getMainLooper());
-        mScreen = new DozeScreenState(mServiceFake, mHandlerFake);
+        mScreen = new DozeScreenState(mServiceFake, mHandlerFake, mDozeParameters);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 3e37cfe..bf6cc53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -151,22 +151,4 @@
         verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
                 eq(SystemMessage.NOTE_THERMAL_SHUTDOWN), any());
     }
-
-    @Test
-    public void testGetTimeRemainingFormatted_roundsDownTo15() {
-        mPowerNotificationWarnings.updateEstimate(
-                new Estimate(TimeUnit.MINUTES.toMillis(57), true));
-        String time = mPowerNotificationWarnings.getTimeRemainingFormatted();
-
-        assertTrue("time:" + time + ", expected: " + FORMATTED_45M, time.equals(FORMATTED_45M));
-    }
-
-    @Test
-    public void testGetTimeRemainingFormatted_keepsMinutesWhenZero() {
-        mPowerNotificationWarnings.updateEstimate(
-                new Estimate(TimeUnit.MINUTES.toMillis(65), true));
-        String time = mPowerNotificationWarnings.getTimeRemainingFormatted();
-
-        assertTrue("time:" + time + ", expected: " + FORMATTED_HOUR, time.equals(FORMATTED_HOUR));
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 0a51e5a..4b455ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -155,7 +155,7 @@
         // hybrid but the threshold has been overriden to be too low
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        ABOVE_WARNING_BUCKET, Long.MAX_VALUE, BELOW_HYBRID_THRESHOLD,
+                        ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertFalse(shouldShow);
     }
@@ -172,7 +172,7 @@
         // hybrid since the threshold has been overriden to be much higher
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        ABOVE_WARNING_BUCKET, Long.MAX_VALUE, ABOVE_HYBRID_THRESHOLD,
+                        ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertTrue(shouldShow);
     }
@@ -188,7 +188,7 @@
         // hybrid
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        ABOVE_WARNING_BUCKET, Long.MAX_VALUE, BELOW_HYBRID_THRESHOLD,
+                        ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertTrue(shouldShow);
     }
@@ -203,7 +203,7 @@
         // unplugged device that would show the non-hybrid notification and the hybrid
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, Long.MAX_VALUE, BELOW_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertTrue(shouldShow);
     }
@@ -218,7 +218,7 @@
         // unplugged device that would show the non-hybrid but not the hybrid
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, Long.MAX_VALUE, ABOVE_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertTrue(shouldShow);
     }
@@ -233,7 +233,7 @@
         // unplugged device that would show the neither due to battery level being good
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, ABOVE_HYBRID_THRESHOLD,
+                        ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertFalse(shouldShow);
     }
@@ -248,7 +248,7 @@
         // plugged device that would show the neither due to being plugged
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(!UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, BELOW_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertFalse(shouldShow);
    }
@@ -263,7 +263,7 @@
         // Unknown battery status device that would show the neither due
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, BELOW_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         !POWER_SAVER_OFF, BatteryManager.BATTERY_STATUS_UNKNOWN);
         assertFalse(shouldShow);
     }
@@ -278,12 +278,31 @@
         // BatterySaverEnabled device that would show the neither due to battery saver
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, BELOW_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         !POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertFalse(shouldShow);
     }
 
     @Test
+    public void testShouldShowLowBatteryWarning_onlyShowsOncePerChargeCycle() {
+        mPowerUI.start();
+        when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
+        when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
+        when(mEnhancedEstimates.getEstimate())
+                .thenReturn(new Estimate(BELOW_HYBRID_THRESHOLD, true));
+        mPowerUI.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD;
+
+        mPowerUI.maybeShowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                ABOVE_WARNING_BUCKET);
+        boolean shouldShow =
+                mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                        ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
+                        POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
+        assertFalse(shouldShow);
+    }
+
+    @Test
     public void testShouldDismissLowBatteryWarning_dismissWhenPowerSaverEnabled() {
         mPowerUI.start();
         when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 5f763a4..1204dda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -86,13 +86,13 @@
                 mHeadsUpManager);
         gutsManager.setUpWithPresenter(mPresenter, entryManager, mListContainer,
                 mCheckSaveListener, mOnClickListener);
-        notificationListener.setUpWithPresenter(mPresenter, entryManager);
         notificationLogger.setUpWithEntryManager(entryManager, mListContainer);
         mediaManager.setUpWithPresenter(mPresenter, entryManager);
         remoteInputManager.setUpWithPresenter(mPresenter, entryManager, mRemoteInputManagerCallback,
                 mDelegate);
         lockscreenUserManager.setUpWithPresenter(mPresenter, entryManager);
         viewHierarchyManager.setUpWithPresenter(mPresenter, entryManager, mListContainer);
+        notificationListener.setUpWithPresenter(mPresenter, entryManager);
 
         assertFalse(mDependency.hasInstantiatedDependency(StatusBarWindowManager.class));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 6e7477f..f3c1171 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -32,6 +32,7 @@
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.NotificationInflaterTest;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
@@ -51,7 +52,7 @@
     public NotificationTestHelper(Context context) {
         mContext = context;
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
-        mHeadsUpManager = new HeadsUpManager(mContext, null, mGroupManager);
+        mHeadsUpManager = new HeadsUpManagerPhone(mContext, null, mGroupManager, null, null);
     }
 
     public ExpandableNotificationRow createRow() throws Exception {
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
new file mode 100644
index 0000000..aa991cb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.app.Notification;
+import android.os.UserHandle;
+import android.view.View;
+import android.service.notification.StatusBarNotification;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertFalse;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class HeadsUpManagerPhoneTest extends SysuiTestCase {
+    @Rule public MockitoRule rule = MockitoJUnit.rule();
+
+    private static final String TEST_PACKAGE_NAME = "test";
+    private static final int TEST_UID = 0;
+
+    private HeadsUpManagerPhone mHeadsUpManager;
+
+    private NotificationData.Entry mEntry;
+    private StatusBarNotification mSbn;
+
+    @Mock private NotificationGroupManager mGroupManager;
+    @Mock private View mStatusBarWindowView;
+    @Mock private StatusBar mBar;
+    @Mock private ExpandableNotificationRow mRow;
+    @Mock private VisualStabilityManager mVSManager;
+
+    @Before
+    public void setUp() {
+        when(mVSManager.isReorderingAllowed()).thenReturn(true);
+
+        mHeadsUpManager = new HeadsUpManagerPhone(
+                mContext, mStatusBarWindowView, mGroupManager, mBar, mVSManager);
+
+        Notification.Builder n = new Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+        mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
+             0, n.build(), new UserHandle(ActivityManager.getCurrentUser()), null, 0);
+
+        mEntry = new NotificationData.Entry(mSbn);
+        mEntry.row = mRow;
+        mEntry.expandedIcon = mock(StatusBarIconView.class);
+    }
+
+    @Test
+    public void testBasicOperations() {
+        // Check the initial state.
+        assertNull(mHeadsUpManager.getEntry(mEntry.key));
+        assertNull(mHeadsUpManager.getTopEntry());
+        assertEquals(0, mHeadsUpManager.getAllEntries().count());
+        assertFalse(mHeadsUpManager.hasHeadsUpNotifications());
+
+        // Add a notification.
+        mHeadsUpManager.showNotification(mEntry);
+
+        assertEquals(mEntry, mHeadsUpManager.getEntry(mEntry.key));
+        assertEquals(mEntry, mHeadsUpManager.getTopEntry());
+        assertEquals(1, mHeadsUpManager.getAllEntries().count());
+        assertTrue(mHeadsUpManager.hasHeadsUpNotifications());
+
+        // Update the notification.
+        mHeadsUpManager.updateNotification(mEntry, false);
+
+        assertEquals(mEntry, mHeadsUpManager.getEntry(mEntry.key));
+        assertEquals(mEntry, mHeadsUpManager.getTopEntry());
+        assertEquals(1, mHeadsUpManager.getAllEntries().count());
+        assertTrue(mHeadsUpManager.hasHeadsUpNotifications());
+
+        // Try to remove but defer, since the notification is currenlt visible on display.
+        mHeadsUpManager.removeNotification(mEntry.key, false /* ignoreEarliestRemovalTime */);
+
+        assertEquals(mEntry, mHeadsUpManager.getEntry(mEntry.key));
+        assertEquals(mEntry, mHeadsUpManager.getTopEntry());
+        assertEquals(1, mHeadsUpManager.getAllEntries().count());
+        assertTrue(mHeadsUpManager.hasHeadsUpNotifications());
+
+        // Remove forcibly with ignoreEarliestRemovalTime = true.
+        mHeadsUpManager.removeNotification(mEntry.key, true /* ignoreEarliestRemovalTime */);
+
+        // Check the initial state.
+        assertNull(mHeadsUpManager.getEntry(mEntry.key));
+        assertNull(mHeadsUpManager.getTopEntry());
+        assertEquals(0, mHeadsUpManager.getAllEntries().count());
+        assertFalse(mHeadsUpManager.hasHeadsUpNotifications());
+    }
+
+    @Test
+    public void testsTimeoutRemoval() {
+        mHeadsUpManager.removeMinimumDisplayTimeForTesting();
+
+        // Check the initial state.
+        assertNull(mHeadsUpManager.getEntry(mEntry.key));
+        assertNull(mHeadsUpManager.getTopEntry());
+        assertEquals(0, mHeadsUpManager.getAllEntries().count());
+        assertFalse(mHeadsUpManager.hasHeadsUpNotifications());
+
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+
+        // Run the code on the main thready, not to run an async operations.
+        instrumentation.runOnMainSync(() -> {
+            // Add a notification.
+            mHeadsUpManager.showNotification(mEntry);
+
+            // Ensure the head up is visible before timeout.
+            assertNotNull(mHeadsUpManager.getEntry(mEntry.key));
+            assertNotNull(mHeadsUpManager.getTopEntry());
+            assertEquals(1, mHeadsUpManager.getAllEntries().count());
+            assertTrue(mHeadsUpManager.hasHeadsUpNotifications());
+        });
+        // Wait for the async operations, which removes the heads up notification.
+        waitForIdleSync();
+
+        assertNull(mHeadsUpManager.getEntry(mEntry.key));
+        assertNull(mHeadsUpManager.getTopEntry());
+        assertEquals(0, mHeadsUpManager.getAllEntries().count());
+        assertFalse(mHeadsUpManager.hasHeadsUpNotifications());
+    }
+
+    @Test
+    public void releaseImmediately() {
+        // Check the initial state.
+        assertNull(mHeadsUpManager.getEntry(mEntry.key));
+        assertNull(mHeadsUpManager.getTopEntry());
+        assertEquals(0, mHeadsUpManager.getAllEntries().count());
+        assertFalse(mHeadsUpManager.hasHeadsUpNotifications());
+
+        // Add a notification.
+        mHeadsUpManager.showNotification(mEntry);
+
+        assertEquals(mEntry, mHeadsUpManager.getEntry(mEntry.key));
+        assertEquals(mEntry, mHeadsUpManager.getTopEntry());
+        assertEquals(1, mHeadsUpManager.getAllEntries().count());
+        assertTrue(mHeadsUpManager.hasHeadsUpNotifications());
+
+        // Remove but defer, since the notification is visible on display.
+        mHeadsUpManager.releaseImmediately(mEntry.key);
+
+        assertNull(mHeadsUpManager.getEntry(mEntry.key));
+        assertNull(mHeadsUpManager.getTopEntry());
+        assertEquals(0, mHeadsUpManager.getAllEntries().count());
+        assertFalse(mHeadsUpManager.hasHeadsUpNotifications());
+    }
+
+    @Test
+    public void releaseAllImmediately() {
+        // Check the initial state.
+        assertNull(mHeadsUpManager.getEntry(mEntry.key));
+        assertNull(mHeadsUpManager.getTopEntry());
+        assertEquals(0, mHeadsUpManager.getAllEntries().count());
+        assertFalse(mHeadsUpManager.hasHeadsUpNotifications());
+
+        // Add a notification.
+        mHeadsUpManager.showNotification(mEntry);
+
+        assertEquals(mEntry, mHeadsUpManager.getEntry(mEntry.key));
+        assertEquals(mEntry, mHeadsUpManager.getTopEntry());
+        assertEquals(1, mHeadsUpManager.getAllEntries().count());
+        assertTrue(mHeadsUpManager.hasHeadsUpNotifications());
+
+        // Remove but defer, since the notification is visible on display.
+        mHeadsUpManager.releaseAllImmediately();
+
+        assertNull(mHeadsUpManager.getEntry(mEntry.key));
+        assertNull(mHeadsUpManager.getTopEntry());
+        assertEquals(0, mHeadsUpManager.getAllEntries().count());
+        assertFalse(mHeadsUpManager.hasHeadsUpNotifications());
+    }
+}
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 6d2691c..43e16db 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
@@ -38,6 +38,7 @@
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.Choreographer;
 import android.view.View;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -374,7 +375,6 @@
             onPreDraw();
 
             // Force finish screen blanking.
-            endAnimation(mScrimInFront, TAG_KEY_ANIM_BLANK);
             mHandler.dispatchQueuedMessages();
             // Force finish all animations.
             endAnimation(mScrimBehind, TAG_KEY_ANIM);
@@ -401,6 +401,15 @@
         protected WakeLock createWakeLock() {
             return mWakeLock;
         }
+
+        /**
+         * Do not wait for a frame since we're in a test environment.
+         * @param callback What to execute.
+         */
+        @Override
+        protected void doOnTheNextFrame(Choreographer.FrameCallback callback) {
+            callback.doFrame(0);
+        }
     }
 
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index bdf9b1f..31442af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -86,8 +86,8 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -110,7 +110,7 @@
     @Mock private UnlockMethodCache mUnlockMethodCache;
     @Mock private KeyguardIndicationController mKeyguardIndicationController;
     @Mock private NotificationStackScrollLayout mStackScroller;
-    @Mock private HeadsUpManager mHeadsUpManager;
+    @Mock private HeadsUpManagerPhone mHeadsUpManager;
     @Mock private SystemServicesProxy mSystemServicesProxy;
     @Mock private NotificationPanelView mNotificationPanelView;
     @Mock private IStatusBarService mBarService;
@@ -588,7 +588,7 @@
     static class TestableStatusBar extends StatusBar {
         public TestableStatusBar(StatusBarKeyguardViewManager man,
                 UnlockMethodCache unlock, KeyguardIndicationController key,
-                NotificationStackScrollLayout stack, HeadsUpManager hum,
+                NotificationStackScrollLayout stack, HeadsUpManagerPhone hum,
                 PowerManager pm, NotificationPanelView panelView,
                 IStatusBarService barService, NotificationListener notificationListener,
                 NotificationLogger notificationLogger,
@@ -650,7 +650,7 @@
         public void setUpForTest(NotificationPresenter presenter,
                 NotificationListContainer listContainer,
                 Callback callback,
-                HeadsUpManager headsUpManager,
+                HeadsUpManagerPhone headsUpManager,
                 NotificationData notificationData) {
             super.setUpWithPresenter(presenter, listContainer, callback, headsUpManager);
             mNotificationData = notificationData;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index a10bebf..e1b97bda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -29,12 +29,14 @@
 import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
+@Ignore
 public class LocationControllerImplTest extends SysuiTestCase {
 
     private LocationControllerImpl mLocationController;
@@ -79,4 +81,4 @@
 
         TestableLooper.get(this).processAllMessages();
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
new file mode 100644
index 0000000..32a7cb9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class SmartReplyConstantsTest extends SysuiTestCase {
+
+    private static final int CONTENT_OBSERVER_TIMEOUT_SECONDS = 10;
+
+    private SmartReplyConstants mConstants;
+
+    @Before
+    public void setUp() {
+        overrideSetting(null); // No config.
+        TestableResources resources = mContext.getOrCreateTestableResources();
+        resources.addOverride(R.bool.config_smart_replies_in_notifications_enabled, true);
+        resources.addOverride(
+                R.integer.config_smart_replies_in_notifications_max_squeeze_remeasure_attempts, 7);
+        mConstants = new SmartReplyConstants(new Handler(Looper.getMainLooper()), mContext);
+    }
+
+    @Test
+    public void testIsEnabledWithNoConfig() {
+        assertTrue(mConstants.isEnabled());
+    }
+
+    @Test
+    public void testIsEnabledWithInvalidConfig() {
+        overrideSetting("invalid config");
+        triggerConstantsOnChange();
+        assertTrue(mConstants.isEnabled());
+    }
+
+    @Test
+    public void testIsEnabledWithValidConfig() {
+        overrideSetting("enabled=false,max_squeeze_remeasure_attempts=5");
+        triggerConstantsOnChange();
+        assertFalse(mConstants.isEnabled());
+    }
+
+    @Test
+    public void testGetMaxSqueezeRemeasureAttemptsWithNoConfig() {
+        assertTrue(mConstants.isEnabled());
+        assertEquals(7, mConstants.getMaxSqueezeRemeasureAttempts());
+    }
+
+    @Test
+    public void testGetMaxSqueezeRemeasureAttemptsWithInvalidConfig() {
+        overrideSetting("invalid config");
+        triggerConstantsOnChange();
+        assertEquals(7, mConstants.getMaxSqueezeRemeasureAttempts());
+    }
+
+    @Test
+    public void testGetMaxSqueezeRemeasureAttemptsWithValidConfig() {
+        overrideSetting("enabled=false,max_squeeze_remeasure_attempts=5");
+        triggerConstantsOnChange();
+        assertEquals(5, mConstants.getMaxSqueezeRemeasureAttempts());
+    }
+
+    private void overrideSetting(String flags) {
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS, flags);
+    }
+
+    private void triggerConstantsOnChange() {
+        // Since Settings.Global is mocked in TestableContext, we need to manually trigger the
+        // content observer.
+        mConstants.onChange(false,
+                Settings.Global.getUriFor(Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java
index f7bb065..922bde7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.volume;
 
+import static com.android.systemui.volume.OutputChooserDialog.INCLUDE_MEDIA_ROUTES;
+
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -149,19 +151,13 @@
     }
 
     @Test
-    public void testMediaScanIfNotInCall() {
-        mDialog.setIsInCall(false);
-        mDialog.onAttachedToWindow();
-
-        verify(mRouter, times(1)).addCallback(any(), any(), anyInt());
-    }
-
-    @Test
     public void testRegisterCallbacks() {
         mDialog.setIsInCall(false);
         mDialog.onAttachedToWindow();
 
-        verify(mRouter, times(1)).addCallback(any(), any(), anyInt());
+        if (INCLUDE_MEDIA_ROUTES) {
+            verify(mRouter, times(1)).addCallback(any(), any(), anyInt());
+        }
         verify(mController, times(1)).addCallback(any());
         verify(mVolumeController, times(1)).addCallback(any(), any());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 401fd68..a4ed459 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -76,6 +76,16 @@
     }
 
     @Test
+    public void testVolumeChangeW_nullStatusBar() {
+        VolumeDialogControllerImpl.C callback = mock(VolumeDialogControllerImpl.C.class);
+        TestableVolumeDialogControllerImpl nullStatusBarTestableDialog =  new
+                TestableVolumeDialogControllerImpl(mContext, callback, null);
+        nullStatusBarTestableDialog.setEnableDialogs(true, true);
+        nullStatusBarTestableDialog.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
+        verify(callback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
+    }
+
+    @Test
     public void testOnRemoteVolumeChanged_newStream_noNullPointer() {
         MediaSession.Token token = new MediaSession.Token(null);
         mVolumeController.mMediaSessionsCallbacksW.onRemoteVolumeChanged(token, 0);
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index 0254673..7efe8ab 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -5,8 +5,6 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := telephony-common
-
 LOCAL_PACKAGE_NAME := WallpaperCropper
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
diff --git a/proto/Android.bp b/proto/Android.bp
index 95f453c..f3811bd 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -6,6 +6,8 @@
     },
     srcs: ["src/**/*.proto"],
     no_framework_libs: true,
+    // Pin java_version until jarjar is certified to support later versions. http://b/72703434
+    java_version: "1.8",
     target: {
         android: {
             jarjar_rules: "jarjar-rules.txt",
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 01714cf..ae5e133 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5171,6 +5171,7 @@
     // An autofill service was bound using an unofficial(but still supported) permission.
     // Package: Package of the autofill service
     // OS: P
+
     AUTOFILL_INVALID_PERMISSION = 1289;
 
     // OPEN: QS Alarm tile shown
@@ -5185,6 +5186,33 @@
     // OS: P
     USB_DEVICE_DETAILS = 1291;
 
+    // OPEN: Settings > Accessibility > Vibration
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACCESSIBILITY_VIBRATION = 1292;
+
+    // OPEN: Settings > Accessibility > Vibration > Ring & notification vibration
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACCESSIBILITY_VIBRATION_NOTIFICATION = 1293;
+
+    // OPEN: Settings > Accessibility > Vibration > Touch vibration
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACCESSIBILITY_VIBRATION_TOUCH = 1294;
+
+    // OPEN: Volume panel > output chooser dialog
+    // OS: P
+    OUTPUT_CHOOSER = 1295;
+
+    // Action: Volume panel > output chooser dialog > tap on device
+    // OS: P
+    ACTION_OUTPUT_CHOOSER_CONNECT = 1296;
+
+    // Action: Volume panel > output chooser dialog > tap on X next to connected device
+    // OS: P
+    ACTION_OUTPUT_CHOOSER_DISCONNECT = 1297;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index fc6058c..eba9830 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1020,7 +1020,7 @@
 
             // Disconnect from services for the old user.
             UserState oldUserState = getCurrentUserStateLocked();
-            oldUserState.onSwitchToAnotherUser();
+            oldUserState.onSwitchToAnotherUserLocked();
 
             // Disable the local managers for the old user.
             if (oldUserState.mUserClients.getRegisteredCallbackCount() > 0) {
@@ -1349,21 +1349,29 @@
     private void updateRelevantEventsLocked(UserState userState) {
         mMainHandler.post(() -> {
             broadcastToClients(userState, ignoreRemoteException(client -> {
-                int relevantEventTypes = computeRelevantEventTypes(userState, client);
+                int relevantEventTypes;
+                boolean changed = false;
+                synchronized (mLock) {
+                    relevantEventTypes = computeRelevantEventTypesLocked(userState, client);
 
-                if (client.mLastSentRelevantEventTypes != relevantEventTypes) {
-                    client.mLastSentRelevantEventTypes = relevantEventTypes;
+                    if (client.mLastSentRelevantEventTypes != relevantEventTypes) {
+                        client.mLastSentRelevantEventTypes = relevantEventTypes;
+                        changed = true;
+                    }
+                }
+                if (changed) {
                     client.mCallback.setRelevantEventTypes(relevantEventTypes);
                 }
             }));
         });
     }
 
-    private int computeRelevantEventTypes(UserState userState, Client client) {
+    private int computeRelevantEventTypesLocked(UserState userState, Client client) {
         int relevantEventTypes = 0;
 
-        // Use iterator for thread-safety
-        for (AccessibilityServiceConnection service : userState.mBoundServices) {
+        int serviceCount = userState.mBoundServices.size();
+        for (int i = 0; i < serviceCount; i++) {
+            AccessibilityServiceConnection service = userState.mBoundServices.get(i);
             relevantEventTypes |= isClientInPackageWhitelist(service.getServiceInfo(), client)
                     ? service.getRelevantEventTypes()
                     : 0;
@@ -3616,7 +3624,9 @@
         private Client(IAccessibilityManagerClient callback, int clientUid, UserState userState) {
             mCallback = callback;
             mPackageNames = mPackageManager.getPackagesForUid(clientUid);
-            mLastSentRelevantEventTypes = computeRelevantEventTypes(userState, this);
+            synchronized (mLock) {
+                mLastSentRelevantEventTypes = computeRelevantEventTypesLocked(userState, this);
+            }
         }
     }
 
@@ -3635,8 +3645,7 @@
 
         // Transient state.
 
-        public final CopyOnWriteArrayList<AccessibilityServiceConnection> mBoundServices =
-                new CopyOnWriteArrayList<>();
+        public final ArrayList<AccessibilityServiceConnection> mBoundServices = new ArrayList<>();
 
         public final Map<ComponentName, AccessibilityServiceConnection> mComponentNameToServiceMap =
                 new HashMap<>();
@@ -3698,7 +3707,7 @@
             return !mBoundServices.isEmpty() || !mBindingServices.isEmpty();
         }
 
-        public void onSwitchToAnotherUser() {
+        public void onSwitchToAnotherUserLocked() {
             // Unbind all services.
             unbindAllServicesLocked(this);
 
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index a70b88e..c36bb6d 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -901,6 +901,7 @@
             }
         }
 
+        @GuardedBy("mLock")
         private void setMagnificationSpecLocked(MagnificationSpec spec) {
             if (mEnabled) {
                 if (DEBUG_SET_MAGNIFICATION_SPEC) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 72c3c94..d5a722b 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -306,6 +306,7 @@
      *
      * @return service instance.
      */
+    @GuardedBy("mLock")
     @NonNull
     AutofillManagerServiceImpl getServiceForUserLocked(int userId) {
         final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
@@ -325,6 +326,7 @@
      *
      * @return service instance or {@code null} if not already present
      */
+    @GuardedBy("mLock")
     @Nullable
     AutofillManagerServiceImpl peekServiceForUserLocked(int userId) {
         final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
@@ -474,6 +476,7 @@
     /**
      * Removes a cached service for a given user.
      */
+    @GuardedBy("mLock")
     private void removeCachedServiceLocked(int userId) {
         final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
         if (service != null) {
@@ -485,6 +488,7 @@
     /**
      * Updates a cached service for a given user.
      */
+    @GuardedBy("mLock")
     private void updateCachedServiceLocked(int userId) {
         updateCachedServiceLocked(userId, mDisabledUsers.get(userId));
     }
@@ -492,6 +496,7 @@
     /**
      * Updates a cached service for a given user.
      */
+    @GuardedBy("mLock")
     private void updateCachedServiceLocked(int userId, boolean disabled) {
         AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
         if (service != null) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 297dcf1..2dcc6da 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -211,6 +211,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private int getServiceUidLocked() {
         if (mInfo == null) {
             Slog.w(TAG,  "getServiceUidLocked(): no mInfo");
@@ -248,6 +249,7 @@
                 mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
     }
 
+    @GuardedBy("mLock")
     void updateLocked(boolean disabled) {
         final boolean wasEnabled = isEnabledLocked();
         if (sVerbose) {
@@ -300,6 +302,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     boolean addClientLocked(IAutoFillManagerClient client) {
         if (mClients == null) {
             mClients = new RemoteCallbackList<>();
@@ -308,12 +311,14 @@
         return isEnabledLocked();
     }
 
+    @GuardedBy("mLock")
     void removeClientLocked(IAutoFillManagerClient client) {
         if (mClients != null) {
             mClients.unregister(client);
         }
     }
 
+    @GuardedBy("mLock")
     void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) {
         if (!isEnabledLocked()) {
             return;
@@ -336,6 +341,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     int startSessionLocked(@NonNull IBinder activityToken, int uid,
             @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
@@ -389,6 +395,7 @@
     /**
      * Remove abandoned sessions if needed.
      */
+    @GuardedBy("mLock")
     private void pruneAbandonedSessionsLocked() {
         long now = System.currentTimeMillis();
         if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) {
@@ -400,6 +407,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void finishSessionLocked(int sessionId, int uid) {
         if (!isEnabledLocked()) {
             return;
@@ -423,6 +431,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void cancelSessionLocked(int sessionId, int uid) {
         if (!isEnabledLocked()) {
             return;
@@ -436,6 +445,7 @@
         session.removeSelfLocked();
     }
 
+    @GuardedBy("mLock")
     void disableOwnedAutofillServicesLocked(int uid) {
         Slog.i(TAG, "disableOwnedServices(" + uid + "): " + mInfo);
         if (mInfo == null) return;
@@ -468,6 +478,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
             @NonNull IBinder appCallbackToken, boolean hasCallback,
             @NonNull ComponentName componentName, int flags) {
@@ -546,6 +557,7 @@
     /**
      * Updates a session and returns whether it should be restarted.
      */
+    @GuardedBy("mLock")
     boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
             AutofillValue value, int action, int flags) {
         final Session session = mSessions.get(sessionId);
@@ -568,6 +580,7 @@
         return false;
     }
 
+    @GuardedBy("mLock")
     void removeSessionLocked(int sessionId) {
         mSessions.remove(sessionId);
     }
@@ -603,6 +616,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void destroyLocked() {
         if (sVerbose) Slog.v(TAG, "destroyLocked()");
 
@@ -655,6 +669,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private boolean isValidEventLocked(String method, int sessionId) {
         if (mEventHistory == null) {
             Slog.w(TAG, method + ": not logging event because history is null");
@@ -726,6 +741,7 @@
     /**
      * Updates the last fill response when an autofill context is committed.
      */
+    @GuardedBy("mLock")
     void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState,
             @Nullable ArrayList<String> selectedDatasets,
             @Nullable ArraySet<String> ignoredDatasets,
@@ -739,6 +755,7 @@
                 manuallyFilledDatasetIds, null, null, appPackageName);
     }
 
+    @GuardedBy("mLock")
     void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState,
             @Nullable ArrayList<String> selectedDatasets,
             @Nullable ArraySet<String> ignoredDatasets,
@@ -847,6 +864,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private boolean isCalledByServiceLocked(String methodName, int callingUid) {
         if (getServiceUidLocked() != callingUid) {
             Slog.w(TAG, methodName + "() called by UID " + callingUid
@@ -856,13 +874,19 @@
         return true;
     }
 
+    @GuardedBy("mLock")
     void dumpLocked(String prefix, PrintWriter pw) {
         final String prefix2 = prefix + "  ";
 
         pw.print(prefix); pw.print("User: "); pw.println(mUserId);
         pw.print(prefix); pw.print("UID: "); pw.println(getServiceUidLocked());
-        pw.print(prefix); pw.print("Component: "); pw.println(mInfo != null
-                ? mInfo.getServiceInfo().getComponentName() : null);
+        pw.print(prefix); pw.print("Autofill Service Info: ");
+        if (mInfo == null) {
+            pw.println("N/A");
+        } else {
+            pw.println();
+            mInfo.dump(prefix2, pw);
+        }
         pw.print(prefix); pw.print("Component from settings: ");
             pw.println(getComponentNameFromSettings());
         pw.print(prefix); pw.print("Default component: ");
@@ -870,6 +894,7 @@
         pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
         pw.print(prefix); pw.print("Field classification enabled: ");
             pw.println(isFieldClassificationEnabledLocked());
+        pw.print(prefix); pw.print("Compat pkgs: "); pw.println(getWhitelistedCompatModePackages());
         pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
         pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
 
@@ -959,6 +984,7 @@
         mFieldClassificationStrategy.dump(prefix2, pw);
     }
 
+    @GuardedBy("mLock")
     void destroySessionsLocked() {
         if (mSessions.size() == 0) {
             mUi.destroyAll(null, null, false);
@@ -970,6 +996,7 @@
     }
 
     // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities
+    @GuardedBy("mLock")
     void destroyFinishedSessionsLocked() {
         final int sessionCount = mSessions.size();
         for (int i = sessionCount - 1; i >= 0; i--) {
@@ -981,6 +1008,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void listSessionsLocked(ArrayList<String> output) {
         final int numSessions = mSessions.size();
         for (int i = 0; i < numSessions; i++) {
@@ -989,6 +1017,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     boolean isCompatibilityModeRequestedLocked(@NonNull String packageName,
             long versionCode) {
         if (mInfo == null || !mInfo.isCompatibilityModeRequested(packageName, versionCode)) {
@@ -996,14 +1025,18 @@
         }
         if (!Build.IS_ENG) {
             // TODO: Build a map and watch for settings changes (this is called on app start)
-            final String whiteListedPackages = Settings.Global.getString(
-                    mContext.getContentResolver(),
-                    Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+            final String whiteListedPackages = getWhitelistedCompatModePackages();
             return whiteListedPackages != null && whiteListedPackages.contains(packageName);
         }
         return true;
     }
 
+    private String getWhitelistedCompatModePackages() {
+        return Settings.Global.getString(
+                mContext.getContentResolver(),
+                Settings.Global.AUTOFILL_COMPAT_ALLOWED_PACKAGES);
+    }
+
     private void sendStateToClients(boolean resetClient) {
         final RemoteCallbackList<IAutoFillManagerClient> clients;
         final int userClientCount;
@@ -1050,6 +1083,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private boolean isClientSessionDestroyedLocked(IAutoFillManagerClient client) {
         final int sessionCount = mSessions.size();
         for (int i = 0; i < sessionCount; i++) {
@@ -1061,6 +1095,7 @@
         return true;
     }
 
+    @GuardedBy("mLock")
     boolean isEnabledLocked() {
         return mSetupComplete && mInfo != null && !mDisabled;
     }
@@ -1113,6 +1148,7 @@
     /**
      * Checks if autofill is disabled by service to the given activity.
      */
+    @GuardedBy("mLock")
     private boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) {
         // Check activities first.
         long elapsedTime = 0;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index aea9ad0..fe6d4c4 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -475,6 +475,7 @@
             return true;
         }
 
+        @GuardedBy("mLock")
         protected boolean isCancelledLocked() {
             return mCancelled;
         }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 6108afa..4a24704 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -300,6 +300,7 @@
     /**
      * Returns the ids of all entries in {@link #mViewStates} in the same order.
      */
+    @GuardedBy("mLock")
     private AutofillId[] getIdsOfAllViewStatesLocked() {
         final int numViewState = mViewStates.size();
         final AutofillId[] ids = new AutofillId[numViewState];
@@ -346,6 +347,7 @@
      * <p>Gets the value of a field, using either the {@code viewStates} or the {@code mContexts},
      * or {@code null} when not found on either of them.
      */
+    @GuardedBy("mLock")
     private AutofillValue findValueLocked(@NonNull AutofillId id) {
         final ViewState state = mViewStates.get(id);
         if (state == null) {
@@ -369,6 +371,7 @@
      * @param fillContext The context to be filled
      * @param flags The flags that started the session
      */
+    @GuardedBy("mLock")
     private void fillContextWithAllowedValuesLocked(@NonNull FillContext fillContext, int flags) {
         final ViewNode[] nodes = fillContext
                 .findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
@@ -409,6 +412,7 @@
     /**
      * Cancels the last request sent to the {@link #mRemoteFillService}.
      */
+    @GuardedBy("mLock")
     private void cancelCurrentRequestLocked() {
         final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
 
@@ -430,6 +434,7 @@
     /**
      * Reads a new structure and then request a new fill response from the fill service.
      */
+    @GuardedBy("mLock")
     private void requestNewFillResponseLocked(int flags) {
         int requestId;
 
@@ -497,6 +502,7 @@
      *
      * @return The activity token
      */
+    @GuardedBy("mLock")
     @NonNull IBinder getActivityTokenLocked() {
         return mActivityToken;
     }
@@ -663,6 +669,7 @@
      *
      * @return The context or {@code null} if there is no context
      */
+    @GuardedBy("mLock")
     @Nullable private FillContext getFillContextByRequestIdLocked(int requestId) {
         if (mContexts == null) {
             return null;
@@ -820,6 +827,7 @@
         });
     }
 
+    @GuardedBy("mLock")
     void setAuthenticationResultLocked(Bundle data, int authenticationId) {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#setAuthenticationResultLocked() rejected - session: "
@@ -882,6 +890,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void setHasCallbackLocked(boolean hasIt) {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#setHasCallbackLocked() rejected - session: "
@@ -891,6 +900,7 @@
         mHasCallback = hasIt;
     }
 
+    @GuardedBy("mLock")
     @Nullable
     private FillResponse getLastResponseLocked(@Nullable String logPrefix) {
         if (mContexts == null) {
@@ -923,6 +933,7 @@
         return response;
     }
 
+    @GuardedBy("mLock")
     @Nullable
     private SaveInfo getSaveInfoLocked() {
         final FillResponse response = getLastResponseLocked(null);
@@ -941,13 +952,14 @@
         });
     }
 
+    @GuardedBy("mLock")
     private void logContextCommittedLocked() {
         final FillResponse lastResponse = getLastResponseLocked("logContextCommited()");
         if (lastResponse == null) return;
 
         final int flags = lastResponse.getFlags();
         if ((flags & FillResponse.FLAG_TRACK_CONTEXT_COMMITED) == 0) {
-            if (sDebug) Slog.d(TAG, "logContextCommittedLocked(): ignored by flags " + flags);
+            if (sVerbose) Slog.v(TAG, "logContextCommittedLocked(): ignored by flags " + flags);
             return;
         }
 
@@ -1241,6 +1253,7 @@
      *
      * @return {@code true} if session is done, or {@code false} if it's pending user action.
      */
+    @GuardedBy("mLock")
     public boolean showSaveLocked() {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#showSaveLocked() rejected - session: "
@@ -1431,7 +1444,10 @@
                     }
                 }
 
-                if (sDebug) Slog.d(TAG, "Good news, everyone! All checks passed, show save UI!");
+                if (sDebug) {
+                    Slog.d(TAG, "Good news, everyone! All checks passed, show save UI for "
+                            + id + "!");
+                }
 
                 // Use handler so logContextCommitted() is logged first
                 mHandlerCaller.getHandler().post(() -> mService.logSaveShown(id, mClientState));
@@ -1455,7 +1471,7 @@
         }
         // Nothing changed...
         if (sDebug) {
-            Slog.d(TAG, "showSaveLocked(): with no changes, comes no responsibilities."
+            Slog.d(TAG, "showSaveLocked(" + id +"): with no changes, comes no responsibilities."
                     + "allRequiredAreNotNull=" + allRequiredAreNotEmpty
                     + ", atLeastOneChanged=" + atLeastOneChanged);
         }
@@ -1507,6 +1523,7 @@
     /**
      * Returns whether the session is currently showing the save UI
      */
+    @GuardedBy("mLock")
     boolean isSavingLocked() {
         return mIsSaving;
     }
@@ -1514,6 +1531,7 @@
     /**
      * Gets the latest non-empty value for the given id in the autofill contexts.
      */
+    @GuardedBy("mLock")
     @Nullable
     private AutofillValue getValueFromContextsLocked(AutofillId id) {
         final int numContexts = mContexts.size();
@@ -1536,6 +1554,7 @@
     /**
      * Gets the latest autofill options for the given id in the autofill contexts.
      */
+    @GuardedBy("mLock")
     @Nullable
     private CharSequence[] getAutofillOptionsFromContextsLocked(AutofillId id) {
         final int numContexts = mContexts.size();
@@ -1553,6 +1572,7 @@
     /**
      * Calls service when user requested save.
      */
+    @GuardedBy("mLock")
     void callSaveLocked() {
         if (mDestroyed) {
             Slog.w(TAG, "Call to Session#callSaveLocked() rejected - session: "
@@ -1643,6 +1663,7 @@
      * @param viewState The view that is entered.
      * @param flags The flag that was passed by the AutofillManager.
      */
+    @GuardedBy("mLock")
     private void requestNewFillResponseOnViewEnteredIfNecessaryLocked(@NonNull AutofillId id,
             @NonNull ViewState viewState, int flags) {
         if ((flags & FLAG_MANUAL_REQUEST) != 0) {
@@ -1670,6 +1691,7 @@
      *
      * @return {@code true} iff a new partition should be started
      */
+    @GuardedBy("mLock")
     private boolean shouldStartNewPartitionLocked(@NonNull AutofillId id) {
         if (mResponses == null) {
             return true;
@@ -1718,6 +1740,7 @@
         return true;
     }
 
+    @GuardedBy("mLock")
     void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int action,
             int flags) {
         if (mDestroyed) {
@@ -1827,6 +1850,7 @@
     /**
      * Checks whether a view should be ignored.
      */
+    @GuardedBy("mLock")
     private boolean isIgnoredLocked(AutofillId id) {
         // Always check the latest response only
         final FillResponse response = getLastResponseLocked(null);
@@ -1907,6 +1931,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void updateTrackedIdsLocked() {
         // Only track the views of the last response as only those are reported back to the
         // service, see #showSaveLocked
@@ -1970,7 +1995,7 @@
         try {
             if (sVerbose) {
                 Slog.v(TAG, "updateTrackedIdsLocked(): " + trackedViews + " => " + fillableIds
-                        + " (triggering on " + saveTriggerId + ")");
+                        + " triggerId: " + saveTriggerId + " saveOnFinish:" + saveOnFinish);
             }
             mClient.setTrackedViews(id, toArray(trackedViews), saveOnAllViewsInvisible,
                     saveOnFinish, toArray(fillableIds), saveTriggerId);
@@ -1979,6 +2004,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void replaceResponseLocked(@NonNull FillResponse oldResponse,
             @NonNull FillResponse newResponse, @Nullable Bundle newClientState) {
         // Disassociate view states with the old response
@@ -2002,6 +2028,7 @@
         removeSelf();
     }
 
+    @GuardedBy("mLock")
     private void processResponseLocked(@NonNull FillResponse newResponse,
             @Nullable Bundle newClientState, int flags) {
         // Make sure we are hiding the UI which will be shown
@@ -2039,6 +2066,7 @@
     /**
      * Sets the state of all views in the given response.
      */
+    @GuardedBy("mLock")
     private void setViewStatesLocked(FillResponse response, int state, boolean clearResponse) {
         final List<Dataset> datasets = response.getDatasets();
         if (datasets != null) {
@@ -2087,6 +2115,7 @@
     /**
      * Sets the state of all views in the given dataset and response.
      */
+    @GuardedBy("mLock")
     private void setViewStatesLocked(@Nullable FillResponse response, @NonNull Dataset dataset,
             int state, boolean clearResponse) {
         final ArrayList<AutofillId> ids = dataset.getFieldIds();
@@ -2107,6 +2136,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private ViewState createOrUpdateViewStateLocked(@NonNull AutofillId id, int state,
             @Nullable AutofillValue value) {
         ViewState viewState = mViewStates.get(id);
@@ -2168,6 +2198,7 @@
     }
 
     // TODO: this should never be null, but we got at least one occurrence, probably due to a race.
+    @GuardedBy("mLock")
     @Nullable
     private Intent createAuthFillInIntentLocked(int requestId, Bundle extras) {
         final Intent fillInIntent = new Intent();
@@ -2200,6 +2231,7 @@
         return "Session: [id=" + id + ", component=" + mComponentName + "]";
     }
 
+    @GuardedBy("mLock")
     void dumpLocked(String prefix, PrintWriter pw) {
         final String prefix2 = prefix + "  ";
         pw.print(prefix); pw.print("id: "); pw.println(id);
@@ -2329,6 +2361,7 @@
      *       disabled it).
      * </ul>
      */
+    @GuardedBy("mLock")
     RemoteFillService destroyLocked() {
         if (mDestroyed) {
             return null;
@@ -2344,6 +2377,7 @@
      * Cleans up this session and remove it from the service always, even if it does have a pending
      * Save UI.
      */
+    @GuardedBy("mLock")
     void forceRemoveSelfLocked() {
         if (sVerbose) Slog.v(TAG, "forceRemoveSelfLocked(): " + mPendingSaveUi);
 
@@ -2373,6 +2407,7 @@
      * Cleans up this session and remove it from the service, but but only if it does not have a
      * pending Save UI.
      */
+    @GuardedBy("mLock")
     void removeSelfLocked() {
         if (sVerbose) Slog.v(TAG, "removeSelfLocked(): " + mPendingSaveUi);
         if (mDestroyed) {
@@ -2401,6 +2436,7 @@
      * a specific {@code token} created by
      * {@link PendingUi#PendingUi(IBinder, int, IAutoFillManagerClient)}.
      */
+    @GuardedBy("mLock")
     boolean isSaveUiPendingForTokenLocked(@NonNull IBinder token) {
         return isSaveUiPendingLocked() && token.equals(mPendingSaveUi.getToken());
     }
@@ -2408,10 +2444,12 @@
     /**
      * Checks whether this session is hiding the Save UI to handle a custom description link.
      */
+    @GuardedBy("mLock")
     private boolean isSaveUiPendingLocked() {
         return mPendingSaveUi != null && mPendingSaveUi.getState() == PendingUi.STATE_PENDING;
     }
 
+    @GuardedBy("mLock")
     private int getLastResponseIndexLocked() {
         // The response ids are monotonically increasing so
         // we just find the largest id which is the last. We
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 3b80f55..83367f3 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1931,6 +1931,7 @@
     /**
      * Remove a package from the full-data queue.
      */
+    @GuardedBy("mQueueLock")
     private void dequeueFullBackupLocked(String packageName) {
         final int N = mFullBackupQueue.size();
         for (int i = N - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index f49cd67..10fad62 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -55,9 +55,11 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.system.Os;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.KeyValueListParser;
 import android.util.Log;
 import android.util.Pair;
@@ -79,7 +81,6 @@
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.Locale;
 import java.util.Random;
@@ -88,6 +89,7 @@
 import java.util.function.Predicate;
 
 import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
+import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
 import static android.app.AlarmManager.RTC_WAKEUP;
 import static android.app.AlarmManager.RTC;
 import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
@@ -98,7 +100,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.LocalLog;
-import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.internal.util.Preconditions;
+import com.android.server.AppStateTracker.Listener;
 
 /**
  * Alarm manager implementaion.
@@ -157,6 +160,7 @@
     private long mNextNonWakeup;
     private long mLastWakeupSet;
     private long mLastWakeup;
+    private long mLastTrigger;
     private long mLastTickSet;
     private long mLastTickIssued; // elapsed
     private long mLastTickReceived;
@@ -224,10 +228,12 @@
 
     interface Stats {
         int REBATCH_ALL_ALARMS = 0;
+        int REORDER_ALARMS_FOR_STANDBY = 1;
     }
 
     private final StatLogger mStatLogger = new StatLogger(new String[] {
             "REBATCH_ALL_ALARMS",
+            "REORDER_ALARMS_FOR_STANDBY",
     });
 
     /**
@@ -247,7 +253,7 @@
     private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
             new SparseArray<>();
 
-    private final ForceAppStandbyTracker mForceAppStandbyTracker;
+    private AppStateTracker mAppStateTracker;
     private boolean mAppStandbyParole;
     private ArrayMap<Pair<String, Integer>, Long> mLastAlarmDeliveredForPackage = new ArrayMap<>();
 
@@ -522,6 +528,10 @@
             return newStart;
         }
 
+        boolean remove(Alarm alarm) {
+            return remove(a -> (a == alarm));
+        }
+
         boolean remove(Predicate<Alarm> predicate) {
             boolean didRemove = false;
             long newStart = 0;  // recalculate endpoints as we go
@@ -701,9 +711,6 @@
         super(context);
         mConstants = new Constants(mHandler);
 
-        mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
-        mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
-
         publishLocalService(AlarmManagerInternal.class, new LocalService());
     }
 
@@ -741,6 +748,23 @@
         return (index == 0);
     }
 
+    private void insertAndBatchAlarmLocked(Alarm alarm) {
+        final int whichBatch = ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) ? -1
+                : attemptCoalesceLocked(alarm.whenElapsed, alarm.maxWhenElapsed);
+
+        if (whichBatch < 0) {
+            addBatchLocked(mAlarmBatches, new Batch(alarm));
+        } else {
+            final Batch batch = mAlarmBatches.get(whichBatch);
+            if (batch.add(alarm)) {
+                // The start time of this batch advanced, so batch ordering may
+                // have just been broken.  Move it to where it now belongs.
+                mAlarmBatches.remove(whichBatch);
+                addBatchLocked(mAlarmBatches, batch);
+            }
+        }
+    }
+
     // Return the index of the matching batch, or -1 if none found.
     int attemptCoalesceLocked(long whenElapsed, long maxWhen) {
         final int N = mAlarmBatches.size();
@@ -794,7 +818,7 @@
     }
 
     void rebatchAllAlarmsLocked(boolean doValidate) {
-        long start = mStatLogger.getTime();
+        final long start = mStatLogger.getTime();
         final int oldCount =
                 getAlarmCount(mAlarmBatches) + ArrayUtils.size(mPendingWhileIdleAlarms);
         final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches)
@@ -837,6 +861,44 @@
         mStatLogger.logDurationStat(Stats.REBATCH_ALL_ALARMS, start);
     }
 
+    /**
+     * Re-orders the alarm batches based on newly evaluated send times based on the current
+     * app-standby buckets
+     * @param targetPackages [Package, User] pairs for which alarms need to be re-evaluated,
+     *                       null indicates all
+     * @return True if there was any reordering done to the current list.
+     */
+    boolean reorderAlarmsBasedOnStandbyBuckets(ArraySet<Pair<String, Integer>> targetPackages) {
+        final long start = mStatLogger.getTime();
+        final ArrayList<Alarm> rescheduledAlarms = new ArrayList<>();
+
+        for (int batchIndex = mAlarmBatches.size() - 1; batchIndex >= 0; batchIndex--) {
+            final Batch batch = mAlarmBatches.get(batchIndex);
+            for (int alarmIndex = batch.size() - 1; alarmIndex >= 0; alarmIndex--) {
+                final Alarm alarm = batch.get(alarmIndex);
+                final Pair<String, Integer> packageUser =
+                        Pair.create(alarm.sourcePackage, UserHandle.getUserId(alarm.creatorUid));
+                if (targetPackages != null && !targetPackages.contains(packageUser)) {
+                    continue;
+                }
+                if (adjustDeliveryTimeBasedOnStandbyBucketLocked(alarm)) {
+                    batch.remove(alarm);
+                    rescheduledAlarms.add(alarm);
+                }
+            }
+            if (batch.size() == 0) {
+                mAlarmBatches.remove(batchIndex);
+            }
+        }
+        for (int i = 0; i < rescheduledAlarms.size(); i++) {
+            final Alarm a = rescheduledAlarms.get(i);
+            insertAndBatchAlarmLocked(a);
+        }
+
+        mStatLogger.logDurationStat(Stats.REORDER_ALARMS_FOR_STANDBY, start);
+        return rescheduledAlarms.size() > 0;
+    }
+
     void reAddAlarmLocked(Alarm a, long nowElapsed, boolean doValidate) {
         a.when = a.origWhen;
         long whenElapsed = convertToElapsed(a.when, a.type);
@@ -950,7 +1012,7 @@
             // Recurring alarms may have passed several alarm intervals while the
             // alarm was kept pending. Send the appropriate trigger count.
             if (alarm.repeatInterval > 0) {
-                alarm.count += (nowELAPSED - alarm.requestedWhenElapsed) / alarm.repeatInterval;
+                alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;
                 // Also schedule its next recurrence
                 final long delta = alarm.count * alarm.repeatInterval;
                 final long nextElapsed = alarm.whenElapsed + delta;
@@ -1268,13 +1330,15 @@
     @Override
     public void onBootPhase(int phase) {
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
-            mForceAppStandbyTracker.start();
             mConstants.start(getContext().getContentResolver());
             mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
             mLocalDeviceIdleController
                     = LocalServices.getService(DeviceIdleController.LocalService.class);
             mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
             mUsageStatsManagerInternal.addAppIdleStateChangeListener(new AppStandbyTracker());
+
+            mAppStateTracker = LocalServices.getService(AppStateTracker.class);
+            mAppStateTracker.addListener(mForceAppStandbyListener);
         }
     }
 
@@ -1442,18 +1506,27 @@
         else return mConstants.APP_STANDBY_MIN_DELAYS[0];
     }
 
-    private void adjustDeliveryTimeBasedOnStandbyBucketLocked(Alarm alarm) {
-        if (alarm.alarmClock != null || UserHandle.isCore(alarm.creatorUid)) {
-            return;
+    /**
+     * Adjusts the alarm delivery time based on the current app standby bucket.
+     * @param alarm The alarm to adjust
+     * @return true if the alarm delivery time was updated.
+     */
+    private boolean adjustDeliveryTimeBasedOnStandbyBucketLocked(Alarm alarm) {
+        if (isExemptFromAppStandby(alarm)) {
+            return false;
         }
         if (mAppStandbyParole) {
-            if (alarm.whenElapsed > alarm.requestedWhenElapsed) {
-                // We did throttle this alarm earlier, restore original requirements
-                alarm.whenElapsed = alarm.requestedWhenElapsed;
-                alarm.maxWhenElapsed = alarm.requestedMaxWhenElapsed;
+            if (alarm.whenElapsed > alarm.expectedWhenElapsed) {
+                // We did defer this alarm earlier, restore original requirements
+                alarm.whenElapsed = alarm.expectedWhenElapsed;
+                alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
+                return true;
             }
-            return;
+            return false;
         }
+        final long oldWhenElapsed = alarm.whenElapsed;
+        final long oldMaxWhenElapsed = alarm.maxWhenElapsed;
+
         final String sourcePackage = alarm.sourcePackage;
         final int sourceUserId = UserHandle.getUserId(alarm.creatorUid);
         final int standbyBucket = mUsageStatsManagerInternal.getAppStandbyBucket(
@@ -1463,10 +1536,16 @@
         final long lastElapsed = mLastAlarmDeliveredForPackage.getOrDefault(packageUser, 0L);
         if (lastElapsed > 0) {
             final long minElapsed = lastElapsed + getMinDelayForBucketLocked(standbyBucket);
-            if (alarm.requestedWhenElapsed < minElapsed) {
+            if (alarm.expectedWhenElapsed < minElapsed) {
                 alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
+            } else {
+                // app is now eligible to run alarms at the originally requested window.
+                // Restore original requirements in case they were changed earlier.
+                alarm.whenElapsed = alarm.expectedWhenElapsed;
+                alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
             }
         }
+        return (oldWhenElapsed != alarm.whenElapsed || oldMaxWhenElapsed != alarm.maxWhenElapsed);
     }
 
     private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) {
@@ -1521,21 +1600,7 @@
             }
         }
         adjustDeliveryTimeBasedOnStandbyBucketLocked(a);
-
-        int whichBatch = ((a.flags&AlarmManager.FLAG_STANDALONE) != 0)
-                ? -1 : attemptCoalesceLocked(a.whenElapsed, a.maxWhenElapsed);
-        if (whichBatch < 0) {
-            Batch batch = new Batch(a);
-            addBatchLocked(mAlarmBatches, batch);
-        } else {
-            Batch batch = mAlarmBatches.get(whichBatch);
-            if (batch.add(a)) {
-                // The start time of this batch advanced, so batch ordering may
-                // have just been broken.  Move it to where it now belongs.
-                mAlarmBatches.remove(whichBatch);
-                addBatchLocked(mAlarmBatches, batch);
-            }
-        }
+        insertAndBatchAlarmLocked(a);
 
         if (a.alarmClock != null) {
             mNextAlarmClockMayChange = true;
@@ -1661,8 +1726,9 @@
             // This means we will allow these alarms to go off as normal even while idle, with no
             // timing restrictions.
             } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
-                    || callingUid == mSystemUiUid
-                    || mForceAppStandbyTracker.isUidPowerSaveWhitelisted(callingUid))) {
+                    || UserHandle.isSameApp(callingUid, mSystemUiUid)
+                    || ((mAppStateTracker != null)
+                        && mAppStateTracker.isUidPowerSaveWhitelisted(callingUid)))) {
                 flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
                 flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
             }
@@ -1745,8 +1811,10 @@
             mConstants.dump(pw);
             pw.println();
 
-            mForceAppStandbyTracker.dump(pw, "  ");
-            pw.println();
+            if (mAppStateTracker != null) {
+                mAppStateTracker.dump(pw, "  ");
+                pw.println();
+            }
 
             pw.println("  App Standby Parole: " + mAppStandbyParole);
             pw.println();
@@ -1773,27 +1841,32 @@
                 pw.print("  Time since non-interactive: ");
                 TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw);
                 pw.println();
-                pw.print("  Max wakeup delay: ");
-                TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw);
-                pw.println();
-                pw.print("  Time since last dispatch: ");
-                TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
-                pw.println();
-                pw.print("  Next non-wakeup delivery time: ");
-                TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
-                pw.println();
             }
+            pw.print("  Max wakeup delay: ");
+            TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw);
+            pw.println();
+            pw.print("  Time since last dispatch: ");
+            TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
+            pw.println();
+            pw.print("  Next non-wakeup delivery time: ");
+            TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
+            pw.println();
 
             long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
             long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
             pw.print("  Next non-wakeup alarm: ");
                     TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
+                    pw.print(" = "); pw.print(mNextNonWakeup);
                     pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
-            pw.print("  Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
+            pw.print("  Next wakeup alarm: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
+                    pw.print(" = "); pw.print(mNextWakeup);
                     pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
+            pw.print("    set at "); TimeUtils.formatDuration(mLastWakeupSet, nowELAPSED, pw);
+                    pw.println();
             pw.print("  Last wakeup: "); TimeUtils.formatDuration(mLastWakeup, nowELAPSED, pw);
-            pw.print(" set at "); TimeUtils.formatDuration(mLastWakeupSet, nowELAPSED, pw);
-            pw.println();
+                    pw.print(" = "); pw.println(mLastWakeup);
+            pw.print("  Last trigger: "); TimeUtils.formatDuration(mLastTrigger, nowELAPSED, pw);
+                    pw.print(" = "); pw.println(mLastTrigger);
             pw.print("  Num time change events: "); pw.println(mNumTimeChanged);
 
             pw.println();
@@ -2094,8 +2167,10 @@
 
             mConstants.dumpProto(proto, AlarmManagerServiceProto.SETTINGS);
 
-            mForceAppStandbyTracker.dumpProto(proto,
-                    AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER);
+            if (mAppStateTracker != null) {
+                mAppStateTracker.dumpProto(proto,
+                        AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER);
+            }
 
             proto.write(AlarmManagerServiceProto.IS_INTERACTIVE, mInteractive);
             if (!mInteractive) {
@@ -2821,7 +2896,14 @@
                 alarmNanoseconds = (when % 1000) * 1000 * 1000;
             }
 
-            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
+            final int result = set(mNativeData, type, alarmSeconds, alarmNanoseconds);
+            if (result != 0) {
+                final long nowElapsed = SystemClock.elapsedRealtime();
+                Slog.wtf(TAG, "Unable to set kernel alarm, now=" + nowElapsed
+                        + " type=" + type + " when=" + when
+                        + " @ (" + alarmSeconds + "," + alarmNanoseconds
+                        + "), ret = " + result + " = " + Os.strerror(result));
+            }
         } else {
             Message msg = Message.obtain();
             msg.what = ALARM_EVENT;
@@ -2875,20 +2957,21 @@
         }
         final String sourcePackage = alarm.sourcePackage;
         final int sourceUid = alarm.creatorUid;
-        return mForceAppStandbyTracker.areAlarmsRestricted(sourceUid, sourcePackage,
-                allowWhileIdle);
+        return (mAppStateTracker != null) &&
+                mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage, allowWhileIdle);
     }
 
     private native long init();
     private native void close(long nativeData);
-    private native void set(long nativeData, int type, long seconds, long nanoseconds);
+    private native int set(long nativeData, int type, long seconds, long nanoseconds);
     private native int waitForAlarm(long nativeData);
     private native int setKernelTime(long nativeData, long millis);
     private native int setKernelTimezone(long nativeData, int minuteswest);
 
     private long getWhileIdleMinIntervalLocked(int uid) {
         final boolean dozing = mPendingIdleUntil != null;
-        final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled();
+        final boolean ebs = (mAppStateTracker != null)
+                && mAppStateTracker.isForceAllAppsStandbyEnabled();
         if (!dozing && !ebs) {
             return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
         }
@@ -2933,10 +3016,11 @@
                         // Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE
                         // alarm went off for this app.  Reschedule the alarm to be in the
                         // correct time period.
-                        alarm.whenElapsed = minTime;
+                        alarm.expectedWhenElapsed = alarm.whenElapsed = minTime;
                         if (alarm.maxWhenElapsed < minTime) {
                             alarm.maxWhenElapsed = minTime;
                         }
+                        alarm.expectedMaxWhenElapsed = alarm.maxWhenElapsed;
                         if (RECORD_DEVICE_IDLE_ALARMS) {
                             IdleDispatchEntry ent = new IdleDispatchEntry();
                             ent.uid = alarm.uid;
@@ -2986,7 +3070,7 @@
                 if (alarm.repeatInterval > 0) {
                     // this adjustment will be zero if we're late by
                     // less than one full repeat interval
-                    alarm.count += (nowELAPSED - alarm.requestedWhenElapsed) / alarm.repeatInterval;
+                    alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;
 
                     // Also schedule its next recurrence
                     final long delta = alarm.count * alarm.repeatInterval;
@@ -3061,8 +3145,9 @@
         public long windowLength;
         public long whenElapsed;    // 'when' in the elapsed time base
         public long maxWhenElapsed; // also in the elapsed time base
-        public final long requestedWhenElapsed; // original expiry time requested by the app
-        public final long requestedMaxWhenElapsed;
+        // Expected alarm expiry time before app standby deferring is applied.
+        public long expectedWhenElapsed;
+        public long expectedMaxWhenElapsed;
         public long repeatInterval;
         public PriorityClass priorityClass;
 
@@ -3076,10 +3161,10 @@
                     || _type == AlarmManager.RTC_WAKEUP;
             when = _when;
             whenElapsed = _whenElapsed;
-            requestedWhenElapsed = _whenElapsed;
+            expectedWhenElapsed = _whenElapsed;
             windowLength = _windowLength;
             maxWhenElapsed = _maxWhen;
-            requestedMaxWhenElapsed = _maxWhen;
+            expectedMaxWhenElapsed = _maxWhen;
             repeatInterval = _interval;
             operation = _op;
             listener = _rec;
@@ -3138,8 +3223,10 @@
             final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
             pw.print(prefix); pw.print("tag="); pw.println(statsTag);
             pw.print(prefix); pw.print("type="); pw.print(type);
-                    pw.print(" requestedWhenELapsed="); TimeUtils.formatDuration(
-                            requestedWhenElapsed, nowELAPSED, pw);
+                    pw.print(" expectedWhenElapsed="); TimeUtils.formatDuration(
+                    expectedWhenElapsed, nowELAPSED, pw);
+                    pw.print(" expectedMaxWhenElapsed="); TimeUtils.formatDuration(
+                    expectedMaxWhenElapsed, nowELAPSED, pw);
                     pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
                             nowELAPSED, pw);
                     pw.print(" when=");
@@ -3277,6 +3364,11 @@
         }
     }
 
+    private boolean isExemptFromAppStandby(Alarm a) {
+        return a.alarmClock != null || UserHandle.isCore(a.creatorUid)
+                || (a.flags & FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED) != 0;
+    }
+
     private class AlarmThread extends Thread
     {
         public AlarmThread()
@@ -3291,12 +3383,14 @@
             while (true)
             {
                 int result = waitForAlarm(mNativeData);
-                mLastWakeup = SystemClock.elapsedRealtime();
-
-                triggerList.clear();
 
                 final long nowRTC = System.currentTimeMillis();
                 final long nowELAPSED = SystemClock.elapsedRealtime();
+                synchronized (mLock) {
+                    mLastWakeup = nowELAPSED;
+                }
+
+                triggerList.clear();
 
                 if ((result & TIME_CHANGED_MASK) != 0) {
                     // The kernel can give us spurious time change notifications due to
@@ -3362,6 +3456,7 @@
                             }
                         }
 
+                        mLastTrigger = nowELAPSED;
                         boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
                         if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
                             // if there are no wakeup alarms and the screen is off, we can
@@ -3391,28 +3486,19 @@
                                 }
                                 mPendingNonWakeupAlarms.clear();
                             }
-                            boolean needRebatch = false;
-                            final HashSet<String> triggerPackages = new HashSet<>();
-                            for (int i = triggerList.size() - 1; i >= 0; i--) {
-                                triggerPackages.add(triggerList.get(i).sourcePackage);
-                            }
-                            outer:
-                            for (int i = 0; i < mAlarmBatches.size(); i++) {
-                                final Batch batch = mAlarmBatches.get(i);
-                                for (int j = 0; j < batch.size(); j++) {
-                                    if (triggerPackages.contains(batch.get(j))) {
-                                        needRebatch = true;
-                                        break outer;
-                                    }
+                            final ArraySet<Pair<String, Integer>> triggerPackages =
+                                    new ArraySet<>();
+                            for (int i = 0; i < triggerList.size(); i++) {
+                                final Alarm a = triggerList.get(i);
+                                if (!isExemptFromAppStandby(a)) {
+                                    triggerPackages.add(Pair.create(
+                                            a.sourcePackage, UserHandle.getUserId(a.creatorUid)));
                                 }
                             }
-                            if (needRebatch) {
-                                rebatchAllAlarmsLocked(false);
-                            } else {
-                                rescheduleKernelAlarmsLocked();
-                                updateNextAlarmClockLocked();
-                            }
                             deliverAlarmsLocked(triggerList, nowELAPSED);
+                            reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
+                            rescheduleKernelAlarmsLocked();
+                            updateNextAlarmClockLocked();
                         }
                     }
 
@@ -3470,10 +3556,15 @@
         public static final int REPORT_ALARMS_ACTIVE = 4;
         public static final int APP_STANDBY_BUCKET_CHANGED = 5;
         public static final int APP_STANDBY_PAROLE_CHANGED = 6;
+        public static final int REMOVE_FOR_STOPPED = 7;
 
         public AlarmHandler() {
         }
 
+        public void postRemoveForStopped(int uid) {
+            obtainMessage(REMOVE_FOR_STOPPED, uid, 0).sendToTarget();
+        }
+
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case ALARM_EVENT: {
@@ -3518,13 +3609,27 @@
                 case APP_STANDBY_PAROLE_CHANGED:
                     synchronized (mLock) {
                         mAppStandbyParole = (Boolean) msg.obj;
-                        rebatchAllAlarmsLocked(false);
+                        if (reorderAlarmsBasedOnStandbyBuckets(null)) {
+                            rescheduleKernelAlarmsLocked();
+                            updateNextAlarmClockLocked();
+                        }
                     }
                     break;
 
                 case APP_STANDBY_BUCKET_CHANGED:
                     synchronized (mLock) {
-                        rebatchAllAlarmsLocked(false);
+                        final ArraySet<Pair<String, Integer>> filterPackages = new ArraySet<>();
+                        filterPackages.add(Pair.create((String) msg.obj, msg.arg1));
+                        if (reorderAlarmsBasedOnStandbyBuckets(filterPackages)) {
+                            rescheduleKernelAlarmsLocked();
+                            updateNextAlarmClockLocked();
+                        }
+                    }
+                    break;
+
+                case REMOVE_FOR_STOPPED:
+                    synchronized (mLock) {
+                        removeForStoppedLocked(msg.arg1);
                     }
                     break;
 
@@ -3717,10 +3822,8 @@
         }
 
         @Override public void onUidGone(int uid, boolean disabled) {
-            synchronized (mLock) {
-                if (disabled) {
-                    removeForStoppedLocked(uid);
-                }
+            if (disabled) {
+                mHandler.postRemoveForStopped(uid);
             }
         }
 
@@ -3728,10 +3831,8 @@
         }
 
         @Override public void onUidIdle(int uid, boolean disabled) {
-            synchronized (mLock) {
-                if (disabled) {
-                    removeForStoppedLocked(uid);
-                }
+            if (disabled) {
+                mHandler.postRemoveForStopped(uid);
             }
         }
 
@@ -3751,7 +3852,8 @@
                         bucket);
             }
             mHandler.removeMessages(AlarmHandler.APP_STANDBY_BUCKET_CHANGED);
-            mHandler.sendEmptyMessage(AlarmHandler.APP_STANDBY_BUCKET_CHANGED);
+            mHandler.obtainMessage(AlarmHandler.APP_STANDBY_BUCKET_CHANGED, userId, -1, packageName)
+                    .sendToTarget();
         }
 
         @Override
@@ -3982,6 +4084,7 @@
         /**
          * Deliver an alarm and set up the post-delivery handling appropriately
          */
+        @GuardedBy("mLock")
         public void deliverLocked(Alarm alarm, long nowELAPSED, boolean allowWhileIdle) {
             if (alarm.operation != null) {
                 // PendingIntent alarm
@@ -4059,7 +4162,8 @@
             if (allowWhileIdle) {
                 // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
                 mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED);
-                if (mForceAppStandbyTracker.isUidInForeground(alarm.creatorUid)) {
+                if ((mAppStateTracker == null)
+                        || mAppStateTracker.isUidInForeground(alarm.creatorUid)) {
                     mUseAllowWhileIdleShortTime.put(alarm.creatorUid, true);
                 } else {
                     mUseAllowWhileIdleShortTime.put(alarm.creatorUid, false);
@@ -4074,7 +4178,7 @@
                     mAllowWhileIdleDispatches.add(ent);
                 }
             }
-            if (!UserHandle.isCore(alarm.creatorUid)) {
+            if (!isExemptFromAppStandby(alarm)) {
                 final Pair<String, Integer> packageUser = Pair.create(alarm.sourcePackage,
                         UserHandle.getUserId(alarm.creatorUid));
                 mLastAlarmDeliveredForPackage.put(packageUser, nowELAPSED);
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/AppStateTracker.java
similarity index 91%
rename from services/core/java/com/android/server/ForceAppStandbyTracker.java
rename to services/core/java/com/android/server/AppStateTracker.java
index 339101f..9b29b32 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -54,7 +54,6 @@
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
-import com.android.server.DeviceIdleController.LocalService;
 import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
 import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
 
@@ -73,14 +72,14 @@
  * TODO: Make it a LocalService.
  *
  * Test:
-  atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+  atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
  */
-public class ForceAppStandbyTracker {
+public class AppStateTracker {
     private static final String TAG = "ForceAppStandbyTracker";
     private static final boolean DEBUG = true;
 
-    @GuardedBy("ForceAppStandbyTracker.class")
-    private static ForceAppStandbyTracker sInstance;
+    @GuardedBy("AppStateTracker.class")
+    private static AppStateTracker sInstance;
 
     private final Object mLock = new Object();
     private final Context mContext;
@@ -89,6 +88,7 @@
     static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
 
     IActivityManager mIActivityManager;
+    ActivityManagerInternal mActivityManagerInternal;
     AppOpsManager mAppOpsManager;
     IAppOpsService mAppOpsService;
     PowerManagerInternal mPowerManagerInternal;
@@ -172,6 +172,9 @@
         int EXEMPT_CHANGED = 6;
         int FORCE_ALL_CHANGED = 7;
         int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
+
+        int IS_UID_ACTIVE_CACHED = 9;
+        int IS_UID_ACTIVE_RAW = 10;
     }
 
     private final StatLogger mStatLogger = new StatLogger(new String[] {
@@ -184,6 +187,9 @@
             "EXEMPT_CHANGED",
             "FORCE_ALL_CHANGED",
             "FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED",
+
+            "IS_UID_ACTIVE_CACHED",
+            "IS_UID_ACTIVE_RAW",
     });
 
     @VisibleForTesting
@@ -249,7 +255,7 @@
         /**
          * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package.
          */
-        private void onRunAnyAppOpsChanged(ForceAppStandbyTracker sender,
+        private void onRunAnyAppOpsChanged(AppStateTracker sender,
                 int uid, @NonNull String packageName) {
             updateJobsForUidPackage(uid, packageName);
 
@@ -264,14 +270,14 @@
         /**
          * This is called when the foreground state changed for a UID.
          */
-        private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) {
+        private void onUidForegroundStateChanged(AppStateTracker sender, int uid) {
             onUidForeground(uid, sender.isUidInForeground(uid));
         }
 
         /**
          * This is called when the active/idle state changed for a UID.
          */
-        private void onUidActiveStateChanged(ForceAppStandbyTracker sender, int uid) {
+        private void onUidActiveStateChanged(AppStateTracker sender, int uid) {
             updateJobsForUid(uid);
 
             if (sender.isUidActive(uid)) {
@@ -282,7 +288,7 @@
         /**
          * This is called when an app-id(s) is removed from the power save whitelist.
          */
-        private void onPowerSaveUnwhitelisted(ForceAppStandbyTracker sender) {
+        private void onPowerSaveUnwhitelisted(AppStateTracker sender) {
             updateAllJobs();
             unblockAllUnrestrictedAlarms();
         }
@@ -291,14 +297,14 @@
          * This is called when the power save whitelist changes, excluding the
          * {@link #onPowerSaveUnwhitelisted} case.
          */
-        private void onPowerSaveWhitelistedChanged(ForceAppStandbyTracker sender) {
+        private void onPowerSaveWhitelistedChanged(AppStateTracker sender) {
             updateAllJobs();
         }
 
         /**
          * This is called when the temp whitelist changes.
          */
-        private void onTempPowerSaveWhitelistChanged(ForceAppStandbyTracker sender) {
+        private void onTempPowerSaveWhitelistChanged(AppStateTracker sender) {
 
             // TODO This case happens rather frequently; consider optimizing and update jobs
             // only for affected app-ids.
@@ -311,7 +317,7 @@
         /**
          * This is called when the EXEMPT bucket is updated.
          */
-        private void onExemptChanged(ForceAppStandbyTracker sender) {
+        private void onExemptChanged(AppStateTracker sender) {
             // This doesn't happen very often, so just re-evaluate all jobs / alarms.
             updateAllJobs();
             unblockAllUnrestrictedAlarms();
@@ -320,7 +326,7 @@
         /**
          * This is called when the global "force all apps standby" flag changes.
          */
-        private void onForceAllAppsStandbyChanged(ForceAppStandbyTracker sender) {
+        private void onForceAllAppsStandbyChanged(AppStateTracker sender) {
             updateAllJobs();
 
             if (!sender.isForceAllAppsStandbyEnabled()) {
@@ -377,30 +383,15 @@
         }
     }
 
-    @VisibleForTesting
-    ForceAppStandbyTracker(Context context, Looper looper) {
+    public AppStateTracker(Context context, Looper looper) {
         mContext = context;
         mHandler = new MyHandler(looper);
     }
 
-    private ForceAppStandbyTracker(Context context) {
-        this(context, FgThread.get().getLooper());
-    }
-
-    /**
-     * Get the singleton instance.
-     */
-    public static synchronized ForceAppStandbyTracker getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new ForceAppStandbyTracker(context);
-        }
-        return sInstance;
-    }
-
     /**
      * Call it when the system is ready.
      */
-    public void start() {
+    public void onSystemServicesReady() {
         synchronized (mLock) {
             if (mStarted) {
                 return;
@@ -408,6 +399,7 @@
             mStarted = true;
 
             mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
+            mActivityManagerInternal = Preconditions.checkNotNull(injectActivityManagerInternal());
             mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
             mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
             mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
@@ -475,6 +467,11 @@
     }
 
     @VisibleForTesting
+    ActivityManagerInternal injectActivityManagerInternal() {
+        return LocalServices.getService(ActivityManagerInternal.class);
+    }
+
+    @VisibleForTesting
     PowerManagerInternal injectPowerManagerInternal() {
         return LocalServices.getService(PowerManagerInternal.class);
     }
@@ -497,6 +494,7 @@
     /**
      * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
      */
+    @GuardedBy("mLock")
     private void refreshForcedAppStandbyUidPackagesLocked() {
         mRunAnyRestrictedPackages.clear();
         final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(
@@ -536,6 +534,7 @@
     /**
      * Update {@link #mForceAllAppsStandby} and notifies the listeners.
      */
+    @GuardedBy("mLock")
     private void toggleForceAllAppsStandbyLocked(boolean enable) {
         if (enable == mForceAllAppsStandby) {
             return;
@@ -545,6 +544,7 @@
         mHandler.notifyForceAllAppsStandbyChanged();
     }
 
+    @GuardedBy("mLock")
     private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
         final int size = mRunAnyRestrictedPackages.size();
         if (size > 8) {
@@ -563,6 +563,7 @@
     /**
      * @return whether a uid package-name pair is in mRunAnyRestrictedPackages.
      */
+    @GuardedBy("mLock")
     boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) {
         return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
     }
@@ -570,6 +571,7 @@
     /**
      * Add to / remove from {@link #mRunAnyRestrictedPackages}.
      */
+    @GuardedBy("mLock")
     boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName,
             boolean restricted) {
         final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
@@ -614,48 +616,22 @@
     private final class UidObserver extends IUidObserver.Stub {
         @Override
         public void onUidStateChanged(int uid, int procState, long procStateSeq) {
-            synchronized (mLock) {
-                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-                    if (removeUidFromArray(mForegroundUids, uid, false)) {
-                        mHandler.notifyUidForegroundStateChanged(uid);
-                    }
-                } else {
-                    if (addUidToArray(mForegroundUids, uid)) {
-                        mHandler.notifyUidForegroundStateChanged(uid);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void onUidGone(int uid, boolean disabled) {
-            removeUid(uid, true);
+            mHandler.onUidStateChanged(uid, procState);
         }
 
         @Override
         public void onUidActive(int uid) {
-            synchronized (mLock) {
-                if (addUidToArray(mActiveUids, uid)) {
-                    mHandler.notifyUidActiveStateChanged(uid);
-                }
-            }
+            mHandler.onUidActive(uid);
+        }
+
+        @Override
+        public void onUidGone(int uid, boolean disabled) {
+            mHandler.onUidGone(uid, disabled);
         }
 
         @Override
         public void onUidIdle(int uid, boolean disabled) {
-            // Just to avoid excessive memcpy, don't remove from the array in this case.
-            removeUid(uid, false);
-        }
-
-        private void removeUid(int uid, boolean remove) {
-            synchronized (mLock) {
-                if (removeUidFromArray(mActiveUids, uid, remove)) {
-                    mHandler.notifyUidActiveStateChanged(uid);
-                }
-                if (removeUidFromArray(mForegroundUids, uid, remove)) {
-                    mHandler.notifyUidForegroundStateChanged(uid);
-                }
-            }
+            mHandler.onUidIdle(uid, disabled);
         }
 
         @Override
@@ -740,6 +716,11 @@
         private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;
         private static final int MSG_EXEMPT_CHANGED = 10;
 
+        private static final int MSG_ON_UID_STATE_CHANGED = 11;
+        private static final int MSG_ON_UID_ACTIVE = 12;
+        private static final int MSG_ON_UID_GONE = 13;
+        private static final int MSG_ON_UID_IDLE = 14;
+
         public MyHandler(Looper looper) {
             super(looper);
         }
@@ -790,6 +771,22 @@
             obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
         }
 
+        public void onUidStateChanged(int uid, int procState) {
+            obtainMessage(MSG_ON_UID_STATE_CHANGED, uid, procState).sendToTarget();
+        }
+
+        public void onUidActive(int uid) {
+            obtainMessage(MSG_ON_UID_ACTIVE, uid, 0).sendToTarget();
+        }
+
+        public void onUidGone(int uid, boolean disabled) {
+            obtainMessage(MSG_ON_UID_GONE, uid, disabled ? 1 : 0).sendToTarget();
+        }
+
+        public void onUidIdle(int uid, boolean disabled) {
+            obtainMessage(MSG_ON_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget();
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -804,7 +801,7 @@
                     return;
                 }
             }
-            final ForceAppStandbyTracker sender = ForceAppStandbyTracker.this;
+            final AppStateTracker sender = AppStateTracker.this;
 
             long start = mStatLogger.getTime();
             switch (msg.what) {
@@ -883,6 +880,61 @@
                 case MSG_USER_REMOVED:
                     handleUserRemoved(msg.arg1);
                     return;
+
+                case MSG_ON_UID_STATE_CHANGED:
+                    handleUidStateChanged(msg.arg1, msg.arg2);
+                    return;
+                case MSG_ON_UID_ACTIVE:
+                    handleUidActive(msg.arg1);
+                    return;
+                case MSG_ON_UID_GONE:
+                    handleUidGone(msg.arg1, msg.arg1 != 0);
+                    return;
+                case MSG_ON_UID_IDLE:
+                    handleUidIdle(msg.arg1, msg.arg1 != 0);
+                    return;
+            }
+        }
+
+        public void handleUidStateChanged(int uid, int procState) {
+            synchronized (mLock) {
+                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+                    if (removeUidFromArray(mForegroundUids, uid, false)) {
+                        mHandler.notifyUidForegroundStateChanged(uid);
+                    }
+                } else {
+                    if (addUidToArray(mForegroundUids, uid)) {
+                        mHandler.notifyUidForegroundStateChanged(uid);
+                    }
+                }
+            }
+        }
+
+        public void handleUidActive(int uid) {
+            synchronized (mLock) {
+                if (addUidToArray(mActiveUids, uid)) {
+                    mHandler.notifyUidActiveStateChanged(uid);
+                }
+            }
+        }
+
+        public void handleUidGone(int uid, boolean disabled) {
+            removeUid(uid, true);
+        }
+
+        public void handleUidIdle(int uid, boolean disabled) {
+            // Just to avoid excessive memcpy, don't remove from the array in this case.
+            removeUid(uid, false);
+        }
+
+        private void removeUid(int uid, boolean remove) {
+            synchronized (mLock) {
+                if (removeUidFromArray(mActiveUids, uid, remove)) {
+                    mHandler.notifyUidActiveStateChanged(uid);
+                }
+                if (removeUidFromArray(mForegroundUids, uid, remove)) {
+                    mHandler.notifyUidForegroundStateChanged(uid);
+                }
             }
         }
     }
@@ -1039,11 +1091,11 @@
     }
 
     /**
-     * @return whether a UID is in active or not.
+     * @return whether a UID is in active or not *based on cached information.*
      *
      * Note this information is based on the UID proc state callback, meaning it's updated
      * asynchronously and may subtly be stale. If the fresh data is needed, use
-     * {@link ActivityManagerInternal#getUidProcessState} instead.
+     * {@link #isUidActiveSynced} instead.
      */
     public boolean isUidActive(int uid) {
         if (UserHandle.isCore(uid)) {
@@ -1055,6 +1107,23 @@
     }
 
     /**
+     * @return whether a UID is in active or not *right now.*
+     *
+     * This gives the fresh information, but may access the activity manager so is slower.
+     */
+    public boolean isUidActiveSynced(int uid) {
+        if (isUidActive(uid)) { // Use the cached one first.
+            return true;
+        }
+        final long start = mStatLogger.getTime();
+
+        final boolean ret = mActivityManagerInternal.isUidActive(uid);
+        mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start);
+
+        return ret;
+    }
+
+    /**
      * @return whether a UID is in the foreground or not.
      *
      * Note this information is based on the UID proc state callback, meaning it's updated
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 2077790..55ad8cc 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -948,8 +948,11 @@
         return true;
     }
 
-    private boolean startConsentUiIfNeeded(String packageName, int callingUid, String intentAction)
-            throws RemoteException {
+    private boolean startConsentUiIfNeeded(String packageName,
+            int callingUid, String intentAction) throws RemoteException {
+        if (checkBluetoothPermissionWhenPermissionReviewRequired()) {
+            return false;
+        }
         try {
             // Validate the package only if we are going to use it
             ApplicationInfo applicationInfo = mContext.getPackageManager()
@@ -957,7 +960,8 @@
                             PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                             UserHandle.getUserId(callingUid));
             if (applicationInfo.uid != callingUid) {
-                throw new SecurityException("Package " + callingUid + " not in uid " + callingUid);
+                throw new SecurityException("Package " + packageName
+                        + " not in uid " + callingUid);
             }
 
             Intent intent = new Intent(intentAction);
@@ -977,6 +981,26 @@
         }
     }
 
+    /**
+     * Check if the caller must still pass permission check or if the caller is exempted
+     * from the consent UI via the MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED check.
+     *
+     * Commands from some callers may be exempted from triggering the consent UI when
+     * enabling bluetooth. This exemption is checked via the
+     * MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED and allows calls to skip
+     * the consent UI where it may otherwise be required.
+     *
+     * @hide
+     */
+    private boolean checkBluetoothPermissionWhenPermissionReviewRequired() {
+        if (!mPermissionReviewRequired) {
+            return false;
+        }
+        int result = mContext.checkCallingPermission(
+                android.Manifest.permission.MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED);
+        return result == PackageManager.PERMISSION_GRANTED;
+    }
+
     public void unbindAndFinish() {
         if (DBG) {
             Slog.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3bfa31a..efad7d5 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1402,7 +1402,8 @@
     public boolean isActiveNetworkMetered() {
         enforceAccessPermission();
 
-        final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork());
+        final int uid = Binder.getCallingUid();
+        final NetworkCapabilities caps = getUnfilteredActiveNetworkState(uid).networkCapabilities;
         if (caps != null) {
             return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         } else {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 44974ff..2b3c585 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -82,6 +82,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.net.NetworkPolicyManagerInternal;
@@ -128,6 +129,7 @@
     private Intent mIdleIntent;
     private Intent mLightIdleIntent;
     private AnyMotionDetector mAnyMotionDetector;
+    private final AppStateTracker mAppStateTracker;
     private boolean mLightEnabled;
     private boolean mDeepEnabled;
     private boolean mForceIdle;
@@ -1371,6 +1373,8 @@
         super(context);
         mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
         mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
+        mAppStateTracker = new AppStateTracker(context, FgThread.get().getLooper());
+        LocalServices.addService(AppStateTracker.class, mAppStateTracker);
     }
 
     boolean isAppOnWhitelistInternal(int appid) {
@@ -1501,6 +1505,8 @@
                         (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
                         mHandler, mSensorManager, this, angleThreshold);
 
+                mAppStateTracker.onSystemServicesReady();
+
                 mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
                 mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                         | Intent.FLAG_RECEIVER_FOREGROUND);
@@ -2615,7 +2621,7 @@
     }
 
     private void passWhiteListToForceAppStandbyTrackerLocked() {
-        ForceAppStandbyTracker.getInstance(getContext()).setPowerSaveWhitelistAppIds(
+        mAppStateTracker.setPowerSaveWhitelistAppIds(
                 mPowerSaveWhitelistExceptIdleAppIdArray,
                 mTempWhitelistAppIdArray);
     }
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 2f42585..bdeb231 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1166,6 +1166,7 @@
             mImePackageAppeared = false;
         }
 
+        @GuardedBy("mMethodMap")
         private boolean shouldRebuildInputMethodListLocked() {
             // This method is guaranteed to be called only by getRegisteredHandler().
 
@@ -1467,6 +1468,7 @@
         setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
     }
 
+    @GuardedBy("mMethodMap")
     private void switchUserLocked(int newUserId) {
         if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
                 + " currentUserId=" + mSettings.getCurrentUserId());
@@ -1817,6 +1819,7 @@
         return flags;
     }
 
+    @GuardedBy("mMethodMap")
     @NonNull
     InputBindResult attachNewInputLocked(
             /* @InputMethodClient.StartInputReason */ final int startInputReason, boolean initial) {
@@ -1846,6 +1849,7 @@
                 mCurId, mCurSeq, mCurUserActionNotificationSequenceNumber);
     }
 
+    @GuardedBy("mMethodMap")
     @NonNull
     InputBindResult startInputLocked(
             /* @InputMethodClient.StartInputReason */ final int startInputReason,
@@ -1889,6 +1893,7 @@
                 controlFlags, startInputReason);
     }
 
+    @GuardedBy("mMethodMap")
     @NonNull
     InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
             /* @InputConnectionInspector.missingMethods */ final int missingMethods,
@@ -2970,12 +2975,19 @@
                         break;
                 }
 
-                if (!didStart && attribute != null) {
-                    if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
-                            || (controlFlags
-                                    & InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR) != 0) {
-                        res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
-                                controlFlags, startInputReason);
+                if (!didStart) {
+                    if (attribute != null) {
+                        if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
+                                || (controlFlags
+                                & InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR) != 0) {
+                            res = startInputUncheckedLocked(cs, inputContext, missingMethods,
+                                    attribute,
+                                    controlFlags, startInputReason);
+                        } else {
+                            res = InputBindResult.NO_EDITOR;
+                        }
+                    } else {
+                        res = InputBindResult.NULL_EDITOR_INFO;
                     }
                 }
             }
@@ -3635,6 +3647,7 @@
         return false;
     }
 
+    @GuardedBy("mMethodMap")
     void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
         if (DEBUG) {
             Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index a07a982..45a4dfb9 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -1438,7 +1438,9 @@
 
         switch (config.getMode()) {
             case IpSecTransform.MODE_TRANSPORT:
+                break;
             case IpSecTransform.MODE_TUNNEL:
+                enforceNetworkStackPermission();
                 break;
             default:
                 throw new IllegalArgumentException(
@@ -1446,6 +1448,11 @@
         }
     }
 
+    private void enforceNetworkStackPermission() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK,
+                "IpSecService");
+    }
+
     private void createOrUpdateTransform(
             IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord)
             throws RemoteException {
@@ -1615,6 +1622,7 @@
     @Override
     public synchronized void applyTunnelModeTransform(
             int tunnelResourceId, int direction, int transformResourceId) throws RemoteException {
+        enforceNetworkStackPermission();
         checkDirection(direction);
 
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index f4238f2..42c836e 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -199,6 +199,7 @@
      *            bound.
      * @returns {@code true} if a valid package was found to bind to.
      */
+    @GuardedBy("mLock")
     private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
         Intent intent = new Intent(mAction);
         if (justCheckThisPackage != null) {
@@ -273,6 +274,7 @@
         return true;
     }
 
+    @GuardedBy("mLock")
     private void unbindLocked() {
         ComponentName component;
         component = mBoundComponent;
@@ -287,6 +289,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void bindToPackageLocked(ComponentName component, int version, int userId) {
         Intent intent = new Intent(mAction);
         intent.setComponent(component);
diff --git a/services/core/java/com/android/server/StatLogger.java b/services/core/java/com/android/server/StatLogger.java
index f211731..0e6f5e2 100644
--- a/services/core/java/com/android/server/StatLogger.java
+++ b/services/core/java/com/android/server/StatLogger.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.os.SystemClock;
+import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
@@ -33,6 +34,8 @@
  * @hide
  */
 public class StatLogger {
+    private static final String TAG = "StatLogger";
+
     private final Object mLock = new Object();
 
     private final int SIZE;
@@ -66,8 +69,12 @@
      */
     public void logDurationStat(int eventId, long start) {
         synchronized (mLock) {
-            mCountStats[eventId]++;
-            mDurationStats[eventId] += (getTime() - start);
+            if (eventId >= 0 && eventId < SIZE) {
+                mCountStats[eventId]++;
+                mDurationStats[eventId] += (getTime() - start);
+            } else {
+                Slog.wtf(TAG, "Invalid event ID: " + eventId);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 84b93e3..1a0068d 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -809,6 +809,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void addInternalVolumeLocked() {
         // Create a stub volume that represents internal storage
         final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
@@ -1109,6 +1110,7 @@
         }
     };
 
+    @GuardedBy("mLock")
     private void onDiskScannedLocked(DiskInfo disk) {
         int volumeCount = 0;
         for (int i = 0; i < mVolumes.size(); i++) {
@@ -1134,6 +1136,7 @@
         mCallbacks.notifyDiskScanned(disk, volumeCount);
     }
 
+    @GuardedBy("mLock")
     private void onVolumeCreatedLocked(VolumeInfo vol) {
         if (mPms.isOnlyCoreApps()) {
             Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
@@ -1209,6 +1212,7 @@
         return true;
     }
 
+    @GuardedBy("mLock")
     private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
         // Remember that we saw this volume so we're ready to accept user
         // metadata, or so we can annoy them when a private volume is ejected
@@ -1299,6 +1303,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void onMoveStatusLocked(int status) {
         if (mMoveCallback == null) {
             Slog.w(TAG, "Odd, status but no move requested");
@@ -1515,6 +1520,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void readSettingsLocked() {
         mRecords.clear();
         mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
@@ -1559,6 +1565,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void writeSettingsLocked() {
         FileOutputStream fos = null;
         try {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 6743484..6747be3 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -35,7 +35,6 @@
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
 import android.telephony.DisconnectCause;
-import android.telephony.LocationAccessPolicy;
 import android.telephony.PhoneStateListener;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
@@ -94,8 +93,7 @@
         IPhoneStateListener callback;
         IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
 
-        int callerUid;
-        int callerPid;
+        int callerUserId;
 
         int events;
 
@@ -119,7 +117,7 @@
                     + " callback=" + callback
                     + " onSubscriptionsChangedListenererCallback="
                                             + onSubscriptionsChangedListenerCallback
-                    + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
+                    + " callerUserId=" + callerUserId + " subId=" + subId + " phoneId=" + phoneId
                     + " events=" + Integer.toHexString(events)
                     + " canReadPhoneState=" + canReadPhoneState + "}";
         }
@@ -358,8 +356,6 @@
     public void addOnSubscriptionsChangedListener(String callingPackage,
             IOnSubscriptionsChangedListener callback) {
         int callerUserId = UserHandle.getCallingUserId();
-        mContext.getSystemService(AppOpsManager.class)
-                .checkPackage(Binder.getCallingUid(), callingPackage);
         if (VDBG) {
             log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
                 + " callerUserId="  + callerUserId + " callback=" + callback
@@ -403,8 +399,7 @@
 
             r.onSubscriptionsChangedListenerCallback = callback;
             r.callingPackage = callingPackage;
-            r.callerUid = Binder.getCallingUid();
-            r.callerPid = Binder.getCallingPid();
+            r.callerUserId = callerUserId;
             r.events = 0;
             r.canReadPhoneState = true; // permission has been enforced above
             if (DBG) {
@@ -475,8 +470,6 @@
     private void listen(String callingPackage, IPhoneStateListener callback, int events,
             boolean notifyNow, int subId) {
         int callerUserId = UserHandle.getCallingUserId();
-        mContext.getSystemService(AppOpsManager.class)
-                .checkPackage(Binder.getCallingUid(), callingPackage);
         if (VDBG) {
             log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
                 + " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
@@ -521,8 +514,7 @@
 
                 r.callback = callback;
                 r.callingPackage = callingPackage;
-                r.callerUid = Binder.getCallingUid();
-                r.callerPid = Binder.getCallingPid();
+                r.callerUserId = callerUserId;
                 boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK
                         | ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0;
                 r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage);
@@ -580,10 +572,8 @@
                         try {
                             if (DBG_LOC) log("listen: mCellLocation = "
                                     + mCellLocation[phoneId]);
-                            if (checkLocationAccess(r)) {
-                                r.callback.onCellLocationChanged(
-                                        new Bundle(mCellLocation[phoneId]));
-                            }
+                            r.callback.onCellLocationChanged(
+                                    new Bundle(mCellLocation[phoneId]));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -629,9 +619,7 @@
                         try {
                             if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
                                     + mCellInfo.get(phoneId));
-                            if (checkLocationAccess(r)) {
-                                r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
-                            }
+                            r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
                         } catch (RemoteException ex) {
                             remove(r.binder);
                         }
@@ -991,8 +979,7 @@
                 mCellInfo.set(phoneId, cellInfo);
                 for (Record r : mRecords) {
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
-                            idMatch(r.subId, subId, phoneId) &&
-                            checkLocationAccess(r)) {
+                            idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG_LOC) {
                                 log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
@@ -1275,8 +1262,7 @@
                 mCellLocation[phoneId] = cellLocation;
                 for (Record r : mRecords) {
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
-                            idMatch(r.subId, subId, phoneId) &&
-                            checkLocationAccess(r)) {
+                            idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG_LOC) {
                                 log("notifyCellLocation: cellLocation=" + cellLocation
@@ -1720,11 +1706,10 @@
         boolean valid = false;
         try {
             foregroundUser = ActivityManager.getCurrentUser();
-            valid = UserHandle.getUserId(r.callerUid) == foregroundUser
-                    && r.matchPhoneStateListenerEvent(events);
+            valid = r.callerUserId ==  foregroundUser && r.matchPhoneStateListenerEvent(events);
             if (DBG | DBG_LOC) {
                 log("validateEventsAndUserLocked: valid=" + valid
-                        + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
+                        + " r.callerUserId=" + r.callerUserId + " foregroundUser=" + foregroundUser
                         + " r.events=" + r.events + " events=" + events);
             }
         } finally {
@@ -1756,16 +1741,6 @@
         }
     }
 
-    private boolean checkLocationAccess(Record r) {
-        long token = Binder.clearCallingIdentity();
-        try {
-            return LocationAccessPolicy.canAccessCellLocation(mContext,
-                    r.callingPackage, r.callerUid, r.callerPid);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
     private void checkPossibleMissNotify(Record r, int phoneId) {
         int events = r.events;
 
@@ -1813,9 +1788,7 @@
                     log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
                             + mCellInfo.get(phoneId));
                 }
-                if (checkLocationAccess(r)) {
-                    r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
-                }
+                r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
             } catch (RemoteException ex) {
                 mRemoveList.add(r.binder);
             }
@@ -1863,9 +1836,7 @@
             try {
                 if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = "
                         + mCellLocation[phoneId]);
-                if (checkLocationAccess(r)) {
-                    r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
-                }
+                r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
             } catch (RemoteException ex) {
                 mRemoveList.add(r.binder);
             }
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 48b5a58..7fe5d7c 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -25,7 +25,7 @@
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.input.InputManager;
-import android.hardware.vibrator.V1_0.Constants.EffectStrength;
+import android.hardware.vibrator.V1_0.EffectStrength;
 import android.icu.text.DateFormat;
 import android.media.AudioManager;
 import android.os.PowerManager.ServiceType;
@@ -55,6 +55,7 @@
 import android.view.InputDevice;
 import android.media.AudioAttributes;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.DumpUtils;
@@ -111,6 +112,7 @@
     private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
     private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
 
+    @GuardedBy("mLock")
     private Vibration mCurrentVibration;
     private int mCurVibUid = -1;
     private boolean mLowPowerMode;
@@ -435,45 +437,45 @@
 
         // If our current vibration is longer than the new vibration and is the same amplitude,
         // then just let the current one finish.
-        if (effect instanceof VibrationEffect.OneShot
-                && mCurrentVibration != null
-                && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
-            VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
-            VibrationEffect.OneShot currentOneShot =
-                    (VibrationEffect.OneShot) mCurrentVibration.effect;
-            if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
-                    && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
+        synchronized (mLock) {
+            if (effect instanceof VibrationEffect.OneShot
+                    && mCurrentVibration != null
+                    && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
+                VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
+                VibrationEffect.OneShot currentOneShot =
+                        (VibrationEffect.OneShot) mCurrentVibration.effect;
+                if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
+                        && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Ignoring incoming vibration in favor of current vibration");
+                    }
+                    return;
+                }
+            }
+
+            // If the current vibration is repeating and the incoming one is non-repeating, then
+            // ignore the non-repeating vibration. This is so that we don't cancel vibrations that
+            // are meant to grab the attention of the user, like ringtones and alarms, in favor of
+            // one-shot vibrations that are likely quite short.
+            if (!isRepeatingVibration(effect)
+                    && mCurrentVibration != null
+                    && isRepeatingVibration(mCurrentVibration.effect)) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Ignoring incoming vibration in favor of current vibration");
+                    Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
                 }
                 return;
             }
-        }
 
-        // If the current vibration is repeating and the incoming one is non-repeating, then ignore
-        // the non-repeating vibration. This is so that we don't cancel vibrations that are meant
-        // to grab the attention of the user, like ringtones and alarms, in favor of one-shot
-        // vibrations that are likely quite short.
-        if (!isRepeatingVibration(effect)
-                && mCurrentVibration != null && isRepeatingVibration(mCurrentVibration.effect)) {
-            if (DEBUG) {
-                Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
-            }
-            return;
-        }
-
-        Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
-        linkVibration(vib);
-
-        long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
+            Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
+            linkVibration(vib);
+            long ident = Binder.clearCallingIdentity();
+            try {
                 doCancelVibrateLocked();
                 startVibrationLocked(vib);
                 addToPreviousVibrationsLocked(vib);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -516,6 +518,7 @@
         }
     };
 
+    @GuardedBy("mLock")
     private void doCancelVibrateLocked() {
         mH.removeCallbacks(mVibrationEndRunnable);
         if (mThread != null) {
@@ -538,6 +541,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void startVibrationLocked(final Vibration vib) {
         if (!isAllowedToVibrateLocked(vib)) {
             return;
@@ -568,6 +572,7 @@
         startVibrationInnerLocked(vib);
     }
 
+    @GuardedBy("mLock")
     private void startVibrationInnerLocked(Vibration vib) {
         mCurrentVibration = vib;
         if (vib.effect instanceof VibrationEffect.OneShot) {
@@ -701,6 +706,7 @@
         return mode;
     }
 
+    @GuardedBy("mLock")
     private void reportFinishVibrationLocked() {
         if (mCurrentVibration != null) {
             try {
@@ -880,6 +886,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private long doVibratorPrebakedEffectLocked(Vibration vib) {
         final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
         final boolean usingInputDeviceVibrators;
@@ -905,6 +912,7 @@
         Vibration fallbackVib =
                 new Vibration(vib.token, effect, vib.usageHint, vib.uid, vib.opPkg);
         final int intensity = getCurrentIntensityLocked(fallbackVib);
+        linkVibration(fallbackVib);
         applyVibrationIntensityScalingLocked(fallbackVib, intensity);
         startVibrationInnerLocked(fallbackVib);
         return 0;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 5215b6f..c8e0a5e 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -558,14 +558,7 @@
                 Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process");
             } else {
                 Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject);
-                for (int i=0; i<blockedCheckers.size(); i++) {
-                    Slog.w(TAG, blockedCheckers.get(i).getName() + " stack trace:");
-                    StackTraceElement[] stackTrace
-                            = blockedCheckers.get(i).getThread().getStackTrace();
-                    for (StackTraceElement element: stackTrace) {
-                        Slog.w(TAG, "    at " + element);
-                    }
-                }
+                WatchdogDiagnostics.diagnoseCheckers(blockedCheckers);
                 Slog.w(TAG, "*** GOODBYE!");
                 Process.killProcess(Process.myPid());
                 System.exit(10);
diff --git a/services/core/java/com/android/server/WatchdogDiagnostics.java b/services/core/java/com/android/server/WatchdogDiagnostics.java
new file mode 100644
index 0000000..01db2d3
--- /dev/null
+++ b/services/core/java/com/android/server/WatchdogDiagnostics.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.util.Log;
+import android.util.LogWriter;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.Watchdog.HandlerChecker;
+
+import dalvik.system.AnnotatedStackTraceElement;
+import dalvik.system.VMStack;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Class to give diagnostic messages for Watchdogs.
+ */
+class WatchdogDiagnostics {
+    private static String getBlockedOnString(Object blockedOn) {
+        return String.format("- waiting to lock <0x%08x> (a %s)",
+                System.identityHashCode(blockedOn), blockedOn.getClass().getName());
+    }
+
+    private static String getLockedString(Object heldLock) {
+        return String.format("- locked <0x%08x> (a %s)", System.identityHashCode(heldLock),
+                heldLock.getClass().getName());
+    }
+
+    /**
+     * Print the annotated stack for the given thread. If the annotated stack cannot be retrieved,
+     * returns false.
+     */
+    @VisibleForTesting
+    public static boolean printAnnotatedStack(Thread thread, PrintWriter out) {
+        AnnotatedStackTraceElement stack[] = VMStack.getAnnotatedThreadStackTrace(thread);
+        if (stack == null) {
+            return false;
+        }
+        out.println(thread.getName() + " annotated stack trace:");
+        for (AnnotatedStackTraceElement element : stack) {
+            out.println("    at " + element.getStackTraceElement());
+            if (element.getBlockedOn() != null) {
+                out.println("    " + getBlockedOnString(element.getBlockedOn()));
+            }
+            if (element.getHeldLocks() != null) {
+                for (Object held : element.getHeldLocks()) {
+                    out.println("    " + getLockedString(held));
+                }
+            }
+        }
+        return true;
+    }
+
+    public static void diagnoseCheckers(final List<HandlerChecker> blockedCheckers) {
+        PrintWriter out = new PrintWriter(new LogWriter(Log.WARN, Watchdog.TAG, Log.LOG_ID_SYSTEM),
+                true);
+        for (int i=0; i<blockedCheckers.size(); i++) {
+            Thread blockedThread = blockedCheckers.get(i).getThread();
+            if (printAnnotatedStack(blockedThread, out)) {
+                continue;
+            }
+
+            // Fall back to "regular" stack trace, if necessary.
+            Slog.w(Watchdog.TAG, blockedThread.getName() + " stack trace:");
+            StackTraceElement[] stackTrace = blockedThread.getStackTrace();
+            for (StackTraceElement element : stackTrace) {
+                Slog.w(Watchdog.TAG, "    at " + element);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2f7d4c1..14404f5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -84,6 +84,7 @@
 import android.util.EventLog;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -1094,6 +1095,8 @@
                     active.mNumActive++;
                 }
                 r.isForeground = true;
+                StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.userId, r.shortName,
+                        StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
             }
             r.postNotification();
             if (r.app != null) {
@@ -1109,6 +1112,8 @@
                     decActiveForegroundAppLocked(smap, r);
                 }
                 r.isForeground = false;
+                StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.userId, r.shortName,
+                        StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
                 if (r.app != null) {
                     mAm.updateLruProcessLocked(r.app, false, null);
                     updateServiceForegroundLocked(r.app, true);
@@ -2533,7 +2538,10 @@
         cancelForegroundNotificationLocked(r);
         if (r.isForeground) {
             decActiveForegroundAppLocked(smap, r);
+            StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.userId, r.shortName,
+                    StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
         }
+
         r.isForeground = false;
         r.foregroundId = 0;
         r.foregroundNoti = null;
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 220014f..608352b 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -657,6 +657,26 @@
         return false;
     }
 
+    void remove() {
+        final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
+        while (getChildCount() > 0) {
+            final ActivityStack stack = getChildAt(0);
+            if (destroyContentOnRemoval) {
+                mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
+                        false /* onTop */);
+                stack.finishAllActivitiesLocked(true /* immediately */);
+            } else {
+                // Moving all tasks to fullscreen stack, because it's guaranteed to be
+                // a valid launch stack for all activities. This way the task history from
+                // external display will be preserved on primary after move.
+                mSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */);
+            }
+        }
+
+        mWindowContainerController.removeContainer();
+        mWindowContainerController = null;
+    }
+
     /** Update and get all UIDs that are present on the display and have access to it. */
     IntArray getPresentUIDs() {
         mDisplayAccessUIDs.clear();
@@ -666,7 +686,7 @@
         return mDisplayAccessUIDs;
     }
 
-    boolean shouldDestroyContentOnRemove() {
+    private boolean shouldDestroyContentOnRemove() {
         return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a3a854d..99904b5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -778,8 +778,11 @@
     long mWaitForNetworkTimeoutMs;
 
     /**
-     * Helper class which parses out priority arguments and dumps sections according to their
-     * priority. If priority arguments are omitted, function calls the legacy dump command.
+     * Helper class which strips out priority and proto arguments then calls the dump function with
+     * the appropriate arguments. If priority arguments are omitted, function calls the legacy
+     * dump command.
+     * If priority arguments are omitted all sections are dumped, otherwise sections are dumped
+     * according to their priority.
      */
     private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
         @Override
@@ -791,24 +794,7 @@
 
         @Override
         public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
-            if (asProto) {
-                doDump(fd, pw, new String[0], asProto);
-            } else {
-                doDump(fd, pw, new String[]{"settings"}, asProto);
-                doDump(fd, pw, new String[]{"intents"}, asProto);
-                doDump(fd, pw, new String[]{"broadcasts"}, asProto);
-                doDump(fd, pw, new String[]{"providers"}, asProto);
-                doDump(fd, pw, new String[]{"permissions"}, asProto);
-                doDump(fd, pw, new String[]{"services"}, asProto);
-                doDump(fd, pw, new String[]{"recents"}, asProto);
-                doDump(fd, pw, new String[]{"lastanr"}, asProto);
-                doDump(fd, pw, new String[]{"starter"}, asProto);
-                doDump(fd, pw, new String[]{"containers"}, asProto);
-                if (mAssociations.size() > 0) {
-                    doDump(fd, pw, new String[]{"associations"}, asProto);
-                }
-                doDump(fd, pw, new String[]{"processes"}, asProto);
-            }
+            doDump(fd, pw, new String[]{"-a", "--normal-priority"}, asProto);
         }
 
         @Override
@@ -1868,7 +1854,6 @@
     static final int REPORT_MEM_USAGE_MSG = 33;
     static final int IMMERSIVE_MODE_LOCK_MSG = 37;
     static final int PERSIST_URI_GRANTS_MSG = 38;
-    static final int REQUEST_ALL_PSS_MSG = 39;
     static final int UPDATE_TIME_PREFERENCE_MSG = 41;
     static final int ENTER_ANIMATION_COMPLETE_MSG = 44;
     static final int FINISH_BOOTING_MSG = 45;
@@ -2334,12 +2319,6 @@
                 writeGrantedUriPermissions();
                 break;
             }
-            case REQUEST_ALL_PSS_MSG: {
-                synchronized (ActivityManagerService.this) {
-                    requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
-                }
-                break;
-            }
             case UPDATE_TIME_PREFERENCE_MSG: {
                 // The user's time format preference might have changed.
                 // For convenience we re-use the Intent extra values.
@@ -2629,11 +2608,17 @@
                         procState = proc.pssProcState;
                         statType = proc.pssStatType;
                         lastPssTime = proc.lastPssTime;
+                        long now = SystemClock.uptimeMillis();
                         if (proc.thread != null && procState == proc.setProcState
                                 && (lastPssTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE)
-                                        < SystemClock.uptimeMillis()) {
+                                        < now) {
                             pid = proc.pid;
                         } else {
+                            ProcessList.abortNextPssTime(proc.procStateMemTracker);
+                            if (DEBUG_PSS) Slog.d(TAG_PSS, "Skipped pss collection of " + pid +
+                                    ": still need " +
+                                    (lastPssTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE-now) +
+                                    "ms until safe");
                             proc = null;
                             pid = 0;
                         }
@@ -3019,6 +3004,16 @@
 
         Watchdog.getInstance().addMonitor(this);
         Watchdog.getInstance().addThread(mHandler);
+
+        // bind background thread to little cores
+        // this is expected to fail inside of framework tests because apps can't touch cpusets directly
+        try {
+            Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
+                    Process.THREAD_GROUP_BG_NONINTERACTIVE);
+        } catch (Exception e) {
+            Slog.w(TAG, "Setting background thread cpuset failed");
+        }
+
     }
 
     protected ActivityStackSupervisor createStackSupervisor() {
@@ -3297,6 +3292,7 @@
      * Update AMS states when an activity is resumed. This should only be called by
      * {@link ActivityStack#setResumedActivityLocked} when an activity is resumed.
      */
+    @GuardedBy("this")
     void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
         final TaskRecord task = r.getTask();
         if (task.isActivityTypeStandard()) {
@@ -3822,6 +3818,7 @@
             info.className = entryPoint;
             info.packageName = "android";
             info.seInfoUser = SELinuxUtil.COMPLETE_STR;
+            info.targetSdkVersion = Build.VERSION.SDK_INT;
             ProcessRecord proc = startProcessLocked(processName, info /* info */,
                     false /* knownToBeDead */, 0 /* intentFlags */, ""  /* hostingType */,
                     null /* hostingName */, true /* allowWhileBooting */, true /* isolated */,
@@ -3831,6 +3828,7 @@
         }
     }
 
+    @GuardedBy("this")
     final ProcessRecord startProcessLocked(String processName,
             ApplicationInfo info, boolean knownToBeDead, int intentFlags,
             String hostingType, ComponentName hostingName, boolean allowWhileBooting,
@@ -3841,6 +3839,7 @@
                 null /* crashHandler */);
     }
 
+    @GuardedBy("this")
     final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
             boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
             boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
@@ -3957,6 +3956,7 @@
         return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
     }
 
+    @GuardedBy("this")
     private final void startProcessLocked(ProcessRecord app,
             String hostingType, String hostingNameStr) {
         startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */);
@@ -3965,6 +3965,7 @@
     /**
      * @return {@code true} if process start is successful, false otherwise.
      */
+    @GuardedBy("this")
     private final boolean startProcessLocked(ProcessRecord app, String hostingType,
             String hostingNameStr, String abiOverride) {
         if (app.pendingStart) {
@@ -5139,6 +5140,7 @@
                 .supportsLocalVoiceInteraction();
     }
 
+    @GuardedBy("this")
     void onLocalVoiceInteractionStartedLocked(IBinder activity,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
         ActivityRecord activityToCallback = ActivityRecord.forTokenLocked(activity);
@@ -5637,6 +5639,7 @@
      * as a result of that process going away.  Clears out all connections
      * to the process.
      */
+    @GuardedBy("this")
     private final void handleAppDiedLocked(ProcessRecord app,
             boolean restarting, boolean allowRestart) {
         int pid = app.pid;
@@ -5783,10 +5786,12 @@
         }
     }
 
+    @GuardedBy("this")
     final void appDiedLocked(ProcessRecord app) {
        appDiedLocked(app, app.pid, app.thread, false);
     }
 
+    @GuardedBy("this")
     final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
             boolean fromBinderDied) {
         // First check if this ProcessRecord is actually active for the pid.
@@ -6244,6 +6249,7 @@
         }
     }
 
+    @GuardedBy("this")
     final void showLaunchWarningLocked(final ActivityRecord cur, final ActivityRecord next) {
         if (!mLaunchWarningShown) {
             mLaunchWarningShown = true;
@@ -6670,6 +6676,7 @@
         }
     }
 
+    @GuardedBy("this")
     void closeSystemDialogsLocked(String reason) {
         Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -6776,11 +6783,13 @@
         }
     }
 
+    @GuardedBy("this")
     private void forceStopPackageLocked(final String packageName, int uid, String reason) {
         forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
                 false, true, false, false, UserHandle.getUserId(uid), reason);
     }
 
+    @GuardedBy("this")
     private void finishForceStopPackageLocked(final String packageName, int uid) {
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
@@ -6796,6 +6805,7 @@
     }
 
 
+    @GuardedBy("this")
     private final boolean killPackageProcessesLocked(String packageName, int appId,
             int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
             boolean doit, boolean evenPersistent, String reason) {
@@ -6967,6 +6977,7 @@
         return didSomething;
     }
 
+    @GuardedBy("this")
     final boolean forceStopPackageLocked(String packageName, int appId,
             boolean callerWillRestart, boolean purgeCache, boolean doit,
             boolean evenPersistent, boolean uninstalling, int userId, String reason) {
@@ -7178,6 +7189,7 @@
         }
     }
 
+    @GuardedBy("this")
     boolean removeProcessLocked(ProcessRecord app,
             boolean callerWillRestart, boolean allowRestart, String reason) {
         final String name = app.processName;
@@ -7232,6 +7244,7 @@
         return needRestart;
     }
 
+    @GuardedBy("this")
     private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
         cleanupAppInLaunchingProvidersLocked(app, true);
         removeProcessLocked(app, false, true, "timeout publishing content providers");
@@ -7292,6 +7305,7 @@
         }
     }
 
+    @GuardedBy("this")
     private final boolean attachApplicationLocked(IApplicationThread thread,
             int pid, int callingUid, long startSeq) {
 
@@ -9145,6 +9159,7 @@
                 grantEphemeralAccess(userId, intent, targetAppId, ephemeralAppId);
     }
 
+    @GuardedBy("this")
     private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
         final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
         if (targetUris != null) {
@@ -9153,6 +9168,7 @@
         return null;
     }
 
+    @GuardedBy("this")
     private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
             String targetPkg, int targetUid, GrantUri grantUri) {
         ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
@@ -9170,6 +9186,7 @@
         return perm;
     }
 
+    @GuardedBy("this")
     private final boolean checkUriPermissionLocked(GrantUri grantUri, int uid,
             final int modeFlags) {
         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
@@ -9240,6 +9257,7 @@
      * If you already know the uid of the target, you can supply it in
      * lastTargetUid else set that to -1.
      */
+    @GuardedBy("this")
     int checkGrantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
             final int modeFlags, int lastTargetUid) {
         if (!Intent.isAccessUriMode(modeFlags)) {
@@ -9402,6 +9420,7 @@
         }
     }
 
+    @GuardedBy("this")
     void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, GrantUri grantUri,
             final int modeFlags, UriPermissionOwner owner) {
         if (!Intent.isAccessUriMode(modeFlags)) {
@@ -9431,6 +9450,7 @@
         perm.grantModes(modeFlags, owner);
     }
 
+    @GuardedBy("this")
     void grantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
             final int modeFlags, UriPermissionOwner owner, int targetUserId) {
         if (targetPkg == null) {
@@ -9482,6 +9502,7 @@
     /**
      * Like checkGrantUriPermissionLocked, but takes an Intent.
      */
+    @GuardedBy("this")
     NeededUriGrants checkGrantUriPermissionFromIntentLocked(int callingUid,
             String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
         if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
@@ -9568,6 +9589,7 @@
     /**
      * Like grantUriPermissionUncheckedLocked, but takes an Intent.
      */
+    @GuardedBy("this")
     void grantUriPermissionUncheckedFromIntentLocked(NeededUriGrants needed,
             UriPermissionOwner owner) {
         if (needed != null) {
@@ -9579,6 +9601,7 @@
         }
     }
 
+    @GuardedBy("this")
     void grantUriPermissionFromIntentLocked(int callingUid,
             String targetPkg, Intent intent, UriPermissionOwner owner, int targetUserId) {
         NeededUriGrants needed = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg,
@@ -9623,6 +9646,7 @@
         }
     }
 
+    @GuardedBy("this")
     void removeUriPermissionIfNeededLocked(UriPermission perm) {
         if (perm.modeFlags == 0) {
             final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
@@ -9639,6 +9663,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void revokeUriPermissionLocked(String targetPackage, int callingUid, GrantUri grantUri,
             final int modeFlags) {
         if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
@@ -9773,6 +9798,7 @@
      * @param targetOnly When {@code true}, only remove permissions where the app is the target,
      * not source.
      */
+    @GuardedBy("this")
     private void removeUriPermissionsForPackageLocked(
             String packageName, int userHandle, boolean persistable, boolean targetOnly) {
         if (userHandle == UserHandle.USER_ALL && packageName == null) {
@@ -9959,6 +9985,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void readGrantedUriPermissionsLocked() {
         if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "readGrantedUriPermissions()");
 
@@ -10121,6 +10148,7 @@
      *
      * @return if any mutations occured that require persisting.
      */
+    @GuardedBy("this")
     private boolean maybePrunePersistedUriGrantsLocked(int uid) {
         final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
         if (perms == null) return false;
@@ -11330,8 +11358,11 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                startLockTaskModeLocked(mStackSupervisor.anyTaskForIdLocked(taskId),
-                        true /* isSystemCaller */);
+                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+
+                // When starting lock task mode the stack must be in front and focused
+                task.getStack().moveToFront("startSystemLockTaskMode");
+                startLockTaskModeLocked(task, true /* isSystemCaller */);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -12618,6 +12649,7 @@
     // GLOBAL MANAGEMENT
     // =========================================================
 
+    @GuardedBy("this")
     final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
             boolean isolated, int isolatedUid) {
         String proc = customProcess != null ? customProcess : info.processName;
@@ -12662,6 +12694,9 @@
         if (!mBooted && !mBooting
                 && userId == UserHandle.USER_SYSTEM
                 && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
+            // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
+            r.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+            r.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             r.persistent = true;
             r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
         }
@@ -12704,6 +12739,7 @@
         }
     }
 
+    @GuardedBy("this")
     final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
             String abiOverride) {
         ProcessRecord app;
@@ -12820,6 +12856,7 @@
         }
     }
 
+    @GuardedBy("this")
     void finishRunningVoiceLocked() {
         if (mRunningVoice != null) {
             mRunningVoice = null;
@@ -12835,6 +12872,7 @@
         }
     }
 
+    @GuardedBy("this")
     void updateSleepIfNeededLocked() {
         final boolean shouldSleep = !mStackSupervisor.hasAwakeDisplay();
         final boolean wasSleeping = mSleeping;
@@ -12939,6 +12977,7 @@
         Binder.restoreCallingIdentity(origId);
     }
 
+    @GuardedBy("this")
     void startRunningVoiceLocked(IVoiceInteractionSession session, int targetUid) {
         Slog.d(TAG, "<<<  startRunningVoiceLocked()");
         mVoiceWakeLock.setWorkSource(new WorkSource(targetUid));
@@ -14491,9 +14530,6 @@
                             mTestPssMode, isSleepingLocked(), now);
                 }
             }
-
-            mHandler.removeMessages(REQUEST_ALL_PSS_MSG);
-            mHandler.sendEmptyMessageDelayed(REQUEST_ALL_PSS_MSG, 2*60*1000);
         }
     }
 
@@ -14800,8 +14836,6 @@
             mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
 
             BinderInternal.nSetBinderProxyCountEnabled(true);
-            //STOPSHIP: Temporary BinderProxy Threshold for b/71353150
-            BinderInternal.nSetBinderProxyCountWatermarks(1500, 1200);
             BinderInternal.setBinderProxyCountCallback(
                     new BinderInternal.BinderProxyLimitListener() {
                         @Override
@@ -15504,6 +15538,7 @@
         boolean dumpClient = false;
         boolean dumpCheckin = false;
         boolean dumpCheckinFormat = false;
+        boolean dumpNormalPriority = false;
         boolean dumpVisibleStacksOnly = false;
         boolean dumpFocusedStackOnly = false;
         String dumpPackage = null;
@@ -15536,6 +15571,8 @@
                 dumpCheckin = dumpCheckinFormat = true;
             } else if ("-C".equals(opt)) {
                 dumpCheckinFormat = true;
+            } else if ("--normal-priority".equals(opt)) {
+                dumpNormalPriority = true;
             } else if ("-h".equals(opt)) {
                 ActivityManagerShellCommand.dumpHelp(pw, true);
                 return;
@@ -15937,11 +15974,15 @@
                     pw.println("-------------------------------------------------------------------------------");
                 }
                 dumpActivityContainersLocked(pw);
-                pw.println();
-                if (dumpAll) {
-                    pw.println("-------------------------------------------------------------------------------");
+                // Activities section is dumped as part of the Critical priority dump. Exclude the
+                // section if priority is Normal.
+                if (!dumpNormalPriority){
+                    pw.println();
+                    if (dumpAll) {
+                        pw.println("-------------------------------------------------------------------------------");
+                    }
+                    dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                 }
-                dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                 if (mAssociations.size() > 0) {
                     pw.println();
                     if (dumpAll) {
@@ -16172,6 +16213,7 @@
         return false;
     }
 
+    @GuardedBy("this")
     void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage, int dumpAppId) {
         boolean needSep = false;
@@ -16625,6 +16667,7 @@
         pw.println("  mForceBackgroundCheck=" + mForceBackgroundCheck);
     }
 
+    @GuardedBy("this")
     void writeProcessesToProtoLocked(ProtoOutputStream proto, String dumpPackage) {
         int numPers = 0;
 
@@ -17452,6 +17495,7 @@
         }
     }
 
+    @GuardedBy("this")
     void dumpPermissionsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
         boolean needSep = false;
@@ -19524,6 +19568,7 @@
      * @return Returns true if the given process has been restarted, so the
      * app that was passed in must remain on the process lists.
      */
+    @GuardedBy("this")
     private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
             boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
         if (index >= 0) {
@@ -19533,6 +19578,7 @@
 
         mProcessesToGc.remove(app);
         mPendingPssProcesses.remove(app);
+        ProcessList.abortNextPssTime(app.procStateMemTracker);
 
         // Dismiss any open dialogs.
         if (app.crashDialog != null && !app.forceCrashReport) {
@@ -20612,6 +20658,7 @@
         }
     }
 
+    @GuardedBy("this")
     final int broadcastIntentLocked(ProcessRecord callerApp,
             String callerPackage, Intent intent, String resolvedType,
             IIntentReceiver resultTo, int resultCode, String resultData,
@@ -21602,6 +21649,7 @@
         }
     }
 
+    @GuardedBy("this")
     void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
         if (app.instr == null) {
             Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
@@ -21886,7 +21934,7 @@
         }
         try {
             if (values != null) {
-                changes = updateGlobalConfiguration(values, initLocale, persistent, userId,
+                changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId,
                         deferResume);
             }
 
@@ -21904,8 +21952,16 @@
         return kept;
     }
 
+    /**
+     * Returns true if this configuration change is interesting enough to send an
+     * {@link Intent#ACTION_SPLIT_CONFIGURATION_CHANGED} broadcast.
+     */
+    private static boolean isSplitConfigurationChange(int configDiff) {
+        return (configDiff & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_DENSITY)) != 0;
+    }
+
     /** Update default (global) configuration and notify listeners about changes. */
-    private int updateGlobalConfiguration(@NonNull Configuration values, boolean initLocale,
+    private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
             boolean persistent, int userId, boolean deferResume) {
         mTempConfig.setTo(getGlobalConfiguration());
         final int changes = mTempConfig.updateFrom(values);
@@ -22008,6 +22064,19 @@
                     UserHandle.USER_ALL);
         }
 
+        // Send a broadcast to PackageInstallers if the configuration change is interesting
+        // for the purposes of installing additional splits.
+        if (!initLocale && isSplitConfigurationChange(changes)) {
+            intent = new Intent(Intent.ACTION_SPLIT_CONFIGURATION_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+
+            // Typically only app stores will have this permission.
+            String[] permissions = new String[] { android.Manifest.permission.INSTALL_PACKAGES };
+            broadcastIntentLocked(null, null, intent, null, null, 0, null, null, permissions,
+                    OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+        }
+
         // Override configuration of the default display duplicates global config, so we need to
         // update it also. This will also notify WindowManager about changes.
         performDisplayOverrideConfigUpdate(mStackSupervisor.getConfiguration(), deferResume,
@@ -22080,7 +22149,7 @@
                     // Override configuration of the default display duplicates global config, so
                     // we're calling global config update instead for default display. It will also
                     // apply the correct override config.
-                    changes = updateGlobalConfiguration(values, false /* initLocale */,
+                    changes = updateGlobalConfigurationLocked(values, false /* initLocale */,
                             false /* persistent */, UserHandle.USER_NULL /* userId */, deferResume);
                 } else {
                     changes = performDisplayOverrideConfigUpdate(values, deferResume, displayId);
@@ -23297,9 +23366,9 @@
     /**
      * Schedule PSS collection of a process.
      */
-    void requestPssLocked(ProcessRecord proc, int procState) {
+    boolean requestPssLocked(ProcessRecord proc, int procState) {
         if (mPendingPssProcesses.contains(proc)) {
-            return;
+            return false;
         }
         if (mPendingPssProcesses.size() == 0) {
             mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
@@ -23308,6 +23377,7 @@
         proc.pssProcState = procState;
         proc.pssStatType = ProcessStats.ADD_PSS_INTERNAL_SINGLE;
         mPendingPssProcesses.add(proc);
+        return true;
     }
 
     /**
@@ -23324,6 +23394,9 @@
         if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting pss of all procs!  memLowered=" + memLowered);
         mLastFullPssTime = now;
         mFullPssPending = true;
+        for (int i = mPendingPssProcesses.size() - 1; i >= 0; i--) {
+            ProcessList.abortNextPssTime(mPendingPssProcesses.get(i).procStateMemTracker);;
+        }
         mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
         mPendingPssProcesses.clear();
         for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
@@ -23332,7 +23405,9 @@
                     || app.curProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
                 continue;
             }
-            if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
+            if (memLowered || (always && now >
+                            app.lastStateTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE)
+                    || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
                 app.pssProcState = app.setProcState;
                 app.pssStatType = always ? ProcessStats.ADD_PSS_INTERNAL_ALL_POLL
                         : ProcessStats.ADD_PSS_INTERNAL_ALL_MEM;
@@ -23341,7 +23416,9 @@
                 mPendingPssProcesses.add(app);
             }
         }
-        mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+        if (!mBgHandler.hasMessages(COLLECT_PSS_BG_MSG)) {
+            mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+        }
     }
 
     public void setTestPssMode(boolean enabled) {
@@ -23699,7 +23776,7 @@
                 // Experimental code to more aggressively collect pss while
                 // running test...  the problem is that this tends to collect
                 // the data right when a process is transitioning between process
-                // states, which well tend to give noisy data.
+                // states, which will tend to give noisy data.
                 long start = SystemClock.uptimeMillis();
                 long startTime = SystemClock.currentThreadTimeMillis();
                 long pss = Debug.getPss(app.pid, mTmpLong, null);
@@ -23722,9 +23799,10 @@
             if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
                     && now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
                     mTestPssMode)))) {
-                requestPssLocked(app, app.setProcState);
-                app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
-                        app.procStateMemTracker, mTestPssMode, isSleepingLocked(), now);
+                if (requestPssLocked(app, app.setProcState)) {
+                    app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
+                            app.procStateMemTracker, mTestPssMode, isSleepingLocked(), now);
+                }
             } else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
                     "Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
         }
@@ -23991,6 +24069,7 @@
         return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
     }
 
+    @GuardedBy("this")
     final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
             boolean oomAdj) {
         if (isForeground != proc.foregroundServices) {
@@ -24060,6 +24139,7 @@
      *                  if necessary, or skip.
      * @return whether updateOomAdjLocked(app) was successful.
      */
+    @GuardedBy("this")
     final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
@@ -24084,6 +24164,7 @@
         return success;
     }
 
+    @GuardedBy("this")
     final void updateOomAdjLocked() {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
@@ -24804,6 +24885,7 @@
     /**
      * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
      */
+    @GuardedBy("this")
     void tempWhitelistForPendingIntentLocked(int callerPid, int callerUid, int targetUid,
             long duration, String tag) {
         if (DEBUG_WHITELISTS) {
@@ -24836,6 +24918,7 @@
     /**
      * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
      */
+    @GuardedBy("this")
     void tempWhitelistUidLocked(int targetUid, long duration, String tag) {
         mPendingTempWhitelist.put(targetUid, new PendingTempWhitelist(targetUid, duration, tag));
         setUidTempWhitelistStateLocked(targetUid, true);
@@ -24875,6 +24958,7 @@
         }
     }
 
+    @GuardedBy("this")
     final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) {
         boolean changed = false;
         for (int i=mActiveUids.size()-1; i>=0; i--) {
@@ -24889,6 +24973,7 @@
         }
     }
 
+    @GuardedBy("this")
     final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) {
         boolean changed = false;
         final UidRecord uidRec = mActiveUids.get(uid);
@@ -25867,6 +25952,14 @@
         public boolean isCallerRecents(int callingUid) {
             return getRecentTasks().isCallerRecents(callingUid);
         }
+
+        @Override
+        public boolean isUidActive(int uid) {
+            synchronized (ActivityManagerService.this) {
+                final UidRecord uidRec = mActiveUids.get(uid);
+                return (uidRec != null) && !uidRec.idle;
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 66f0592..e2ceb31 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -32,6 +32,8 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.MemoryStatUtil.MemoryStat;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromMemcg;
 
 import android.content.Context;
 import android.metrics.LogMaker;
@@ -67,6 +69,7 @@
     private static final long INVALID_START_TIME = -1;
 
     private static final int MSG_CHECK_VISIBILITY = 0;
+    private static final int MSG_LOG_APP_START_MEMORY_STATE_CAPTURE = 1;
 
     // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
     // time we log.
@@ -102,6 +105,9 @@
                     final SomeArgs args = (SomeArgs) msg.obj;
                     checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
                     break;
+                case MSG_LOG_APP_START_MEMORY_STATE_CAPTURE:
+                    logAppStartMemoryStateCapture((StackTransitionInfo) msg.obj);
+                    break;
             }
         }
     };
@@ -187,10 +193,7 @@
      * @param launchedActivity the activity that is being launched
      */
     void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity) {
-        final ProcessRecord processRecord = launchedActivity != null
-                ? mSupervisor.mService.mProcessNames.get(launchedActivity.processName,
-                        launchedActivity.appInfo.uid)
-                : null;
+        final ProcessRecord processRecord = findProcessForActivity(launchedActivity);
         final boolean processRunning = processRecord != null;
 
         // We consider this a "process switch" if the process of the activity that gets launched
@@ -492,6 +495,7 @@
                     info.bindApplicationDelayMs,
                     info.windowsDrawnDelayMs,
                     launchToken);
+            mHandler.obtainMessage(MSG_LOG_APP_START_MEMORY_STATE_CAPTURE, info).sendToTarget();
         }
     }
 
@@ -548,4 +552,38 @@
         }
         return -1;
     }
+
+    private void logAppStartMemoryStateCapture(StackTransitionInfo info) {
+        final ProcessRecord processRecord = findProcessForActivity(info.launchedActivity);
+        if (processRecord == null) {
+            if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null");
+            return;
+        }
+
+        final int pid = processRecord.pid;
+        final int uid = info.launchedActivity.appInfo.uid;
+        final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid);
+        if (memoryStat == null) {
+            if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null");
+            return;
+        }
+
+        StatsLog.write(
+                StatsLog.APP_START_MEMORY_STATE_CAPTURED,
+                uid,
+                info.launchedActivity.processName,
+                info.launchedActivity.info.name,
+                memoryStat.pgfault,
+                memoryStat.pgmajfault,
+                memoryStat.rssInBytes,
+                memoryStat.cacheInBytes,
+                memoryStat.swapInBytes);
+    }
+
+    private ProcessRecord findProcessForActivity(ActivityRecord launchedActivity) {
+        return launchedActivity != null
+                ? mSupervisor.mService.mProcessNames.get(launchedActivity.processName,
+                        launchedActivity.appInfo.uid)
+                : null;
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index cae0d2b..9838851 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -133,11 +133,16 @@
 import android.app.PendingIntent;
 import android.app.PictureInPictureParams;
 import android.app.ResultInfo;
+import android.app.servertransaction.ActivityLifecycleItem;
+import android.app.servertransaction.ActivityRelaunchItem;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.ClientTransactionItem;
 import android.app.servertransaction.MoveToDisplayItem;
 import android.app.servertransaction.MultiWindowModeChangeItem;
 import android.app.servertransaction.NewIntentItem;
 import android.app.servertransaction.PauseActivityItem;
 import android.app.servertransaction.PipModeChangeItem;
+import android.app.servertransaction.ResumeActivityItem;
 import android.app.servertransaction.WindowVisibilityItem;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.content.ComponentName;
@@ -375,7 +380,8 @@
     }
 
     String getLifecycleDescription(String reason) {
-        return "packageName=" + packageName + ", state=" + state + ", reason=" + reason;
+        return "component:" + intent.getComponent().flattenToShortString() + ", state=" + state
+                + ", reason=" + reason + ", time=" + System.currentTimeMillis();
     }
 
     void dump(PrintWriter pw, String prefix) {
@@ -2370,6 +2376,15 @@
 
         setLastReportedConfiguration(service.getGlobalConfiguration(), newMergedOverrideConfig);
 
+        if (state == INITIALIZING) {
+            // No need to relaunch or schedule new config for activity that hasn't been launched
+            // yet. We do, however, return after applying the config to activity record, so that
+            // it will use it for launch transaction.
+            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+                    "Skipping config check for initializing activity: " + this);
+            return true;
+        }
+
         if (changes == 0 && !forceNewConfig) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                     "Configuration no differences in " + this);
@@ -2559,12 +2574,23 @@
                             + " callers=" + Debug.getCallers(6));
             forceNewConfig = false;
             mStackSupervisor.activityRelaunchingLocked(this);
-            app.thread.scheduleRelaunchActivity(appToken, pendingResults, pendingNewIntents,
-                    configChangeFlags, !andResume,
-                    new Configuration(service.getGlobalConfiguration()),
-                    new Configuration(getMergedOverrideConfiguration()), preserveWindow);
+            final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
+                    pendingNewIntents, configChangeFlags,
+                    new MergedConfiguration(service.getGlobalConfiguration(),
+                            getMergedOverrideConfiguration()),
+                    preserveWindow);
+            final ActivityLifecycleItem lifecycleItem;
+            if (andResume) {
+                lifecycleItem = ResumeActivityItem.obtain(service.isNextTransitionForward());
+            } else {
+                lifecycleItem = PauseActivityItem.obtain();
+            }
+            final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
+            transaction.addCallback(callbackItem);
+            transaction.setLifecycleStateRequest(lifecycleItem);
+            service.mLifecycleManager.scheduleTransaction(transaction);
             // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
-            // pass in 'andResume' if this activity is currently resumed, which implies we aren't
+            // request resume if this activity is currently resumed, which implies we aren't
             // sleeping.
         } catch (RemoteException e) {
             if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ab2dc36..055a1aa 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -138,6 +138,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.BatteryStatsImpl;
@@ -2211,6 +2212,7 @@
      *       Use {@link ActivityStackSupervisor#resumeFocusedStackTopActivityLocked} to resume the
      *       right activity for the current system state.
      */
+    @GuardedBy("mService")
     boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
         if (mStackSupervisor.inResumeTopActivity) {
             // Don't even start recursing.
@@ -2250,6 +2252,7 @@
         mStackSupervisor.mRecentTasks.add(r.getTask());
     }
 
+    @GuardedBy("mService")
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
         if (!mService.mBooting && !mService.mBooted) {
             // Not ready yet!
@@ -4214,7 +4217,8 @@
                 if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
                 mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
                         DestroyActivityItem.obtain(r.finishing, r.configChangeFlags)
-                            .setDescription(r.getLifecycleDescription("destroyActivityLocked")));
+                            .setDescription(
+                                    r.getLifecycleDescription("destroyActivityLocked:" + reason)));
             } catch (Exception e) {
                 // We can just ignore exceptions here...  if the process
                 // has crashed, our death notification will clean things
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index bf38825..4928e90 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -22,6 +22,7 @@
 import static android.Manifest.permission.START_ANY_ACTIVITY;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
+import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
@@ -165,6 +166,7 @@
 import android.view.Display;
 import android.view.RemoteAnimationAdapter;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.logging.MetricsLoggerWrapper;
@@ -1133,19 +1135,31 @@
         }
     }
 
-    void reportTaskToFrontNoLaunch(ActivityRecord r) {
+    void reportWaitingActivityLaunchedIfNeeded(ActivityRecord r, int result) {
+        if (mWaitingActivityLaunched.isEmpty()) {
+            return;
+        }
+
+        if (result != START_DELIVERED_TO_TOP && result != START_TASK_TO_FRONT) {
+            return;
+        }
+
         boolean changed = false;
+
         for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) {
             WaitResult w = mWaitingActivityLaunched.remove(i);
             if (w.who == null) {
                 changed = true;
-                // Set result to START_TASK_TO_FRONT so that startActivityMayWait() knows that
-                // the starting activity ends up moving another activity to front, and it should
-                // wait for this new activity to become visible instead.
-                // Do not modify other fields.
-                w.result = START_TASK_TO_FRONT;
+                w.result = result;
+
+                // Unlike START_TASK_TO_FRONT, When an intent is delivered to top, there
+                // will be no followup launch signals. Assign the result and launched component.
+                if (result == START_DELIVERED_TO_TOP) {
+                    w.who = r.realActivity;
+                }
             }
         }
+
         if (changed) {
             mService.notifyAll();
         }
@@ -1253,7 +1267,7 @@
                 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "resolveIntent");
                 int modifiedFlags = flags
                         | PackageManager.MATCH_DEFAULT_ONLY | ActivityManagerService.STOCK_PM_FLAGS;
-                if (intent.isBrowsableWebIntent()
+                if (intent.isWebIntent()
                             || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
                     modifiedFlags |= PackageManager.MATCH_INSTANT;
                 }
@@ -1495,6 +1509,8 @@
             Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
         }
 
+        // TODO(lifecycler): Resume or pause requests are done as part of launch transaction,
+        // so updating the state should be done accordingly.
         if (andResume && readyToResume()) {
             // As part of the process of launching, ActivityThread also performs
             // a resume.
@@ -1845,6 +1861,7 @@
      * Called when the frontmost task is idle.
      * @return the state of mService.mBooting before this was called.
      */
+    @GuardedBy("mService")
     private boolean checkFinishBootingLocked() {
         final boolean booting = mService.mBooting;
         boolean enableScreen = false;
@@ -1860,6 +1877,7 @@
     }
 
     // Checked.
+    @GuardedBy("mService")
     final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
             boolean processPausingActivities, Configuration config) {
         if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token);
@@ -4074,25 +4092,12 @@
             if (activityDisplay == null) {
                 return;
             }
-            final boolean destroyContentOnRemoval
-                    = activityDisplay.shouldDestroyContentOnRemove();
-            while (activityDisplay.getChildCount() > 0) {
-                final ActivityStack stack = activityDisplay.getChildAt(0);
-                if (destroyContentOnRemoval) {
-                    moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, false /* onTop */);
-                    stack.finishAllActivitiesLocked(true /* immediately */);
-                } else {
-                    // Moving all tasks to fullscreen stack, because it's guaranteed to be
-                    // a valid launch stack for all activities. This way the task history from
-                    // external display will be preserved on primary after move.
-                    moveTasksToFullscreenStackLocked(stack, true /* onTop */);
-                }
-            }
+
+            activityDisplay.remove();
 
             releaseSleepTokens(activityDisplay);
 
             mActivityDisplays.remove(displayId);
-            mWindowManager.onDisplayRemoved(displayId);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index eab88aa..055b89b 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -790,7 +790,7 @@
         // Instead, launch the ephemeral installer. Once the installer is finished, it
         // starts either the intent we resolved here [on install error] or the ephemeral
         // app [on install success].
-        if (rInfo != null && rInfo.isInstantAppAvailable) {
+        if (rInfo != null && rInfo.auxiliaryInfo != null) {
             intent = createLaunchIntent(rInfo.auxiliaryInfo, ephemeralIntent,
                     callingPackage, verificationBundle, resolvedType, userId);
             resolvedType = null;
@@ -879,11 +879,11 @@
         }
 
         // We're waiting for an activity launch to finish, but that activity simply
-        // brought another activity to front. Let startActivityMayWait() know about
-        // this, so it waits for the new activity to become visible instead.
-        if (result == START_TASK_TO_FRONT && !mSupervisor.mWaitingActivityLaunched.isEmpty()) {
-            mSupervisor.reportTaskToFrontNoLaunch(mStartActivity);
-        }
+        // brought another activity to front. We must also handle the case where the task is already
+        // in the front as a result of the trampoline activity being in the same task (it will be
+        // considered focused as the trampoline will be finished). Let startActivityMayWait() know
+        // about this, so it waits for the new activity to become visible instead.
+        mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result);
 
         ActivityStack startedActivityStack = null;
         final ActivityStack currentStack = r.getStack();
@@ -1076,39 +1076,51 @@
 
             if (outResult != null) {
                 outResult.result = res;
-                if (res == ActivityManager.START_SUCCESS) {
-                    mSupervisor.mWaitingActivityLaunched.add(outResult);
-                    do {
-                        try {
-                            mService.wait();
-                        } catch (InterruptedException e) {
-                        }
-                    } while (outResult.result != START_TASK_TO_FRONT
-                            && !outResult.timeout && outResult.who == null);
-                    if (outResult.result == START_TASK_TO_FRONT) {
-                        res = START_TASK_TO_FRONT;
-                    }
-                }
-                if (res == START_TASK_TO_FRONT) {
-                    final ActivityRecord r = outRecord[0];
 
-                    // ActivityRecord may represent a different activity, but it should not be in
-                    // the resumed state.
-                    if (r.nowVisible && r.state == RESUMED) {
-                        outResult.timeout = false;
-                        outResult.who = r.realActivity;
-                        outResult.totalTime = 0;
-                        outResult.thisTime = 0;
-                    } else {
-                        outResult.thisTime = SystemClock.uptimeMillis();
-                        mSupervisor.waitActivityVisible(r.realActivity, outResult);
-                        // Note: the timeout variable is not currently not ever set.
+                final ActivityRecord r = outRecord[0];
+
+                switch(res) {
+                    case START_SUCCESS: {
+                        mSupervisor.mWaitingActivityLaunched.add(outResult);
                         do {
                             try {
                                 mService.wait();
                             } catch (InterruptedException e) {
                             }
-                        } while (!outResult.timeout && outResult.who == null);
+                        } while (outResult.result != START_TASK_TO_FRONT
+                                && !outResult.timeout && outResult.who == null);
+                        if (outResult.result == START_TASK_TO_FRONT) {
+                            res = START_TASK_TO_FRONT;
+                        }
+                        break;
+                    }
+                    case START_DELIVERED_TO_TOP: {
+                        outResult.timeout = false;
+                        outResult.who = r.realActivity;
+                        outResult.totalTime = 0;
+                        outResult.thisTime = 0;
+                        break;
+                    }
+                    case START_TASK_TO_FRONT: {
+                        // ActivityRecord may represent a different activity, but it should not be
+                        // in the resumed state.
+                        if (r.nowVisible && r.state == RESUMED) {
+                            outResult.timeout = false;
+                            outResult.who = r.realActivity;
+                            outResult.totalTime = 0;
+                            outResult.thisTime = 0;
+                        } else {
+                            outResult.thisTime = SystemClock.uptimeMillis();
+                            mSupervisor.waitActivityVisible(r.realActivity, outResult);
+                            // Note: the timeout variable is not currently not ever set.
+                            do {
+                                try {
+                                    mService.wait();
+                                } catch (InterruptedException e) {
+                                }
+                            } while (!outResult.timeout && outResult.who == null);
+                        }
+                        break;
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 927b72c..ef82f36 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -182,6 +182,7 @@
         mExecutorService.shutdownNow();
     }
 
+    @GuardedBy("this")
     private Future<?> scheduleSyncLocked(String reason, int flags) {
         if (mExecutorService.isShutdown()) {
             return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
@@ -248,6 +249,7 @@
         }
     };
 
+    @GuardedBy("mWorkerLock")
     private void updateExternalStatsLocked(final String reason, int updateFlags) {
         // We will request data from external processes asynchronously, and wait on a timeout.
         SynchronousResultReceiver wifiReceiver = null;
@@ -372,6 +374,7 @@
         return null;
     }
 
+    @GuardedBy("mWorkerLock")
     private WifiActivityEnergyInfo extractDeltaLocked(WifiActivityEnergyInfo latest) {
         final long timePeriodMs = latest.mTimestamp - mLastInfo.mTimestamp;
         final long lastScanMs = mLastInfo.mControllerScanTimeMs;
diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
index d6c6f96..71fd71b 100644
--- a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
@@ -41,6 +41,7 @@
     //  {Settings.Global.SETTING_NAME, "system_property_name"},
         {Settings.Global.SYS_VDSO, "sys.vdso"},
         {Settings.Global.FPS_DEVISOR, ThreadedRenderer.DEBUG_FPS_DIVISOR},
+        {Settings.Global.DISPLAY_PANEL_LPM, "sys.display_panel_lpm"},
     };
 
 
@@ -92,7 +93,7 @@
         }
         try {
             systemPropertiesSet(key, value);
-        } catch (IllegalArgumentException e) {
+        } catch (Exception e) {
             Slog.e(TAG, "Unable to set property " + key + " value '" + value + "'", e);
         }
     }
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
new file mode 100644
index 0000000..d97c2a2
--- /dev/null
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.Nullable;
+import android.os.FileUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Static utility methods related to {@link MemoryStat}.
+ */
+final class MemoryStatUtil {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;
+
+    /** Path to memory stat file for logging app start memory state */
+    private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat";
+
+    private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
+    private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
+    private static final Pattern RSS_IN_BYTES = Pattern.compile("total_rss (\\d+)");
+    private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)");
+    private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)");
+
+    private MemoryStatUtil() {}
+
+    /**
+     * Reads memory.stat of a process from memcg.
+     */
+    static @Nullable MemoryStat readMemoryStatFromMemcg(int uid, int pid) {
+        final String memoryStatPath = String.format(MEMORY_STAT_FILE_FMT, uid, pid);
+        final File memoryStatFile = new File(memoryStatPath);
+        if (!memoryStatFile.exists()) {
+            if (DEBUG_METRICS) Slog.i(TAG, memoryStatPath + " not found");
+            return null;
+        }
+
+        try {
+            final String memoryStatContents = FileUtils.readTextFile(
+                    memoryStatFile, 0 /* max */, null /* ellipsis */);
+            return parseMemoryStat(memoryStatContents);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read file:", e);
+            return null;
+        }
+    }
+
+    /**
+     * Parses relevant statistics out from the contents of a memory.stat file in memcg.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    static @Nullable MemoryStat parseMemoryStat(String memoryStatContents) {
+        MemoryStat memoryStat = new MemoryStat();
+        if (memoryStatContents == null) {
+            return memoryStat;
+        }
+
+        Matcher m;
+        m = PGFAULT.matcher(memoryStatContents);
+        memoryStat.pgfault = m.find() ? Long.valueOf(m.group(1)) : 0;
+        m = PGMAJFAULT.matcher(memoryStatContents);
+        memoryStat.pgmajfault = m.find() ? Long.valueOf(m.group(1)) : 0;
+        m = RSS_IN_BYTES.matcher(memoryStatContents);
+        memoryStat.rssInBytes = m.find() ? Long.valueOf(m.group(1)) : 0;
+        m = CACHE_IN_BYTES.matcher(memoryStatContents);
+        memoryStat.cacheInBytes = m.find() ? Long.valueOf(m.group(1)) : 0;
+        m = SWAP_IN_BYTES.matcher(memoryStatContents);
+        memoryStat.swapInBytes = m.find() ? Long.valueOf(m.group(1)) : 0;
+        return memoryStat;
+    }
+
+    static final class MemoryStat {
+        /** Number of page faults */
+        long pgfault;
+        /** Number of major page faults */
+        long pgmajfault;
+        /** Number of bytes of anonymous and swap cache memory */
+        long rssInBytes;
+        /** Number of bytes of page cache memory */
+        long cacheInBytes;
+        /** Number of bytes of swap usage */
+        long swapInBytes;
+    }
+}
diff --git a/services/core/java/com/android/server/am/PersistentConnection.java b/services/core/java/com/android/server/am/PersistentConnection.java
index 52eaca1..c5edb26 100644
--- a/services/core/java/com/android/server/am/PersistentConnection.java
+++ b/services/core/java/com/android/server/am/PersistentConnection.java
@@ -220,6 +220,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     public final void bindInnerLocked(boolean resetBackoff) {
         unscheduleRebindLocked();
 
@@ -260,6 +261,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void cleanUpConnectionLocked() {
         mIsConnected = false;
         mService = null;
@@ -276,6 +278,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private final void unbindLocked() {
         unscheduleRebindLocked();
 
@@ -289,11 +292,13 @@
         cleanUpConnectionLocked();
     }
 
+    @GuardedBy("mLock")
     void unscheduleRebindLocked() {
         injectRemoveCallbacks(mBindForBackoffRunnable);
         mRebindScheduled = false;
     }
 
+    @GuardedBy("mLock")
     void scheduleRebindLocked() {
         unbindLocked();
 
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 08ee237..bf7aef9 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -501,19 +501,19 @@
     private static final int PSS_FIRST_CACHED_INTERVAL = 20*1000;
 
     // The amount of time until PSS when an important process stays in the same state.
-    private static final int PSS_SAME_PERSISTENT_INTERVAL = 20*60*1000;
+    private static final int PSS_SAME_PERSISTENT_INTERVAL = 10*60*1000;
 
     // The amount of time until PSS when the top process stays in the same state.
-    private static final int PSS_SAME_TOP_INTERVAL = 5*60*1000;
+    private static final int PSS_SAME_TOP_INTERVAL = 1*60*1000;
 
     // The amount of time until PSS when an important process stays in the same state.
-    private static final int PSS_SAME_IMPORTANT_INTERVAL = 15*60*1000;
+    private static final int PSS_SAME_IMPORTANT_INTERVAL = 10*60*1000;
 
     // The amount of time until PSS when a service process stays in the same state.
-    private static final int PSS_SAME_SERVICE_INTERVAL = 20*60*1000;
+    private static final int PSS_SAME_SERVICE_INTERVAL = 5*60*1000;
 
     // The amount of time until PSS when a cached process stays in the same state.
-    private static final int PSS_SAME_CACHED_INTERVAL = 20*60*1000;
+    private static final int PSS_SAME_CACHED_INTERVAL = 10*60*1000;
 
     // The amount of time until PSS when a persistent process first appears.
     private static final int PSS_FIRST_ASLEEP_PERSISTENT_INTERVAL = 1*60*1000;
@@ -622,16 +622,17 @@
 
     public static final class ProcStateMemTracker {
         final int[] mHighestMem = new int[PROC_MEM_NUM];
+        final float[] mScalingFactor = new float[PROC_MEM_NUM];
         int mTotalHighestMem = PROC_MEM_CACHED;
-        float mCurFactor = 1.0f;
 
         int mPendingMemState;
         int mPendingHighestMemState;
-        boolean mPendingSame;
+        float mPendingScalingFactor;
 
         public ProcStateMemTracker() {
             for (int i = PROC_MEM_PERSISTENT; i < PROC_MEM_NUM; i++) {
                 mHighestMem[i] = PROC_MEM_NUM;
+                mScalingFactor[i] = 1.0f;
             }
             mPendingMemState = -1;
         }
@@ -639,16 +640,22 @@
         public void dumpLine(PrintWriter pw) {
             pw.print("best=");
             pw.print(mTotalHighestMem);
-            pw.print(" ");
-            pw.print(mCurFactor);
-            pw.print("x (");
+            pw.print(" (");
+            boolean needSep = false;
             for (int i = 0; i < PROC_MEM_NUM; i++) {
-                if (i != 0) {
-                    pw.print(", ");
+                if (mHighestMem[i] < PROC_MEM_NUM) {
+                    if (needSep) {
+                        pw.print(", ");
+                        needSep = false;
+                    }
+                    pw.print(i);
+                    pw.print("=");
+                    pw.print(mHighestMem[i]);
+                    pw.print(" ");
+                    pw.print(mScalingFactor[i]);
+                    pw.print("x");
+                    needSep = true;
                 }
-                pw.print(i);
-                pw.print("=");
-                pw.print(mHighestMem[i]);
             }
             pw.print(")");
             if (mPendingMemState >= 0) {
@@ -656,8 +663,9 @@
                 pw.print(mPendingMemState);
                 pw.print(" highest=");
                 pw.print(mPendingHighestMemState);
-                pw.print(" same=");
-                pw.print(mPendingSame);
+                pw.print(" ");
+                pw.print(mPendingScalingFactor);
+                pw.print("x");
             }
             pw.println();
         }
@@ -674,12 +682,8 @@
     public static void commitNextPssTime(ProcStateMemTracker tracker) {
         if (tracker.mPendingMemState >= 0) {
             tracker.mHighestMem[tracker.mPendingMemState] = tracker.mPendingHighestMemState;
+            tracker.mScalingFactor[tracker.mPendingMemState] = tracker.mPendingScalingFactor;
             tracker.mTotalHighestMem = tracker.mPendingHighestMemState;
-            if (tracker.mPendingSame) {
-                tracker.mCurFactor *= 1.5f;
-            } else {
-                tracker.mCurFactor = 1;
-            }
             tracker.mPendingMemState = -1;
         }
     }
@@ -691,6 +695,7 @@
     public static long computeNextPssTime(int procState, ProcStateMemTracker tracker, boolean test,
             boolean sleeping, long now) {
         boolean first;
+        float scalingFactor;
         final int memState = sProcStateToProcMem[procState];
         if (tracker != null) {
             final int highestMemState = memState < tracker.mTotalHighestMem
@@ -698,9 +703,15 @@
             first = highestMemState < tracker.mHighestMem[memState];
             tracker.mPendingMemState = memState;
             tracker.mPendingHighestMemState = highestMemState;
-            tracker.mPendingSame = !first;
+            if (first) {
+                tracker.mPendingScalingFactor = scalingFactor = 1.0f;
+            } else {
+                scalingFactor = tracker.mScalingFactor[memState];
+                tracker.mPendingScalingFactor = scalingFactor * 1.5f;
+            }
         } else {
             first = true;
+            scalingFactor = 1.0f;
         }
         final long[] table = test
                 ? (first
@@ -709,8 +720,7 @@
                 : (first
                 ? (sleeping ? sFirstAsleepPssTimes : sFirstAwakePssTimes)
                 : (sleeping ? sSameAsleepPssTimes : sSameAwakePssTimes));
-        long delay = (long)(table[memState] * (tracker != null && !first
-                ? tracker.mCurFactor : 1.0f));
+        long delay = (long)(table[memState] * scalingFactor);
         if (delay > PSS_MAX_INTERVAL) {
             delay = PSS_MAX_INTERVAL;
         }
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 8bf320e..c10d81b 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -135,6 +135,7 @@
         return mMemFactorLowered;
     }
 
+    @GuardedBy("mAm")
     public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
         mMemFactorLowered = memFactor < mLastMemOnlyState;
         mLastMemOnlyState = memFactor;
@@ -237,6 +238,7 @@
             if (commit) {
                 mProcessStats.resetSafely();
                 updateFile();
+                mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
             }
             mLastWriteTime = SystemClock.uptimeMillis();
             totalTime = SystemClock.uptimeMillis() - now;
@@ -784,12 +786,14 @@
                 } else if ("--reset".equals(arg)) {
                     synchronized (mAm) {
                         mProcessStats.resetSafely();
+                        mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
                         pw.println("Process stats reset.");
                         quit = true;
                     }
                 } else if ("--clear".equals(arg)) {
                     synchronized (mAm) {
                         mProcessStats.resetSafely();
+                        mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
                         ArrayList<String> files = getCommittedFiles(0, true, true);
                         if (files != null) {
                             for (int fi=0; fi<files.size(); fi++) {
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index e7b067b..db4e09f 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.view.WindowManager.TRANSIT_NONE;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 
@@ -27,6 +28,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.os.Handler;
+import android.os.Trace;
 import android.view.IRecentsAnimationRunner;
 import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
 import com.android.server.wm.WindowManagerService;
@@ -70,6 +72,7 @@
 
     void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner,
             ComponentName recentsComponent, int recentsUid) {
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity");
         mWindowManager.deferSurfaceLayout();
         try {
             // Cancel the previous recents animation if necessary
@@ -124,6 +127,7 @@
             mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT);
         } finally {
             mWindowManager.continueSurfaceLayout();
+            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
         }
     }
 
@@ -134,6 +138,8 @@
             if (mWindowManager.getRecentsAnimationController() == null) return;
 
             mWindowManager.inSurfaceTransaction(() -> {
+                Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER,
+                        "RecentsAnimation#onAnimationFinished_inSurfaceTransaction");
                 mWindowManager.deferSurfaceLayout();
                 try {
                     mWindowManager.cleanupRecentsAnimation();
@@ -167,6 +173,7 @@
                     mWindowManager.executeAppTransition();
                 } finally {
                     mWindowManager.continueSurfaceLayout();
+                    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
                 }
             });
         }
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 7b0c714..d54e264 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -743,7 +743,7 @@
             mInjector.stackSupervisorRemoveUser(userId);
             // Remove the user if it is ephemeral.
             if (getUserInfo(userId).isEphemeral()) {
-                mInjector.getUserManager().removeUser(userId);
+                mInjector.getUserManager().removeUserEvenWhenDisallowed(userId);
             }
             // Evict the user's credential encryption key.
             try {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1825db8..e95608f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -23,6 +23,7 @@
 import static android.os.Process.FIRST_APPLICATION_UID;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -240,6 +241,7 @@
     private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
     private static final int MSG_INDICATE_SYSTEM_READY = 26;
     private static final int MSG_ACCESSORY_PLUG_MEDIA_UNMUTE = 27;
+    private static final int MSG_NOTIFY_VOL_EVENT = 28;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -283,7 +285,7 @@
     private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
 
    /** Maximum volume index values for audio streams */
-    private static int[] MAX_STREAM_VOLUME = new int[] {
+    protected static int[] MAX_STREAM_VOLUME = new int[] {
         5,  // STREAM_VOICE_CALL
         7,  // STREAM_SYSTEM
         7,  // STREAM_RING
@@ -298,7 +300,7 @@
     };
 
     /** Minimum volume index values for audio streams */
-    private static int[] MIN_STREAM_VOLUME = new int[] {
+    protected static int[] MIN_STREAM_VOLUME = new int[] {
         1,  // STREAM_VOICE_CALL
         0,  // STREAM_SYSTEM
         0,  // STREAM_RING
@@ -1334,11 +1336,9 @@
             extVolCtlr = mExtVolumeController;
         }
         if (extVolCtlr != null) {
-            try {
-                mExtVolumeController.notifyVolumeAdjust(direction);
-            } catch(RemoteException e) {
-                // nothing we can do about this. Do not log error, too much potential for spam
-            }
+            sendMsg(mAudioHandler, MSG_NOTIFY_VOL_EVENT, SENDMSG_QUEUE,
+                    direction, 0 /*ignored*/,
+                    extVolCtlr, 0 /*delay*/);
         } else {
             adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
                     caller, Binder.getCallingUid());
@@ -1410,7 +1410,7 @@
                 Binder.getCallingUid());
     }
 
-    private void adjustStreamVolume(int streamType, int direction, int flags,
+    protected void adjustStreamVolume(int streamType, int direction, int flags,
             String callingPackage, String caller, int uid) {
         if (mUseFixedVolume) {
             return;
@@ -5054,6 +5054,15 @@
                     state);
         }
 
+        private void onNotifyVolumeEvent(@NonNull IAudioPolicyCallback apc,
+                @AudioManager.VolumeAdjustment int direction) {
+            try {
+                apc.notifyVolumeAdjust(direction);
+            } catch(Exception e) {
+                // nothing we can do about this. Do not log error, too much potential for spam
+            }
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -5216,6 +5225,10 @@
                 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
                     onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
                     break;
+
+                case MSG_NOTIFY_VOL_EVENT:
+                    onNotifyVolumeEvent((IAudioPolicyCallback) msg.obj, msg.arg1);
+                    break;
             }
         }
     }
@@ -7296,6 +7309,12 @@
     //======================
     /**  */
     public int dispatchFocusChange(AudioFocusInfo afi, int focusChange, IAudioPolicyCallback pcb) {
+        if (afi == null) {
+            throw new IllegalArgumentException("Illegal null AudioFocusInfo");
+        }
+        if (pcb == null) {
+            throw new IllegalArgumentException("Illegal null AudioPolicy callback");
+        }
         synchronized (mAudioPolicies) {
             if (!mAudioPolicies.containsKey(pcb.asBinder())) {
                 throw new IllegalStateException("Unregistered AudioPolicy for focus dispatch");
@@ -7304,6 +7323,23 @@
         }
     }
 
+    public void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult,
+            IAudioPolicyCallback pcb) {
+        if (afi == null) {
+            throw new IllegalArgumentException("Illegal null AudioFocusInfo");
+        }
+        if (pcb == null) {
+            throw new IllegalArgumentException("Illegal null AudioPolicy callback");
+        }
+        synchronized (mAudioPolicies) {
+            if (!mAudioPolicies.containsKey(pcb.asBinder())) {
+                throw new IllegalStateException("Unregistered AudioPolicy for external focus");
+            }
+            mMediaFocusControl.setFocusRequestResultFromExtPolicy(afi, requestResult);
+        }
+    }
+
+
     //======================
     // misc
     //======================
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index f2ef02f..99f0840 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -241,15 +241,15 @@
 
 
     void release() {
+        final IBinder srcRef = mSourceRef;
+        final AudioFocusDeathHandler deathHdlr = mDeathHandler;
         try {
-            if (mSourceRef != null && mDeathHandler != null) {
-                mSourceRef.unlinkToDeath(mDeathHandler, 0);
-                mDeathHandler = null;
-                mFocusDispatcher = null;
+            if (srcRef != null && deathHdlr != null) {
+                srcRef.unlinkToDeath(deathHdlr, 0);
             }
-        } catch (java.util.NoSuchElementException e) {
-            Log.e(TAG, "FocusRequester.release() hit ", e);
-        }
+        } catch (java.util.NoSuchElementException e) { }
+        mDeathHandler = null;
+        mFocusDispatcher = null;
     }
 
     @Override
@@ -424,7 +424,7 @@
 
     int dispatchFocusChange(int focusChange) {
         if (mFocusDispatcher == null) {
-            if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: no focus dispatcher"); }
+            if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); }
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
         }
         if (focusChange == AudioManager.AUDIOFOCUS_NONE) {
@@ -445,12 +445,29 @@
         try {
             mFocusDispatcher.dispatchAudioFocusChange(focusChange, mClientId);
         } catch (android.os.RemoteException e) {
-            Log.v(TAG, "dispatchFocusChange: error talking to focus listener", e);
+            Log.e(TAG, "dispatchFocusChange: error talking to focus listener " + mClientId, e);
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
         }
         return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
     }
 
+    void dispatchFocusResultFromExtPolicy(int requestResult) {
+        if (mFocusDispatcher == null) {
+            if (MediaFocusControl.DEBUG) {
+                Log.e(TAG, "dispatchFocusResultFromExtPolicy: no focus dispatcher");
+            }
+        }
+        if (DEBUG) {
+            Log.v(TAG, "dispatching result" + requestResult + " to " + mClientId);
+        }
+        try {
+            mFocusDispatcher.dispatchFocusResultFromExtPolicy(requestResult, mClientId);
+        } catch (android.os.RemoteException e) {
+            Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener"
+                    + mClientId, e);
+        }
+    }
+
     AudioFocusInfo toAudioFocusInfo() {
         return new AudioFocusInfo(mAttributes, mCallingUid, mClientId, mPackageName,
                 mFocusGainRequest, mFocusLossReceived, mGrantFlags, mSdkTarget);
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 9ddc52a..d023bd7 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -83,6 +83,10 @@
 
     private boolean mRingOrCallActive = false;
 
+    private final Object mExtFocusChangeLock = new Object();
+    @GuardedBy("mExtFocusChangeLock")
+    private long mExtFocusChangeCounter;
+
     protected MediaFocusControl(Context cntxt, PlayerFocusEnforcer pfe) {
         mContext = cntxt;
         mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
@@ -521,7 +525,7 @@
      * @param requestResult
      * @return true if the external audio focus policy (if any) is handling the focus request
      */
-    boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi, int requestResult,
+    boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi,
             IAudioFocusDispatcher fd, IBinder cb) {
         if (mFocusPolicy == null) {
             return false;
@@ -530,6 +534,9 @@
             Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId()
             + " dispatcher=" + fd);
         }
+        synchronized (mExtFocusChangeLock) {
+            afi.setGen(mExtFocusChangeCounter++);
+        }
         final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
         if (existingFr != null) {
             if (!existingFr.hasSameDispatcher(fd)) {
@@ -538,8 +545,7 @@
                 mFocusOwnersForFocusPolicy.put(afi.getClientId(),
                         new FocusRequester(afi, fd, cb, hdlr, this));
             }
-        } else if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
-                 || requestResult == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
+        } else {
             // new focus (future) focus owner to keep track of
             final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
             mFocusOwnersForFocusPolicy.put(afi.getClientId(),
@@ -547,12 +553,25 @@
         }
         try {
             //oneway
-            mFocusPolicy.notifyAudioFocusRequest(afi, requestResult);
+            mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+            return true;
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call notifyAudioFocusRequest() on IAudioPolicyCallback "
                     + mFocusPolicy.asBinder(), e);
         }
-        return true;
+        return false;
+    }
+
+    void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult) {
+        synchronized (mExtFocusChangeLock) {
+            if (afi.getGen() > mExtFocusChangeCounter) {
+                return;
+            }
+        }
+        final FocusRequester fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
+        if (fr != null) {
+            fr.dispatchFocusResultFromExtPolicy(requestResult);
+        }
     }
 
     /**
@@ -590,7 +609,12 @@
                 if (DEBUG) { Log.v(TAG, "> failed: no focus policy" ); }
                 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
             }
-            final FocusRequester fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
+            final FocusRequester fr;
+            if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
+                fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId());
+            } else {
+                fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
+            }
             if (fr == null) {
                 if (DEBUG) { Log.v(TAG, "> failed: no such focus requester known" ); }
                 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
@@ -710,9 +734,7 @@
             boolean focusGrantDelayed = false;
             if (!canReassignAudioFocus()) {
                 if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
-                    final int result = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
-                    notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, result, fd, cb);
-                    return result;
+                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
                 } else {
                     // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be
                     // granted right now, so the requester will be inserted in the focus stack
@@ -721,12 +743,11 @@
                 }
             }
 
-            // external focus policy: delay request for focus gain?
-            final int resultWithExtPolicy = AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+            // external focus policy?
             if (notifyExtFocusPolicyFocusRequest_syncAf(
-                    afiForExtPolicy, resultWithExtPolicy, fd, cb)) {
+                    afiForExtPolicy, fd, cb)) {
                 // stop handling focus request here as it is handled by external audio focus policy
-                return resultWithExtPolicy;
+                return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
             }
 
             // handle the potential premature death of the new holder of the focus
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
index e77cb7a..2a9d386 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
@@ -98,10 +98,6 @@
     private native boolean nativeIsAnalogForced(long nativeContext);
     private native void nativeSetAnalogForced(long nativeContext, boolean isForced);
 
-    private native Map<String, String> nativeSetParameters(long nativeContext,
-            Map<String, String> parameters);
-    private native Map<String, String> nativeGetParameters(long nativeContext, List<String> keys);
-
     @Override
     public void close() {
         synchronized (mLock) {
@@ -291,26 +287,11 @@
 
     @Override
     public Map setParameters(Map parameters) {
-        Map<String, String> results;
-        synchronized (mLock) {
-            checkNotClosedLocked();
-            results = nativeSetParameters(mNativeContext, Objects.requireNonNull(parameters));
-        }
-        if (results == null) return Collections.emptyMap();
-        return results;
+        throw new UnsupportedOperationException("Not supported by HAL 1.x");
     }
 
     @Override
     public Map getParameters(List<String> keys) {
-        if (keys == null) {
-            throw new IllegalArgumentException("The argument must not be a null pointer");
-        }
-        Map<String, String> results;
-        synchronized (mLock) {
-            checkNotClosedLocked();
-            results = nativeGetParameters(mNativeContext, keys);
-        }
-        if (results == null) return Collections.emptyMap();
-        return results;
+        throw new UnsupportedOperationException("Not supported by HAL 1.x");
     }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 04c0e57..7ad73c3 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -169,7 +169,7 @@
 
     @Override
     public void onParametersUpdated(Map parameters) {
-        dispatch(() -> mClientCallback.onParametersUpdated(parameters));
+        Slog.e(TAG, "Not applicable for HAL 1.x");
     }
 
     @Override
diff --git a/services/core/java/com/android/server/car/CarServiceHelperService.java b/services/core/java/com/android/server/car/CarServiceHelperService.java
deleted file mode 100644
index 9392a6a..0000000
--- a/services/core/java/com/android/server/car/CarServiceHelperService.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.car;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Slog;
-
-import com.android.internal.car.ICarServiceHelper;
-import com.android.server.SystemService;
-
-/**
- * System service side companion service for CarService.
- * Starts car service and provide necessary API for CarService. Only for car product.
- */
-public class CarServiceHelperService extends SystemService {
-    private static final String TAG = "CarServiceHelper";
-    private static final String CAR_SERVICE_INTERFACE = "android.car.ICar";
-    private final ICarServiceHelperImpl mHelper = new ICarServiceHelperImpl();
-    private IBinder mCarService;
-    private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
-
-        @Override
-        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
-            Slog.i(TAG, "**CarService connected**");
-            mCarService = iBinder;
-            // Cannot depend on ICar which is defined in CarService, so handle binder call directly
-            // instead.
-            // void setCarServiceHelper(in IBinder helper)
-            Parcel data = Parcel.obtain();
-            data.writeInterfaceToken(CAR_SERVICE_INTERFACE);
-            data.writeStrongBinder(mHelper.asBinder());
-            try {
-                mCarService.transact(IBinder.FIRST_CALL_TRANSACTION, // setCarServiceHelper
-                        data, null, Binder.FLAG_ONEWAY);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException from car service", e);
-                handleCarServiceCrash();
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName componentName) {
-            handleCarServiceCrash();
-        }
-    };
-
-    public CarServiceHelperService(Context context) {
-        super(context);
-    }
-
-    @Override
-    public void onStart() {
-        Intent intent = new Intent();
-        intent.setPackage("com.android.car");
-        intent.setAction(CAR_SERVICE_INTERFACE);
-        if (!getContext().bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE,
-                UserHandle.SYSTEM)) {
-            Slog.wtf(TAG, "cannot start car service");
-        }
-    }
-
-    private void handleCarServiceCrash() {
-        //TODO define recovery bahavior
-    }
-
-    private class ICarServiceHelperImpl extends ICarServiceHelper.Stub {
-        //TODO
-    }
-}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 1ee0548..c3f020a 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1116,6 +1116,7 @@
         return (pi != null) ? pi.packageName : null;
     }
 
+    @GuardedBy("mCache")
     private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId,
             String providerPackageName) {
         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
@@ -1131,6 +1132,7 @@
         return packageCache;
     }
 
+    @GuardedBy("mCache")
     private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) {
         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
         if (userCache == null) return;
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index 51499f7..9980930 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -137,11 +137,13 @@
                             + " params=" + jobParametersToString(params));
                 }
             } else if (runtime < 10 * 1000) {
-                // Job stopped too soon. WTF.
-                wtf("Job " + jobId + " stopped in " + runtime + " ms: "
-                        + " startUptime=" + startUptime
-                        + " nowUptime=" + nowUptime
-                        + " params=" + jobParametersToString(params));
+                // This happens too in a normal case too, and it's rather too often.
+                // Disable it for now.
+//                // Job stopped too soon. WTF.
+//                wtf("Job " + jobId + " stopped in " + runtime + " ms: "
+//                        + " startUptime=" + startUptime
+//                        + " nowUptime=" + nowUptime
+//                        + " params=" + jobParametersToString(params));
             }
 
             mStartedSyncs.delete(jobId);
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
index 75c0181..20aec7e 100644
--- a/services/core/java/com/android/server/content/SyncLogger.java
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -194,6 +194,7 @@
             }
         }
 
+        @GuardedBy("mLock")
         private void openLogLocked(long now) {
             // If we already have a log file opened and the date has't changed, just use it.
             final long day = now % DateUtils.DAY_IN_MILLIS;
@@ -219,6 +220,7 @@
             }
         }
 
+        @GuardedBy("mLock")
         private void closeCurrentLogLocked() {
             IoUtils.closeQuietly(mLogWriter);
             mLogWriter = null;
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 6b4666a..524de91 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -115,12 +115,10 @@
             = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS);
     @GuardedBy("mEventsLock")
     private boolean mEventsDirty;
-    private final Runnable mEventsWriter = () -> writeEvents();
-    private volatile boolean mWriteEventsScheduled;
+
+    private volatile boolean mWriteBrightnessTrackerStateScheduled;
 
     private AmbientBrightnessStatsTracker mAmbientBrightnessStatsTracker;
-    private final Runnable mAmbientBrightnessStatsWriter = () -> writeAmbientBrightnessStats();
-    private volatile boolean mWriteBrightnessStatsScheduled;
 
     private UserManager mUserManager;
     private final Context mContext;
@@ -167,13 +165,7 @@
         }
         mBgHandler = new TrackerHandler(mInjector.getBackgroundHandler().getLooper());
         mUserManager = mContext.getSystemService(UserManager.class);
-        try {
-            final ActivityManager.StackInfo focusedStack = mInjector.getFocusedStack();
-            mCurrentUserId = focusedStack.userId;
-        } catch (RemoteException e) {
-            // Really shouldn't be possible.
-            return;
-        }
+        mCurrentUserId = ActivityManager.getCurrentUser();
         mBgHandler.obtainMessage(MSG_BACKGROUND_START, (Float) initialBrightness).sendToTarget();
     }
 
@@ -355,18 +347,17 @@
     }
 
     private void scheduleWriteBrightnessTrackerState() {
-        if (!mWriteEventsScheduled) {
-            mBgHandler.post(mEventsWriter);
-            mWriteEventsScheduled = true;
-        }
-        if (!mWriteBrightnessStatsScheduled) {
-            mBgHandler.post(mAmbientBrightnessStatsWriter);
-            mWriteBrightnessStatsScheduled = true;
+        if (!mWriteBrightnessTrackerStateScheduled) {
+            mBgHandler.post(() -> {
+                mWriteBrightnessTrackerStateScheduled = false;
+                writeEvents();
+                writeAmbientBrightnessStats();
+            });
+            mWriteBrightnessTrackerStateScheduled = true;
         }
     }
 
     private void writeEvents() {
-        mWriteEventsScheduled = false;
         synchronized (mEventsLock) {
             if (!mEventsDirty) {
                 // Nothing to write
@@ -398,7 +389,6 @@
     }
 
     private void writeAmbientBrightnessStats() {
-        mWriteBrightnessStatsScheduled = false;
         final AtomicFile writeTo = mInjector.getFile(AMBIENT_BRIGHTNESS_STATS_FILE);
         if (writeTo == null) {
             return;
@@ -642,6 +632,7 @@
             }
         }
         if (mAmbientBrightnessStatsTracker != null) {
+            pw.println();
             mAmbientBrightnessStatsTracker.dump(pw);
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index b27f1ec..23de592 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -51,7 +51,6 @@
 import android.provider.Settings;
 import android.util.MathUtils;
 import android.util.Slog;
-import android.util.Spline;
 import android.util.TimeUtils;
 import android.view.Display;
 
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java b/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
index 0976a22..b0cde2d 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
@@ -202,6 +202,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void readStateSyncLocked() {
         FileInputStream in;
         if (!mFile.exists()) {
@@ -226,6 +227,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void parseStateLocked(XmlPullParser parser)
             throws IOException, XmlPullParserException {
         final int outerDepth = parser.getDepth();
@@ -243,6 +245,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void parseFingerprintsLocked(XmlPullParser parser)
             throws IOException, XmlPullParserException {
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 1e09383..de0f298 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1299,6 +1299,7 @@
     /**
      * Return external input devices.
      */
+    @GuardedBy("mLock")
     List<HdmiDeviceInfo> getSafeExternalInputsLocked() {
         return mSafeExternalInputs;
     }
@@ -1421,6 +1422,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     List<HdmiDeviceInfo> getSafeCecDevicesLocked() {
         ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
         for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 3d079cc..b06dba9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1097,6 +1097,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private List<HdmiDeviceInfo> getMhlDevicesLocked() {
         return mMhlDevices;
     }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 401c05e..47a4fb2 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -40,7 +40,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.Intent.UriFlags;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
@@ -79,7 +78,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.DeviceIdleController;
 import com.android.server.FgThread;
-import com.android.server.ForceAppStandbyTracker;
+import com.android.server.AppStateTracker;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
@@ -184,7 +183,7 @@
     ActivityManagerInternal mActivityManagerInternal;
     IBatteryStats mBatteryStats;
     DeviceIdleController.LocalService mLocalDeviceIdleController;
-    final ForceAppStandbyTracker mForceAppStandbyTracker;
+    AppStateTracker mAppStateTracker;
 
     /**
      * Set to true once we are allowed to run third party apps.
@@ -787,20 +786,13 @@
     }
 
     /**
-     * Return whether an UID is in the foreground or not.
+     * Return whether an UID is active or idle.
      */
-    private boolean isUidInForeground(int uid) {
-        synchronized (mLock) {
-            if (mUidPriorityOverride.get(uid, 0) > 0) {
-                return true;
-            }
-        }
-        // Note UID observer may not be called in time, so we always check with the AM.
-        return mActivityManagerInternal.getUidProcessState(uid)
-                <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+    private boolean isUidActive(int uid) {
+        return mAppStateTracker.isUidActiveSynced(uid);
     }
 
-    private final Predicate<Integer> mIsUidInForegroundPredicate = this::isUidInForeground;
+    private final Predicate<Integer> mIsUidActivePredicate = this::isUidActive;
 
     public int scheduleAsPackage(JobInfo job, JobWorkItem work, int uId, String packageName,
             int userId, String tag) {
@@ -826,7 +818,7 @@
 
                     // If any of work item is enqueued when the source is in the foreground,
                     // exempt the entire job.
-                    toCancel.maybeAddForegroundExemption(mIsUidInForegroundPredicate);
+                    toCancel.maybeAddForegroundExemption(mIsUidActivePredicate);
 
                     return JobScheduler.RESULT_SUCCESS;
                 }
@@ -838,7 +830,7 @@
             // Note if it's a sync job, this method is called on the handler so it's not exactly
             // the state when requestSync() was called, but that should be fine because of the
             // 1 minute foreground grace period.
-            jobStatus.maybeAddForegroundExemption(mIsUidInForegroundPredicate);
+            jobStatus.maybeAddForegroundExemption(mIsUidActivePredicate);
 
             if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
             // Jobs on behalf of others don't apply to the per-app job cap
@@ -1123,8 +1115,6 @@
         mDeviceIdleJobsController = DeviceIdleJobsController.get(this);
         mControllers.add(mDeviceIdleJobsController);
 
-        mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
-
         // If the job store determined that it can't yet reschedule persisted jobs,
         // we need to start watching the clock.
         if (!mJobs.jobTimesInflatedValid()) {
@@ -1185,7 +1175,8 @@
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
             mConstants.start(getContext().getContentResolver());
 
-            mForceAppStandbyTracker.start();
+            mAppStateTracker = Preconditions.checkNotNull(
+                    LocalServices.getService(AppStateTracker.class));
 
             // Register br for package removals and user removals.
             final IntentFilter filter = new IntentFilter();
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 37b3990..4988974 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -295,10 +295,12 @@
     }
 
     /** Called externally when a job that was scheduled for execution should be cancelled. */
+    @GuardedBy("mLock")
     void cancelExecutingJobLocked(int reason, String debugReason) {
         doCancelLocked(reason, debugReason);
     }
 
+    @GuardedBy("mLock")
     void preemptExecutingJobLocked() {
         doCancelLocked(JobParameters.REASON_PREEMPT, "cancelled due to preemption");
     }
@@ -319,6 +321,7 @@
         return mTimeoutElapsed;
     }
 
+    @GuardedBy("mLock")
     boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId,
             String reason) {
         final JobStatus executing = getRunningJobLocked();
@@ -512,6 +515,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void doServiceBoundLocked() {
         removeOpTimeOutLocked();
         handleServiceBoundLocked();
@@ -531,6 +535,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void doCallbackLocked(boolean reschedule, String reason) {
         if (DEBUG) {
             Slog.d(TAG, "doCallback of : " + mRunningJob
@@ -550,6 +555,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void doCancelLocked(int arg1, String debugReason) {
         if (mVerb == VERB_FINISHED) {
             if (DEBUG) {
@@ -567,6 +573,7 @@
     }
 
     /** Start the job on the service. */
+    @GuardedBy("mLock")
     private void handleServiceBoundLocked() {
         if (DEBUG) {
             Slog.d(TAG, "handleServiceBound for " + getRunningJobNameLocked());
@@ -605,6 +612,7 @@
      *     _EXECUTING  -> Error
      *     _STOPPING   -> Error
      */
+    @GuardedBy("mLock")
     private void handleStartedLocked(boolean workOngoing) {
         switch (mVerb) {
             case VERB_STARTING:
@@ -637,6 +645,7 @@
      *     _STARTING   -> Error
      *     _PENDING    -> Error
      */
+    @GuardedBy("mLock")
     private void handleFinishedLocked(boolean reschedule, String reason) {
         switch (mVerb) {
             case VERB_EXECUTING:
@@ -659,6 +668,7 @@
      *                      in the message queue.
      *     _ENDING     -> No point in doing anything here, so we ignore.
      */
+    @GuardedBy("mLock")
     private void handleCancelLocked(String reason) {
         if (JobSchedulerService.DEBUG) {
             Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " "
@@ -683,6 +693,7 @@
     }
 
     /** Process MSG_TIMEOUT here. */
+    @GuardedBy("mLock")
     private void handleOpTimeoutLocked() {
         switch (mVerb) {
             case VERB_BINDING:
@@ -722,6 +733,7 @@
      * Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING ->
      * VERB_STOPPING.
      */
+    @GuardedBy("mLock")
     private void sendStopMessageLocked(String reason) {
         removeOpTimeOutLocked();
         if (mVerb != VERB_EXECUTING) {
@@ -747,6 +759,7 @@
      * or from acknowledging the stop message we sent. Either way, we're done tracking it and
      * we want to clean up internally.
      */
+    @GuardedBy("mLock")
     private void closeAndCleanupJobLocked(boolean reschedule, String reason) {
         final JobStatus completedJob;
         if (mVerb == VERB_FINISHED) {
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 5eb7700..e8057fb 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -22,8 +22,10 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.server.ForceAppStandbyTracker;
-import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.internal.util.Preconditions;
+import com.android.server.AppStateTracker;
+import com.android.server.AppStateTracker.Listener;
+import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobStore;
 import com.android.server.job.StateControllerProto;
@@ -42,8 +44,7 @@
 
     private final JobSchedulerService mJobSchedulerService;
 
-    private final ForceAppStandbyTracker mForceAppStandbyTracker;
-
+    private final AppStateTracker mAppStateTracker;
 
     public static BackgroundJobsController get(JobSchedulerService service) {
         synchronized (sCreationLock) {
@@ -59,10 +60,9 @@
         super(service, context, lock);
         mJobSchedulerService = service;
 
-        mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
-
-        mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
-        mForceAppStandbyTracker.start();
+        mAppStateTracker = Preconditions.checkNotNull(
+                LocalServices.getService(AppStateTracker.class));
+        mAppStateTracker.addListener(mForceAppStandbyListener);
     }
 
     @Override
@@ -79,7 +79,7 @@
     public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
         pw.println("BackgroundJobsController");
 
-        mForceAppStandbyTracker.dump(pw, "");
+        mAppStateTracker.dump(pw, "");
 
         pw.println("Job state:");
         mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
@@ -92,16 +92,16 @@
             jobStatus.printUniqueId(pw);
             pw.print(" from ");
             UserHandle.formatUid(pw, uid);
-            pw.print(mForceAppStandbyTracker.isUidActive(uid) ? " active" : " idle");
-            if (mForceAppStandbyTracker.isUidPowerSaveWhitelisted(uid) ||
-                    mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(uid)) {
+            pw.print(mAppStateTracker.isUidActive(uid) ? " active" : " idle");
+            if (mAppStateTracker.isUidPowerSaveWhitelisted(uid) ||
+                    mAppStateTracker.isUidTempPowerSaveWhitelisted(uid)) {
                 pw.print(", whitelisted");
             }
             pw.print(": ");
             pw.print(sourcePkg);
 
             pw.print(" [RUN_ANY_IN_BACKGROUND ");
-            pw.print(mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(uid, sourcePkg)
+            pw.print(mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, sourcePkg)
                     ? "allowed]" : "disallowed]");
 
             if ((jobStatus.satisfiedConstraints
@@ -118,7 +118,7 @@
         final long token = proto.start(fieldId);
         final long mToken = proto.start(StateControllerProto.BACKGROUND);
 
-        mForceAppStandbyTracker.dumpProto(proto,
+        mAppStateTracker.dumpProto(proto,
                 StateControllerProto.BackgroundJobsController.FORCE_APP_STANDBY_TRACKER);
 
         mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
@@ -136,14 +136,14 @@
             proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg);
 
             proto.write(TrackedJob.IS_IN_FOREGROUND,
-                    mForceAppStandbyTracker.isUidActive(sourceUid));
+                    mAppStateTracker.isUidActive(sourceUid));
             proto.write(TrackedJob.IS_WHITELISTED,
-                    mForceAppStandbyTracker.isUidPowerSaveWhitelisted(sourceUid) ||
-                    mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(sourceUid));
+                    mAppStateTracker.isUidPowerSaveWhitelisted(sourceUid) ||
+                    mAppStateTracker.isUidTempPowerSaveWhitelisted(sourceUid));
 
             proto.write(
                     TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
-                    mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(
+                    mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(
                             sourceUid, sourcePkg));
 
             proto.write(
@@ -197,7 +197,7 @@
         final int uid = jobStatus.getSourceUid();
         final String packageName = jobStatus.getSourcePackageName();
 
-        final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName,
+        final boolean canRun = !mAppStateTracker.areJobsRestricted(uid, packageName,
                 (jobStatus.getInternalFlags() & JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION)
                         != 0);
 
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 373d87d..77e813e 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -92,6 +92,7 @@
         mNetPolicyManager.registerListener(mNetPolicyListener);
     }
 
+    @GuardedBy("mLock")
     @Override
     public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
         if (jobStatus.hasConnectivityConstraint()) {
@@ -101,6 +102,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     @Override
     public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
             boolean forUpdate) {
@@ -325,13 +327,16 @@
         }
     };
 
+    @GuardedBy("mLock")
     @Override
     public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
         pw.print("Connectivity: connected=");
-        pw.print(mConnected);
+        pw.println(mConnected);
+
         pw.print("Tracking ");
         pw.print(mTrackedJobs.size());
-        pw.println(":");
+        pw.println(" jobs");
+
         for (int i = 0; i < mTrackedJobs.size(); i++) {
             final JobStatus js = mTrackedJobs.valueAt(i);
             if (js.shouldDump(filterUid)) {
@@ -339,11 +344,14 @@
                 js.printUniqueId(pw);
                 pw.print(" from ");
                 UserHandle.formatUid(pw, js.getSourceUid());
-                pw.print(": "); pw.print(js.getJob().getRequiredNetwork());
+                pw.print(": ");
+                pw.print(js.getJob().getRequiredNetwork());
+                pw.println();
             }
         }
     }
 
+    @GuardedBy("mLock")
     @Override
     public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
         final long token = proto.start(fieldId);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 55c0f5a..3e43d8e 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -206,7 +206,7 @@
     private static final int UPDATE_NETWORK_STATE = 4;
     private static final int INJECT_NTP_TIME = 5;
     private static final int DOWNLOAD_XTRA_DATA = 6;
-    private static final int UPDATE_LOCATION = 7;
+    private static final int UPDATE_LOCATION = 7;  // Handle external location from network listener
     private static final int ADD_LISTENER = 8;
     private static final int REMOVE_LISTENER = 9;
     private static final int INJECT_NTP_TIME_FINISHED = 10;
@@ -259,6 +259,42 @@
         }
     }
 
+    // Simple class to hold stats reported in the Extras Bundle
+    private static class LocationExtras {
+        private int mSvCount;
+        private int mMeanCn0;
+        private int mMaxCn0;
+        private final Bundle mBundle;
+
+        public LocationExtras() {
+            mBundle = new Bundle();
+        }
+
+        public void set(int svCount, int meanCn0, int maxCn0) {
+            mSvCount = svCount;
+            mMeanCn0 = meanCn0;
+            mMaxCn0 = maxCn0;
+            setBundle(mBundle);
+        }
+
+        public void reset() {
+            set(0,0,0);
+        }
+
+        // Also used by outside methods to add to other bundles
+        public void setBundle(Bundle extras) {
+            if (extras != null) {
+                extras.putInt("satellites", mSvCount);
+                extras.putInt("meanCn0", mMeanCn0);
+                extras.putInt("maxCn0", mMaxCn0);
+            }
+        }
+
+        public Bundle getBundle() {
+            return mBundle;
+        }
+    }
+
     private Object mLock = new Object();
 
     // current status
@@ -369,7 +405,7 @@
     private final NtpTrustedTime mNtpTime;
     private final ILocationManager mILocationManager;
     private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
-    private Bundle mLocationExtras = new Bundle();
+    private final LocationExtras mLocationExtras = new LocationExtras();
     private final GnssStatusListenerHelper mListenerHelper;
     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
@@ -713,7 +749,7 @@
         mNtpTime = NtpTrustedTime.getInstance(context);
         mILocationManager = ilocationManager;
 
-        mLocation.setExtras(mLocationExtras);
+        mLocation.setExtras(mLocationExtras.getBundle());
 
         // Create a wake lock
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -1245,29 +1281,17 @@
 
     @Override
     public int getStatus(Bundle extras) {
-        setLocationExtras(extras);
+        mLocationExtras.setBundle(extras);
         return mStatus;
     }
 
-    private void updateStatus(int status, int svCount, int meanCn0, int maxCn0) {
-        if (status != mStatus || svCount != mSvCount || meanCn0 != mMeanCn0 || maxCn0 != mMaxCn0) {
+    private void updateStatus(int status) {
+        if (status != mStatus) {
             mStatus = status;
-            mSvCount = svCount;
-            mMeanCn0 = meanCn0;
-            mMaxCn0 = maxCn0;
-            setLocationExtras(mLocationExtras);
             mStatusUpdateTime = SystemClock.elapsedRealtime();
         }
     }
 
-    private void setLocationExtras(Bundle extras) {
-        if (extras != null) {
-            extras.putInt("satellites", mSvCount);
-            extras.putInt("meanCn0", mMeanCn0);
-            extras.putInt("maxCn0", mMaxCn0);
-        }
-    }
-
     @Override
     public long getStatusUpdateTime() {
         return mStatusUpdateTime;
@@ -1563,7 +1587,8 @@
             }
 
             // reset SV count to zero
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
+            mLocationExtras.reset();
             mFixRequestTime = SystemClock.elapsedRealtime();
             if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
                 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
@@ -1586,7 +1611,8 @@
             mLastFixTime = 0;
 
             // reset SV count to zero
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
+            mLocationExtras.reset();
         }
     }
 
@@ -1626,7 +1652,7 @@
             // It would be nice to push the elapsed real-time timestamp
             // further down the stack, but this is still useful
             mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
-            mLocation.setExtras(mLocationExtras);
+            mLocation.setExtras(mLocationExtras.getBundle());
 
             try {
                 mILocationManager.reportLocation(mLocation, false);
@@ -1662,8 +1688,9 @@
         }
 
         if (mStarted && mStatus != LocationProvider.AVAILABLE) {
-            // we want to time out if we do not receive a fix
-            // within the time out and we are requesting infrequent fixes
+            // For devices that use framework scheduling, a timer may be set to ensure we don't
+            // spend too much power searching for a location, when the requested update rate is slow.
+            // As we just recievied a location, we'll cancel that timer.
             if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
                 mAlarmManager.cancel(mTimeoutIntent);
             }
@@ -1672,7 +1699,7 @@
             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            updateStatus(LocationProvider.AVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
+            updateStatus(LocationProvider.AVAILABLE);
         }
 
         if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
@@ -1771,7 +1798,7 @@
             meanCn0 /= usedInFixCount;
         }
         // return number of sats used in fix instead of total reported
-        updateStatus(mStatus, usedInFixCount, meanCn0, maxCn0);
+        mLocationExtras.set(usedInFixCount, meanCn0, maxCn0);
 
         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
                 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
@@ -1779,7 +1806,7 @@
             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
         }
     }
 
@@ -2726,9 +2753,6 @@
     private float mSvElevations[] = new float[MAX_SVS];
     private float mSvAzimuths[] = new float[MAX_SVS];
     private float mSvCarrierFreqs[] = new float[MAX_SVS];
-    private int mSvCount;
-    private int mMeanCn0;
-    private int mMaxCn0;
     // preallocated to avoid memory allocation in reportNmea()
     private byte[] mNmeaBuffer = new byte[120];
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index e715724..6deff36 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2236,9 +2236,10 @@
      *     This happens during a normal migration case when the user currently has password.
      *
      * 2. credentialhash == null and credential == null
-     *     A new SP blob and a new SID will be created, while the user has no credentials.
+     *     A new SP blob and will be created, while the user has no credentials.
      *     This can happens when we are activating an escrow token on a unsecured device, during
      *     which we want to create the SP structure with an empty user credential.
+     *     This could also happen during an untrusted reset to clear password.
      *
      * 3. credentialhash == null and credential != null
      *     This is the untrusted credential reset, OR the user sets a new lockscreen password
@@ -2250,16 +2251,8 @@
             String credential, int credentialType, int requestedQuality,
             int userId) throws RemoteException {
         Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
-        // Load from the cache or a make a new one
-        AuthenticationToken auth = mSpCache.get(userId);
-        if (auth != null) {
-            // If the synthetic password has been cached, we can only be in case 3., described
-            // above, for an untrusted credential reset so a new SID is still needed.
-            mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
-        } else {
-            auth = mSpManager.newSyntheticPasswordAndSid(getGateKeeperService(),
-                      credentialHash, credential, userId);
-        }
+        final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
+                getGateKeeperService(), credentialHash, credential, userId);
         onAuthTokenKnownForUser(userId, auth);
         if (auth == null) {
             Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
@@ -2473,36 +2466,41 @@
                             : "pattern"));
         }
 
+        boolean untrustedReset = false;
         if (auth != null) {
-            // We are performing a trusted credential change i.e. a correct existing credential
-            // is provided
-            setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, requestedQuality,
-                    userId);
-            mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
             onAuthTokenKnownForUser(userId, auth);
         } else if (response != null
                 && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
-            // We are performing an untrusted credential change i.e. by DevicePolicyManager.
-            // So provision a new SP and SID. This would invalidate existing escrow tokens.
-            // Still support this for now but this flow will be removed in the next release.
+            // We are performing an untrusted credential change, by DevicePolicyManager or other
+            // internal callers that don't provide the existing credential
             Slog.w(TAG, "Untrusted credential change invoked");
-
-            if (mSpCache.get(userId) == null) {
-                throw new IllegalStateException(
-                        "Untrusted credential reset not possible without cached SP");
-            }
-
-            initializeSyntheticPasswordLocked(null, credential, credentialType, requestedQuality,
-                    userId);
-            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
-            mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
-
-            notifyActivePasswordMetricsAvailable(credential, userId);
+            // Try to get a cached auth token, so we can keep SP unchanged.
+            auth = mSpCache.get(userId);
+            untrustedReset = true;
         } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
             Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
                     (response != null ? "rate limit exceeded" : "failed"));
             return;
         }
+
+        if (auth != null) {
+            if (untrustedReset) {
+                // Force change the current SID to mantain existing behaviour that an untrusted
+                // reset leads to a change of SID. If the untrusted reset is for clearing the
+                // current password, the nuking of the SID will be done in
+                // setLockCredentialWithAuthTokenLocked next
+                mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
+            }
+            setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, requestedQuality,
+                    userId);
+            mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
+        } else {
+            throw new IllegalStateException(
+                    "Untrusted credential reset not possible without cached SP");
+            // Could call initializeSyntheticPasswordLocked(null, credential, credentialType,
+            // requestedQuality, userId) instead if we still allow untrusted reset that changes
+            // synthetic password. That would invalidate existing escrow tokens though.
+        }
         mRecoverableKeyStoreManager.lockScreenSecretChanged(credentialType, credential, userId);
     }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 662ffc8..dee24c7 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -44,6 +44,7 @@
 import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
+import java.security.cert.CertPath;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -176,8 +177,17 @@
             return;
         }
 
-        PublicKey publicKey = mRecoverableKeyStoreDb.getRecoveryServicePublicKey(mUserId,
+        PublicKey publicKey;
+        CertPath certPath = mRecoverableKeyStoreDb.getRecoveryServiceCertPath(mUserId,
                 recoveryAgentUid);
+        if (certPath != null) {
+            Log.d(TAG, "Using the public key in stored CertPath for syncing");
+            publicKey = certPath.getCertificates().get(0).getPublicKey();
+        } else {
+            Log.d(TAG, "Using the stored raw public key for syncing");
+            publicKey = mRecoverableKeyStoreDb.getRecoveryServicePublicKey(mUserId,
+                    recoveryAgentUid);
+        }
         if (publicKey == null) {
             Log.w(TAG, "Not initialized for KeySync: no public key set. Cancelling task.");
             return;
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 3a78f95..e5ff5b8 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -194,6 +194,9 @@
            UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
         init(userId);
         try {
+            // Try to see if the decryption key is still accessible before using the encryption key.
+            // The auth-bound decryption will be unrecoverable if the screen lock is disabled.
+            getDecryptKeyInternal(userId);
             return getEncryptKeyInternal(userId);
         } catch (UnrecoverableKeyException e) {
             Log.i(TAG, String.format(Locale.US,
@@ -219,7 +222,7 @@
            UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
         int generationId = getGenerationId(userId);
         String alias = getEncryptAlias(userId, generationId);
-        if (!mKeyStore.containsAlias(alias)) {
+        if (!isKeyLoaded(userId, generationId)) {
             throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias);
         }
         AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
@@ -268,7 +271,7 @@
            UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
         int generationId = getGenerationId(userId);
         String alias = getDecryptAlias(userId, generationId);
-        if (!mKeyStore.containsAlias(alias)) {
+        if (!isKeyLoaded(userId, generationId)) {
             throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias);
         }
         AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
@@ -300,12 +303,12 @@
             return;
         }
         if (generationId == -1) {
-            Log.i(TAG, "Generating initial platform ID.");
+            Log.i(TAG, "Generating initial platform key generation ID.");
             generationId = 1;
         } else {
             Log.w(TAG, String.format(Locale.US, "Platform generation ID was %d but no "
                     + "entry was present in AndroidKeyStore. Generating fresh key.", generationId));
-            // Had to generate a fresh key, bump the generation id
+            // Have to generate a fresh key, so bump the generation id
             generationId++;
         }
 
@@ -374,7 +377,7 @@
         String decryptAlias = getDecryptAlias(userId, generationId);
         SecretKey secretKey = generateAesKey();
 
-        // Store Since decryption key first since it is more likely to fail.
+        // Store decryption key first since it is more likely to fail.
         mKeyStore.setEntry(
                 decryptAlias,
                 new KeyStore.SecretKeyEntry(secretKey),
@@ -386,7 +389,6 @@
                     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                     .setBoundToSpecificSecureUserId(userId)
                     .build());
-
         mKeyStore.setEntry(
                 encryptAlias,
                 new KeyStore.SecretKeyEntry(secretKey),
@@ -397,11 +399,7 @@
 
         setGenerationId(userId, generationId);
 
-        try {
-            secretKey.destroy();
-        } catch (DestroyFailedException e) {
-            Log.w(TAG, "Failed to destroy in-memory platform key.", e);
-        }
+        // TODO: Use a reliable way to destroy the temporary secretKey in memory.
     }
 
     /**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index fda6cdf..9f82268 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -23,16 +23,15 @@
 import static android.security.keystore.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
 import static android.security.keystore.RecoveryController.ERROR_SESSION_EXPIRED;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.Manifest;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
-
 import android.security.keystore.recovery.KeyChainProtectionParams;
 import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.RecoveryController;
@@ -43,6 +42,10 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.HexDump;
 import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage;
+import com.android.server.locksettings.recoverablekeystore.certificate.CertParsingException;
+import com.android.server.locksettings.recoverablekeystore.certificate.CertValidationException;
+import com.android.server.locksettings.recoverablekeystore.certificate.CertXml;
+import com.android.server.locksettings.recoverablekeystore.certificate.TrustedRootCert;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
@@ -52,8 +55,10 @@
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
-import java.security.spec.InvalidKeySpecException;
 import java.security.UnrecoverableKeyException;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateEncodingException;
+import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -152,18 +157,67 @@
     }
 
     public void initRecoveryService(
-            @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
+            @NonNull String rootCertificateAlias, @NonNull byte[] recoveryServiceCertFile)
             throws RemoteException {
         checkRecoverKeyStorePermission();
         int userId = UserHandle.getCallingUserId();
         int uid = Binder.getCallingUid();
-        // TODO: open /system/etc/security/... cert file, and check the signature on the public keys
-        PublicKey publicKey;
+
+        // TODO: Check the public-key signature on the whole file before parsing it
+
+        CertXml certXml;
+        try {
+            certXml = CertXml.parse(recoveryServiceCertFile);
+        } catch (CertParsingException e) {
+            // TODO: Do not use raw key bytes anymore once the other components are updated
+            Log.d(TAG, "Failed to parse the cert file", e);
+            PublicKey publicKey = parseEcPublicKey(recoveryServiceCertFile);
+            if (mDatabase.setRecoveryServicePublicKey(userId, uid, publicKey) > 0) {
+                mDatabase.setShouldCreateSnapshot(userId, uid, true);
+            }
+            return;
+        }
+
+        // Check serial number
+        long newSerial = certXml.getSerial();
+        Long oldSerial = mDatabase.getRecoveryServiceCertSerial(userId, uid);
+        if (oldSerial != null && oldSerial >= newSerial) {
+            if (oldSerial == newSerial) {
+                Log.i(TAG, "The cert file serial number is the same, so skip updating.");
+            } else {
+                Log.e(TAG, "The cert file serial number is older than the one in database.");
+            }
+            return;
+        }
+        Log.i(TAG, "Updating the certificate with the new serial number " + newSerial);
+
+        CertPath certPath;
+        try {
+            Log.d(TAG, "Getting and validating a random endpoint certificate");
+            certPath = certXml.getRandomEndpointCert(TrustedRootCert.TRUSTED_ROOT_CERT);
+        } catch (CertValidationException e) {
+            Log.e(TAG, "Invalid endpoint cert", e);
+            throw new ServiceSpecificException(
+                    ERROR_BAD_CERTIFICATE_FORMAT, "Failed to validate certificate.");
+        }
+        try {
+            Log.d(TAG, "Saving the randomly chosen endpoint certificate to database");
+            if (mDatabase.setRecoveryServiceCertPath(userId, uid, certPath) > 0) {
+                mDatabase.setRecoveryServiceCertSerial(userId, uid, newSerial);
+                mDatabase.setShouldCreateSnapshot(userId, uid, true);
+            }
+        } catch (CertificateEncodingException e) {
+            Log.e(TAG, "Failed to encode CertPath", e);
+            throw new ServiceSpecificException(
+                    ERROR_BAD_CERTIFICATE_FORMAT, "Failed to encode CertPath.");
+        }
+    }
+
+    private PublicKey parseEcPublicKey(@NonNull byte[] bytes) throws ServiceSpecificException {
         try {
             KeyFactory kf = KeyFactory.getInstance("EC");
-            // TODO: Randomly choose a key from the list -- right now we just use the whole input
-            X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(signedPublicKeyList);
-            publicKey = kf.generatePublic(pkSpec);
+            X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(bytes);
+            return kf.generatePublic(pkSpec);
         } catch (NoSuchAlgorithmException e) {
             Log.wtf(TAG, "EC algorithm not available. AOSP must support this.", e);
             throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
@@ -171,10 +225,6 @@
             throw new ServiceSpecificException(
                     ERROR_BAD_CERTIFICATE_FORMAT, "Not a valid X509 certificate.");
         }
-        long updatedRows = mDatabase.setRecoveryServicePublicKey(userId, uid, publicKey);
-        if (updatedRows > 0) {
-            mDatabase.setShouldCreateSnapshot(userId, uid, true);
-        }
     }
 
     /**
@@ -519,11 +569,11 @@
         byte[] locallyEncryptedKey;
         try {
             // TODO: Remove the extraneous logging here
-            Log.e(TAG, constructLoggingMessage("sessionEntry.getKeyClaimant()",
+            Log.d(TAG, constructLoggingMessage("sessionEntry.getKeyClaimant()",
                     sessionEntry.getKeyClaimant()));
-            Log.e(TAG, constructLoggingMessage("sessionEntry.getVaultParams()",
+            Log.d(TAG, constructLoggingMessage("sessionEntry.getVaultParams()",
                     sessionEntry.getVaultParams()));
-            Log.e(TAG, constructLoggingMessage("encryptedClaimResponse", encryptedClaimResponse));
+            Log.d(TAG, constructLoggingMessage("encryptedClaimResponse", encryptedClaimResponse));
             locallyEncryptedKey = KeySyncUtils.decryptRecoveryClaimResponse(
                     sessionEntry.getKeyClaimant(),
                     sessionEntry.getVaultParams(),
@@ -543,9 +593,9 @@
 
         try {
             // TODO: Remove the extraneous logging here
-            Log.e(TAG, constructLoggingMessage("sessionEntry.getLskfHash()",
+            Log.d(TAG, constructLoggingMessage("sessionEntry.getLskfHash()",
                     sessionEntry.getLskfHash()));
-            Log.e(TAG, constructLoggingMessage("locallyEncryptedKey", locallyEncryptedKey));
+            Log.d(TAG, constructLoggingMessage("locallyEncryptedKey", locallyEncryptedKey));
             return KeySyncUtils.decryptRecoveryKey(sessionEntry.getLskfHash(), locallyEncryptedKey);
         } catch (InvalidKeyException e) {
             Log.e(TAG, "Got InvalidKeyException during decrypting recovery key", e);
@@ -585,8 +635,8 @@
 
             try {
                 // TODO: Remove the extraneous logging here
-                Log.e(TAG, constructLoggingMessage("recoveryKey", recoveryKey));
-                Log.e(TAG, constructLoggingMessage("encryptedKeyMaterial", encryptedKeyMaterial));
+                Log.d(TAG, constructLoggingMessage("recoveryKey", recoveryKey));
+                Log.d(TAG, constructLoggingMessage("encryptedKeyMaterial", encryptedKeyMaterial));
                 byte[] keyMaterial =
                         KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial);
                 keyMaterialByAlias.put(alias, keyMaterial);
@@ -600,13 +650,16 @@
                 throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED,
                         "Failed to recover key with alias '" + alias + "': " + e.getMessage());
             } catch (AEADBadTagException e) {
-                // TODO: Remove the extraneous logging here
                 Log.e(TAG, "Got AEADBadTagException during decrypting application key with alias: "
                         + alias, e);
-                throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED,
-                        "Failed to recover key with alias '" + alias + "': " + e.getMessage());
+                // Ignore the exception to continue to recover the other application keys.
             }
         }
+        if (keyMaterialByAlias.isEmpty()) {
+            Log.e(TAG, "Failed to recover any of the application keys.");
+            throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED,
+                    "Failed to recover any of the application keys.");
+        }
         return keyMaterialByAlias;
     }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertParsingException.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertParsingException.java
new file mode 100644
index 0000000..57a3d99
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertParsingException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+/** Exception thrown when parsing errors occur. */
+public class CertParsingException extends Exception {
+
+    public CertParsingException(String message) {
+        super(message);
+    }
+
+    public CertParsingException(Exception cause) {
+        super(cause);
+    }
+
+    public CertParsingException(String message, Exception cause) {
+        super(message, cause);
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java
new file mode 100644
index 0000000..09ec5ad
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+import static javax.xml.xpath.XPathConstants.NODESET;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/** Utility functions related to parsing and validating public-key certificates. */
+public final class CertUtils {
+
+    private static final String CERT_FORMAT = "X.509";
+    private static final String CERT_PATH_ALG = "PKIX";
+    private static final String CERT_STORE_ALG = "Collection";
+    private static final String SIGNATURE_ALG = "SHA256withRSA";
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({MUST_EXIST_UNENFORCED, MUST_EXIST_EXACTLY_ONE, MUST_EXIST_AT_LEAST_ONE})
+    @interface MustExist {}
+    static final int MUST_EXIST_UNENFORCED = 0;
+    static final int MUST_EXIST_EXACTLY_ONE = 1;
+    static final int MUST_EXIST_AT_LEAST_ONE = 2;
+
+    private CertUtils() {}
+
+    /**
+     * Decodes a byte array containing an encoded X509 certificate.
+     *
+     * @param certBytes the byte array containing the encoded X509 certificate
+     * @return the decoded X509 certificate
+     * @throws CertParsingException if any parsing error occurs
+     */
+    static X509Certificate decodeCert(byte[] certBytes) throws CertParsingException {
+        return decodeCert(new ByteArrayInputStream(certBytes));
+    }
+
+    /**
+     * Decodes an X509 certificate from an {@code InputStream}.
+     *
+     * @param inStream the input stream containing the encoded X509 certificate
+     * @return the decoded X509 certificate
+     * @throws CertParsingException if any parsing error occurs
+     */
+    static X509Certificate decodeCert(InputStream inStream) throws CertParsingException {
+        CertificateFactory certFactory;
+        try {
+            certFactory = CertificateFactory.getInstance(CERT_FORMAT);
+        } catch (CertificateException e) {
+            // Should not happen, as X.509 is mandatory for all providers.
+            throw new RuntimeException(e);
+        }
+        try {
+            return (X509Certificate) certFactory.generateCertificate(inStream);
+        } catch (CertificateException e) {
+            throw new CertParsingException(e);
+        }
+    }
+
+    /**
+     * Parses a byte array as the content of an XML file, and returns the root node of the XML file.
+     *
+     * @param xmlBytes the byte array that is the XML file content
+     * @return the root node of the XML file
+     * @throws CertParsingException if any parsing error occurs
+     */
+    static Element getXmlRootNode(byte[] xmlBytes) throws CertParsingException {
+        try {
+            Document document =
+                    DocumentBuilderFactory.newInstance()
+                            .newDocumentBuilder()
+                            .parse(new ByteArrayInputStream(xmlBytes));
+            document.getDocumentElement().normalize();
+            return document.getDocumentElement();
+        } catch (SAXException | ParserConfigurationException | IOException e) {
+            throw new CertParsingException(e);
+        }
+    }
+
+    /**
+     * Gets the text contents of certain XML child nodes, given a XML root node and a list of tags
+     * representing the path to locate the child nodes. The whitespaces and newlines in the text
+     * contents are stripped away.
+     *
+     * <p>For example, the list of tags [tag1, tag2, tag3] represents the XML tree like the
+     * following:
+     *
+     * <pre>
+     *   <root>
+     *     <tag1>
+     *       <tag2>
+     *         <tag3>abc</tag3>
+     *         <tag3>def</tag3>
+     *       </tag2>
+     *     </tag1>
+     *   <root>
+     * </pre>
+     *
+     * @param mustExist whether and how many nodes must exist. If the number of child nodes does not
+     *                  satisfy the requirement, CertParsingException will be thrown.
+     * @param rootNode  the root node that serves as the starting point to locate the child nodes
+     * @param nodeTags  the list of tags representing the relative path from the root node
+     * @return a list of strings that are the text contents of the child nodes
+     * @throws CertParsingException if any parsing error occurs
+     */
+    static List<String> getXmlNodeContents(@MustExist int mustExist, Element rootNode,
+            String... nodeTags)
+            throws CertParsingException {
+        String expression = String.join("/", nodeTags);
+
+        XPath xPath = XPathFactory.newInstance().newXPath();
+        NodeList nodeList;
+        try {
+            nodeList = (NodeList) xPath.compile(expression).evaluate(rootNode, NODESET);
+        } catch (XPathExpressionException e) {
+            throw new CertParsingException(e);
+        }
+
+        switch (mustExist) {
+            case MUST_EXIST_UNENFORCED:
+                break;
+
+            case MUST_EXIST_EXACTLY_ONE:
+                if (nodeList.getLength() != 1) {
+                    throw new CertParsingException(
+                            "The XML file must contain exactly one node with the path "
+                                    + expression);
+                }
+                break;
+
+            case MUST_EXIST_AT_LEAST_ONE:
+                if (nodeList.getLength() == 0) {
+                    throw new CertParsingException(
+                            "The XML file must contain at least one node with the path "
+                                    + expression);
+                }
+                break;
+
+            default:
+                throw new UnsupportedOperationException(
+                        "This value of MustExist is not supported: " + mustExist);
+        }
+
+        List<String> result = new ArrayList<>();
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            Node node = nodeList.item(i);
+            // Remove whitespaces and newlines.
+            result.add(node.getTextContent().replaceAll("\\s", ""));
+        }
+        return result;
+    }
+
+    /**
+     * Decodes a base64-encoded string.
+     *
+     * @param str the base64-encoded string
+     * @return the decoding decoding result
+     * @throws CertParsingException if the input string is not a properly base64-encoded string
+     */
+    public static byte[] decodeBase64(String str) throws CertParsingException {
+        try {
+            return Base64.getDecoder().decode(str);
+        } catch (IllegalArgumentException e) {
+            throw new CertParsingException(e);
+        }
+    }
+
+    /**
+     * Verifies a public-key signature that is computed by RSA with SHA256.
+     *
+     * @param signerPublicKey the public key of the original signer
+     * @param signature       the public-key signature
+     * @param signedBytes     the bytes that have been signed
+     * @throws CertValidationException if the signature verification fails
+     */
+    static void verifyRsaSha256Signature(
+            PublicKey signerPublicKey, byte[] signature, byte[] signedBytes)
+            throws CertValidationException {
+        Signature verifier;
+        try {
+            verifier = Signature.getInstance(SIGNATURE_ALG);
+        } catch (NoSuchAlgorithmException e) {
+            // Should not happen, as SHA256withRSA is mandatory for all providers.
+            throw new RuntimeException(e);
+        }
+        try {
+            verifier.initVerify(signerPublicKey);
+            verifier.update(signedBytes);
+            if (!verifier.verify(signature)) {
+                throw new CertValidationException("The signature is invalid");
+            }
+        } catch (InvalidKeyException | SignatureException e) {
+            throw new CertValidationException(e);
+        }
+    }
+
+    /**
+     * Validates a leaf certificate, and returns the certificate path if the certificate is valid.
+     * If the given validation date is null, the current date will be used.
+     *
+     * @param validationDate    the date for which the validity of the certificate should be
+     *                          determined
+     * @param trustedRoot       the certificate of the trusted root CA
+     * @param intermediateCerts the list of certificates of possible intermediate CAs
+     * @param leafCert          the leaf certificate that is to be validated
+     * @return the certificate path if the leaf cert is valid
+     * @throws CertValidationException if {@code leafCert} is invalid (e.g., is expired, or has
+     *                                 invalid signature)
+     */
+    static CertPath validateCert(
+            @Nullable Date validationDate,
+            X509Certificate trustedRoot,
+            List<X509Certificate> intermediateCerts,
+            X509Certificate leafCert)
+            throws CertValidationException {
+        PKIXParameters pkixParams =
+                buildPkixParams(validationDate, trustedRoot, intermediateCerts, leafCert);
+        CertPath certPath = buildCertPath(pkixParams);
+
+        CertPathValidator certPathValidator;
+        try {
+            certPathValidator = CertPathValidator.getInstance(CERT_PATH_ALG);
+        } catch (NoSuchAlgorithmException e) {
+            // Should not happen, as PKIX is mandatory for all providers.
+            throw new RuntimeException(e);
+        }
+        try {
+            certPathValidator.validate(certPath, pkixParams);
+        } catch (CertPathValidatorException | InvalidAlgorithmParameterException e) {
+            throw new CertValidationException(e);
+        }
+        return certPath;
+    }
+
+    @VisibleForTesting
+    static CertPath buildCertPath(PKIXParameters pkixParams) throws CertValidationException {
+        CertPathBuilder certPathBuilder;
+        try {
+            certPathBuilder = CertPathBuilder.getInstance(CERT_PATH_ALG);
+        } catch (NoSuchAlgorithmException e) {
+            // Should not happen, as PKIX is mandatory for all providers.
+            throw new RuntimeException(e);
+        }
+        try {
+            return certPathBuilder.build(pkixParams).getCertPath();
+        } catch (CertPathBuilderException | InvalidAlgorithmParameterException e) {
+            throw new CertValidationException(e);
+        }
+    }
+
+    @VisibleForTesting
+    static PKIXParameters buildPkixParams(
+            @Nullable Date validationDate,
+            X509Certificate trustedRoot,
+            List<X509Certificate> intermediateCerts,
+            X509Certificate leafCert)
+            throws CertValidationException {
+        // Create a TrustAnchor from the trusted root certificate.
+        Set<TrustAnchor> trustedAnchors = new HashSet<>();
+        trustedAnchors.add(new TrustAnchor(trustedRoot, null));
+
+        // Create a CertStore from the list of intermediate certificates.
+        List<X509Certificate> certs = new ArrayList<>(intermediateCerts);
+        certs.add(leafCert);
+        CertStore certStore;
+        try {
+            certStore =
+                    CertStore.getInstance(CERT_STORE_ALG, new CollectionCertStoreParameters(certs));
+        } catch (NoSuchAlgorithmException e) {
+            // Should not happen, as Collection is mandatory for all providers.
+            throw new RuntimeException(e);
+        } catch (InvalidAlgorithmParameterException e) {
+            throw new CertValidationException(e);
+        }
+
+        // Create a CertSelector from the leaf certificate.
+        X509CertSelector certSelector = new X509CertSelector();
+        certSelector.setCertificate(leafCert);
+
+        // Build a PKIXParameters from TrustAnchor, CertStore, and CertSelector.
+        PKIXBuilderParameters pkixParams;
+        try {
+            pkixParams = new PKIXBuilderParameters(trustedAnchors, certSelector);
+        } catch (InvalidAlgorithmParameterException e) {
+            throw new CertValidationException(e);
+        }
+        pkixParams.addCertStore(certStore);
+
+        // If validationDate is null, the current time will be used.
+        pkixParams.setDate(validationDate);
+        pkixParams.setRevocationEnabled(false);
+
+        return pkixParams;
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertValidationException.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertValidationException.java
new file mode 100644
index 0000000..99a9ff7
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertValidationException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+/** Exception thrown when validation or verification fails. */
+public class CertValidationException extends Exception {
+
+    public CertValidationException(String message) {
+        super(message);
+    }
+
+    public CertValidationException(Exception cause) {
+        super(cause);
+    }
+
+    public CertValidationException(String message, Exception cause) {
+        super(message, cause);
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java
new file mode 100644
index 0000000..c62a31e
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertXml.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.security.SecureRandom;
+import java.security.cert.CertPath;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+/**
+ * Parses and holds the XML file containing the list of THM public-key certificates and related
+ * metadata.
+ */
+public final class CertXml {
+
+    private static final String METADATA_NODE_TAG = "metadata";
+    private static final String METADATA_SERIAL_NODE_TAG = "serial";
+    private static final String METADATA_REFRESH_INTERVAL_NODE_TAG = "refresh-interval";
+    private static final String ENDPOINT_CERT_LIST_TAG = "endpoints";
+    private static final String ENDPOINT_CERT_ITEM_TAG = "cert";
+    private static final String INTERMEDIATE_CERT_LIST_TAG = "intermediates";
+    private static final String INTERMEDIATE_CERT_ITEM_TAG = "cert";
+
+    private final long serial;
+    private final long refreshInterval;
+    private final List<X509Certificate> intermediateCerts;
+    private final List<X509Certificate> endpointCerts;
+
+    private CertXml(
+            long serial,
+            long refreshInterval,
+            List<X509Certificate> intermediateCerts,
+            List<X509Certificate> endpointCerts) {
+        this.serial = serial;
+        this.refreshInterval = refreshInterval;
+        this.intermediateCerts = intermediateCerts;
+        this.endpointCerts = endpointCerts;
+    }
+
+    /** Gets the serial number of the XML file containing public-key certificates. */
+    public long getSerial() {
+        return serial;
+    }
+
+    /**
+     * Gets the refresh interval in the XML file containing public-key certificates. The refresh
+     * interval denotes the number of seconds that the client should follow to contact the server to
+     * refresh the XML file.
+     */
+    public long getRefreshInterval() {
+        return refreshInterval;
+    }
+
+    @VisibleForTesting
+    List<X509Certificate> getAllIntermediateCerts() {
+        return intermediateCerts;
+    }
+
+    @VisibleForTesting
+    List<X509Certificate> getAllEndpointCerts() {
+        return endpointCerts;
+    }
+
+    /**
+     * Chooses a random endpoint certificate from the XML file, validates the chosen certificate,
+     * and returns the certificate path including the chosen certificate if it is valid.
+     *
+     * @param trustedRoot the trusted root certificate
+     * @return the certificate path including the chosen certificate if the certificate is valid
+     * @throws CertValidationException if the chosen certificate cannot be validated based on the
+     *                                 trusted root certificate
+     */
+    public CertPath getRandomEndpointCert(X509Certificate trustedRoot)
+            throws CertValidationException {
+        return getEndpointCert(
+                new SecureRandom().nextInt(this.endpointCerts.size()),
+                /*validationDate=*/ null,
+                trustedRoot);
+    }
+
+    @VisibleForTesting
+    CertPath getEndpointCert(
+            int index, @Nullable Date validationDate, X509Certificate trustedRoot)
+            throws CertValidationException {
+        X509Certificate chosenCert = endpointCerts.get(index);
+        return CertUtils.validateCert(validationDate, trustedRoot, intermediateCerts, chosenCert);
+    }
+
+    /**
+     * Parses a byte array as the content of the XML file containing a list of endpoint
+     * certificates.
+     *
+     * @param bytes the bytes of the XML file
+     * @return a {@code CertXml} instance that contains the parsing result
+     * @throws CertParsingException if any parsing error occurs
+     */
+    public static CertXml parse(byte[] bytes) throws CertParsingException {
+        Element rootNode = CertUtils.getXmlRootNode(bytes);
+        return new CertXml(
+                parseSerial(rootNode),
+                parseRefreshInterval(rootNode),
+                parseIntermediateCerts(rootNode),
+                parseEndpointCerts(rootNode));
+    }
+
+    private static long parseSerial(Element rootNode) throws CertParsingException {
+        List<String> contents =
+                CertUtils.getXmlNodeContents(
+                        CertUtils.MUST_EXIST_EXACTLY_ONE,
+                        rootNode,
+                        METADATA_NODE_TAG,
+                        METADATA_SERIAL_NODE_TAG);
+        return Long.parseLong(contents.get(0));
+    }
+
+    private static long parseRefreshInterval(Element rootNode) throws CertParsingException {
+        List<String> contents =
+                CertUtils.getXmlNodeContents(
+                        CertUtils.MUST_EXIST_EXACTLY_ONE,
+                        rootNode,
+                        METADATA_NODE_TAG,
+                        METADATA_REFRESH_INTERVAL_NODE_TAG);
+        return Long.parseLong(contents.get(0));
+    }
+
+    private static List<X509Certificate> parseIntermediateCerts(Element rootNode)
+            throws CertParsingException {
+        List<String> contents =
+                CertUtils.getXmlNodeContents(
+                        CertUtils.MUST_EXIST_UNENFORCED,
+                        rootNode,
+                        INTERMEDIATE_CERT_LIST_TAG,
+                        INTERMEDIATE_CERT_ITEM_TAG);
+        List<X509Certificate> res = new ArrayList<>();
+        for (String content : contents) {
+            res.add(CertUtils.decodeCert(CertUtils.decodeBase64(content)));
+        }
+        return Collections.unmodifiableList(res);
+    }
+
+    private static List<X509Certificate> parseEndpointCerts(Element rootNode)
+            throws CertParsingException {
+        List<String> contents =
+                CertUtils.getXmlNodeContents(
+                        CertUtils.MUST_EXIST_AT_LEAST_ONE,
+                        rootNode,
+                        ENDPOINT_CERT_LIST_TAG,
+                        ENDPOINT_CERT_ITEM_TAG);
+        List<X509Certificate> res = new ArrayList<>();
+        for (String content : contents) {
+            res.add(CertUtils.decodeCert(CertUtils.decodeBase64(content)));
+        }
+        return Collections.unmodifiableList(res);
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java
new file mode 100644
index 0000000..e75be85
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/SigXml.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+/**
+ * Parses and holds the XML file containing the signature of the XML file containing the list of THM
+ * public-key certificates.
+ */
+public final class SigXml {
+
+    private static final String INTERMEDIATE_CERT_LIST_TAG = "intermediates";
+    private static final String INTERMEDIATE_CERT_ITEM_TAG = "cert";
+    private static final String SIGNER_CERT_NODE_TAG = "certificate";
+    private static final String SIGNATURE_NODE_TAG = "value";
+
+    private final List<X509Certificate> intermediateCerts;
+    private final X509Certificate signerCert;
+    private final byte[] signature;
+
+    private SigXml(
+            List<X509Certificate> intermediateCerts, X509Certificate signerCert, byte[] signature) {
+        this.intermediateCerts = intermediateCerts;
+        this.signerCert = signerCert;
+        this.signature = signature;
+    }
+
+    /**
+     * Verifies the signature contained in this XML file against a trusted root certificate and the
+     * binary content of another file. The signer's public-key certificate and possible intermediate
+     * CA certificates are included in this XML file, and will be validated against the trusted root
+     * certificate.
+     *
+     * @param trustedRoot     the trusted root certificate
+     * @param signedFileBytes the original file content that has been signed
+     * @throws CertValidationException if the signature verification fails, or the signer's
+     *                                 certificate contained in this XML file cannot be validated
+     *                                 based on the trusted root certificate
+     */
+    public void verifyFileSignature(X509Certificate trustedRoot, byte[] signedFileBytes)
+            throws CertValidationException {
+        verifyFileSignature(trustedRoot, signedFileBytes, /*validationDate=*/ null);
+    }
+
+    @VisibleForTesting
+    void verifyFileSignature(
+            X509Certificate trustedRoot, byte[] signedFileBytes, @Nullable Date validationDate)
+            throws CertValidationException {
+        CertUtils.validateCert(validationDate, trustedRoot, intermediateCerts, signerCert);
+        CertUtils.verifyRsaSha256Signature(signerCert.getPublicKey(), signature, signedFileBytes);
+    }
+
+    /**
+     * Parses a byte array as the content of the XML file containing the signature and related
+     * certificates.
+     *
+     * @param bytes the bytes of the XML file
+     * @return a {@code SigXml} instance that contains the parsing result
+     * @throws CertParsingException if any parsing error occurs
+     */
+    public static SigXml parse(byte[] bytes) throws CertParsingException {
+        Element rootNode = CertUtils.getXmlRootNode(bytes);
+        return new SigXml(
+                parseIntermediateCerts(rootNode), parseSignerCert(rootNode),
+                parseFileSignature(rootNode));
+    }
+
+    private static List<X509Certificate> parseIntermediateCerts(Element rootNode)
+            throws CertParsingException {
+        List<String> contents =
+                CertUtils.getXmlNodeContents(
+                        CertUtils.MUST_EXIST_UNENFORCED,
+                        rootNode,
+                        INTERMEDIATE_CERT_LIST_TAG,
+                        INTERMEDIATE_CERT_ITEM_TAG);
+        List<X509Certificate> res = new ArrayList<>();
+        for (String content : contents) {
+            res.add(CertUtils.decodeCert(CertUtils.decodeBase64(content)));
+        }
+        return Collections.unmodifiableList(res);
+    }
+
+    private static X509Certificate parseSignerCert(Element rootNode) throws CertParsingException {
+        List<String> contents =
+                CertUtils.getXmlNodeContents(
+                        CertUtils.MUST_EXIST_EXACTLY_ONE, rootNode, SIGNER_CERT_NODE_TAG);
+        return CertUtils.decodeCert(CertUtils.decodeBase64(contents.get(0)));
+    }
+
+    private static byte[] parseFileSignature(Element rootNode) throws CertParsingException {
+        List<String> contents =
+                CertUtils.getXmlNodeContents(
+                        CertUtils.MUST_EXIST_EXACTLY_ONE, rootNode, SIGNATURE_NODE_TAG);
+        return CertUtils.decodeBase64(contents.get(0));
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/TrustedRootCert.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/TrustedRootCert.java
new file mode 100644
index 0000000..7195d62
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/TrustedRootCert.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * Holds the X509 certificate of the trusted root CA cert for the recoverable key store service.
+ *
+ * TODO: Read the certificate from a PEM file directly and remove this class.
+ */
+public final class TrustedRootCert {
+
+    private  static final String TRUSTED_ROOT_CERT_BASE64 = ""
+            + "MIIFJjCCAw6gAwIBAgIJAIobXsJlzhNdMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV"
+            + "BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDIxOTM5MTRaFw0zODAx"
+            + "MjgxOTM5MTRaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCAiIw"
+            + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2OT5i40/H7LINg/lq/0G0hR65P"
+            + "Q4Mud3OnuVt6UIYV2T18+v6qW1yJd5FcnND/ZKPau4aUAYklqJuSVjOXQD0BjgS2"
+            + "98Xa4dSn8Ci1rUR+5tdmrxqbYUdT2ZvJIUMMR6fRoqi+LlAbKECrV+zYQTyLU68w"
+            + "V66hQpAButjJKiZzkXjmKLfJ5IWrNEn17XM988rk6qAQn/BYCCQGf3rQuJeksGmA"
+            + "N1lJOwNYxmWUyouVwqwZthNEWqTuEyBFMkAT+99PXW7oVDc7oU5cevuihxQWNTYq"
+            + "viGB8cck6RW3cmqrDSaJF/E+N0cXFKyYC7FDcggt6k3UrxNKTuySdDEa8+2RTQqU"
+            + "Y9npxBlQE+x9Ig56OI1BG3bSBsGdPgjpyHadZeh2tgk+oqlGsSsum24YxaxuSysT"
+            + "Qfcu/XhyfUXavfmGrBOXerTzIl5oBh/F5aHTV85M2tYEG0qsPPvSpZAWtdJ/2rca"
+            + "OxvhwOL+leZKr8McjXVR00lBsRuKXX4nTUMwya09CO3QHFPFZtZvqjy2HaMOnVLQ"
+            + "I6b6dHEfmsHybzVOe3yPEoFQSU9UhUdmi71kwwoanPD3j9fJHmXTx4PzYYBRf1ZE"
+            + "o+uPgMPk7CDKQFZLjnR40z1uzu3O8aZ3AKZzP+j7T4XQKJLQLmllKtPgLgNdJyib"
+            + "2Glg7QhXH/jBTL6hAgMBAAGjYzBhMB0GA1UdDgQWBBSbZfrqOYH54EJpkdKMZjMc"
+            + "z/Hp+DAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DAPBgNVHRMBAf8E"
+            + "BTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQ0FAAOCAgEAKh9nm/vW"
+            + "glMWp3vcCwWwJW286ecREDlI+CjGh5h+f2N4QRrXd/tKE3qQJWCqGx8sFfIUjmI7"
+            + "KYdsC2gyQ2cA2zl0w7pB2QkuqE6zVbnh1D17Hwl19IMyAakFaM9ad4/EoH7oQmqX"
+            + "nF/f5QXGZw4kf1HcgKgoCHWXjqR8MqHOcXR8n6WFqxjzJf1jxzi6Yo2dZ7PJbnE6"
+            + "+kHIJuiCpiHL75v5g1HM41gT3ddFFSrn88ThNPWItT5Z8WpFjryVzank2Yt02LLl"
+            + "WqZg9IC375QULc5B58NMnaiVJIDJQ8zoNgj1yaxqtUMnJX570lotO2OXe4ec9aCQ"
+            + "DIJ84YLM/qStFdeZ9416E80dchskbDG04GuVJKlzWjxAQNMRFhyaPUSBTLLg+kwP"
+            + "t9+AMmc+A7xjtFQLZ9fBYHOBsndJOmeSQeYeckl+z/1WQf7DdwXn/yijon7mxz4z"
+            + "cCczfKwTJTwBh3wR5SQr2vQm7qaXM87qxF8PCAZrdZaw5I80QwkgTj0WTZ2/GdSw"
+            + "d3o5SyzzBAjpwtG+4bO/BD9h9wlTsHpT6yWOZs4OYAKU5ykQrncI8OyavMggArh3"
+            + "/oM58v0orUWINtIc2hBlka36PhATYQiLf+AiWKnwhCaaHExoYKfQlMtXBodNvOK8"
+            + "xqx69x05q/qbHKEcTHrsss630vxrp1niXvA=";
+
+    /**
+     * The X509 certificate of the trusted root CA cert for the recoverable key store service.
+     *
+     * TODO: Change it to the production certificate root CA before the final launch.
+     */
+    public static final X509Certificate TRUSTED_ROOT_CERT;
+
+    static {
+        try {
+            TRUSTED_ROOT_CERT = CertUtils.decodeCert(
+                    CertUtils.decodeBase64(TRUSTED_ROOT_CERT_BASE64));
+        } catch (CertParsingException e) {
+            // Should not happen
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index b96208d..89ddb6c 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -31,9 +31,14 @@
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
 
+import java.io.ByteArrayInputStream;
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
@@ -53,6 +58,7 @@
     private static final String TAG = "RecoverableKeyStoreDb";
     private static final int IDLE_TIMEOUT_SECONDS = 30;
     private static final int LAST_SYNCED_AT_UNSYNCED = -1;
+    private static final String CERT_PATH_ENCODING = "PkiPath";
 
     private final RecoverableKeyStoreDbHelper mKeyStoreDbHelper;
 
@@ -361,6 +367,79 @@
     }
 
     /**
+     * Returns the serial number of the XML file containing certificates of the recovery service.
+     *
+     * @param userId The userId of the profile the application is running under.
+     * @param uid The uid of the application who initializes the local recovery components.
+     * @return The value that were previously set, or null if there's none.
+     *
+     * @hide
+     */
+    @Nullable
+    public Long getRecoveryServiceCertSerial(int userId, int uid) {
+        return getLong(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL);
+    }
+
+    /**
+     * Records the serial number of the XML file containing certificates of the recovery service.
+     *
+     * @param userId The userId of the profile the application is running under.
+     * @param uid The uid of the application who initializes the local recovery components.
+     * @param serial The serial number contained in the XML file for recovery service certificates.
+     * @return The primary key of the inserted row, or -1 if failed.
+     *
+     * @hide
+     */
+    public long setRecoveryServiceCertSerial(int userId, int uid, long serial) {
+        return setLong(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, serial);
+    }
+
+    /**
+     * Returns the {@code CertPath} of the recovery service.
+     *
+     * @param userId The userId of the profile the application is running under.
+     * @param uid The uid of the application who initializes the local recovery components.
+     * @return The value that were previously set, or null if there's none.
+     *
+     * @hide
+     */
+    @Nullable
+    public CertPath getRecoveryServiceCertPath(int userId, int uid) {
+        byte[] bytes = getBytes(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH);
+        if (bytes == null) {
+            return null;
+        }
+        try {
+            return decodeCertPath(bytes);
+        } catch (CertificateException e) {
+            Log.wtf(TAG,
+                    String.format(Locale.US,
+                            "Recovery service CertPath entry cannot be decoded for "
+                                    + "userId=%d uid=%d.",
+                            userId, uid), e);
+            return null;
+        }
+    }
+
+    /**
+     * Sets the {@code CertPath} of the recovery service.
+     *
+     * @param userId The userId of the profile the application is running under.
+     * @param uid The uid of the application who initializes the local recovery components.
+     * @param certPath The certificate path of the recovery service.
+     * @return The primary key of the inserted row, or -1 if failed.
+     * @hide
+     */
+    public long setRecoveryServiceCertPath(int userId, int uid, CertPath certPath) throws
+            CertificateEncodingException {
+        if (certPath.getCertificates().size() == 0) {
+            throw new CertificateEncodingException("No certificate contained in the cert path.");
+        }
+        return setBytes(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH,
+                certPath.getEncoded(CERT_PATH_ENCODING));
+    }
+
+    /**
      * Returns the list of recovery agents initialized for given {@code userId}
      * @param userId The userId of the profile the application is running under.
      * @return The list of recovery agents
@@ -515,48 +594,6 @@
     }
 
     /**
-     * Returns the first (and only?) public key for {@code userId}.
-     *
-     * @param userId The userId of the profile whose keys are to be synced.
-     * @return The public key, or null if none exists.
-     */
-    @Nullable
-    public PublicKey getRecoveryServicePublicKey(int userId) {
-        SQLiteDatabase db = mKeyStoreDbHelper.getReadableDatabase();
-
-        String[] projection = { RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY };
-        String selection =
-                RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " = ?";
-        String[] selectionArguments = { Integer.toString(userId) };
-
-        try (
-            Cursor cursor = db.query(
-                    RecoveryServiceMetadataEntry.TABLE_NAME,
-                    projection,
-                    selection,
-                    selectionArguments,
-                    /*groupBy=*/ null,
-                    /*having=*/ null,
-                    /*orderBy=*/ null)
-        ) {
-            if (cursor.getCount() < 1) {
-                return null;
-            }
-
-            cursor.moveToFirst();
-            byte[] keyBytes = cursor.getBlob(cursor.getColumnIndexOrThrow(
-                    RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY));
-
-            try {
-                return decodeX509Key(keyBytes);
-            } catch (InvalidKeySpecException e) {
-                Log.wtf(TAG, "Could not decode public key for " + userId);
-                return null;
-            }
-        }
-    }
-
-    /**
      * Updates the counterId
      *
      * @param userId The userId of the profile the application is running under.
@@ -585,7 +622,6 @@
         return getLong(userId, uid, RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID);
     }
 
-
     /**
      * Updates the server parameters given by the application initializing the local recovery
      * components.
@@ -869,4 +905,16 @@
             throw new RuntimeException(e);
         }
     }
+
+    @Nullable
+    private static CertPath decodeCertPath(byte[] bytes) throws CertificateException {
+        CertificateFactory certFactory;
+        try {
+            certFactory = CertificateFactory.getInstance("X.509");
+        } catch (CertificateException e) {
+            // Should not happen, as X.509 is mandatory for all providers.
+            throw new RuntimeException(e);
+        }
+        return certFactory.generateCertPath(new ByteArrayInputStream(bytes), CERT_PATH_ENCODING);
+    }
 }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index 4ee282b..1cb5d91 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -104,9 +104,10 @@
         static final String COLUMN_NAME_UID = "uid";
 
         /**
-         * Version of the latest recovery snapshot
+         * Version of the latest recovery snapshot.
          */
         static final String COLUMN_NAME_SNAPSHOT_VERSION = "snapshot_version";
+
         /**
          * Flag to generate new snapshot.
          */
@@ -118,6 +119,16 @@
         static final String COLUMN_NAME_PUBLIC_KEY = "public_key";
 
         /**
+         * The certificate path of the recovery service.
+         */
+        static final String COLUMN_NAME_CERT_PATH = "cert_path";
+
+        /**
+         * The serial number contained in the certificate XML file of the recovery service.
+         */
+        static final String COLUMN_NAME_CERT_SERIAL = "cert_serial";
+
+        /**
          * Secret types used for end-to-end encryption.
          */
         static final String COLUMN_NAME_SECRET_TYPES = "secret_types";
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
index 79fd496..8a89f2d 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
 
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
@@ -28,7 +29,9 @@
  * Helper for creating the recoverable key database.
  */
 class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
-    private static final int DATABASE_VERSION = 2;
+    private static final String TAG = "RecoverableKeyStoreDbHp";
+
+    static final int DATABASE_VERSION = 3;
     private static final String DATABASE_NAME = "recoverablekeystore.db";
 
     private static final String SQL_CREATE_KEYS_ENTRY =
@@ -59,6 +62,8 @@
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION + " INTEGER,"
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT + " INTEGER,"
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY + " BLOB,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH + " BLOB,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL + " INTEGER,"
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES + " TEXT,"
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID + " INTEGER,"
                     + RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS + " BLOB,"
@@ -88,9 +93,39 @@
 
     @Override
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-        db.execSQL(SQL_DELETE_KEYS_ENTRY);
-        db.execSQL(SQL_DELETE_USER_METADATA_ENTRY);
-        db.execSQL(SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY);
-        onCreate(db);
+        if (oldVersion < 2) {
+            db.execSQL(SQL_DELETE_KEYS_ENTRY);
+            db.execSQL(SQL_DELETE_USER_METADATA_ENTRY);
+            db.execSQL(SQL_DELETE_RECOVERY_SERVICE_METADATA_ENTRY);
+            onCreate(db);
+            return;
+        }
+
+        if (oldVersion < 3) {
+            upgradeDbForVersion3(db);
+        }
+    }
+
+    private void upgradeDbForVersion3(SQLiteDatabase db) {
+        // Add the two columns for cert path and cert serial number
+        addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
+                RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH, "BLOB", /*defaultStr=*/ null);
+        addColumnToTable(db, RecoveryServiceMetadataEntry.TABLE_NAME,
+                RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, "INTEGER", /*defaultStr=*/
+                null);
+    }
+
+    private static void addColumnToTable(
+            SQLiteDatabase db, String tableName, String column, String columnType,
+            String defaultStr) {
+        Log.d(TAG, "Adding column " + column + " to " + tableName + ".");
+
+        String alterStr = "ALTER TABLE " + tableName + " ADD COLUMN " + column + " " + columnType;
+        if (defaultStr != null && !defaultStr.isEmpty()) {
+            alterStr += " DEFAULT " + defaultStr;
+        }
+
+        db.execSQL(alterStr + ";");
     }
 }
+
diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
index 7881a95..648c782 100644
--- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
+++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
@@ -289,6 +289,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void sendAudioPlayerActiveStateChangedMessageLocked(
             final AudioPlaybackConfiguration config, final boolean isRemoved) {
         for (MessageHandler messageHandler : mListenerMap.values()) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index a6f049e..f346629 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1722,7 +1722,7 @@
                 final long totalBytes = getTotalBytes(
                         NetworkTemplate.buildTemplateMobileAll(state.subscriberId), start, end);
                 final long remainingBytes = limitBytes - totalBytes;
-                final long remainingDays = Math.min(1, (end - currentTimeMillis())
+                final long remainingDays = Math.max(1, (end - currentTimeMillis())
                         / TimeUnit.DAYS.toMillis(1));
                 if (remainingBytes > 0) {
                     quotaBytes = (remainingBytes / remainingDays) / 10;
@@ -4678,10 +4678,12 @@
         return subId;
     }
 
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private int getSubIdLocked(Network network) {
         return mNetIdToSubId.get(network.netId, INVALID_SUBSCRIPTION_ID);
     }
 
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private SubscriptionPlan getPrimarySubscriptionPlanLocked(int subId) {
         final SubscriptionPlan[] plans = mSubscriptionPlans.get(subId);
         return ArrayUtils.isEmpty(plans) ? null : plans[0];
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 961a451..3cc4d83 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -187,6 +187,7 @@
      */
     @VisibleForTesting
     public static long multiplySafe(long value, long num, long den) {
+        if (den == 0) den = 1;
         long x = value;
         long y = num;
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index bfc150e..76c4db1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -405,6 +405,7 @@
                 mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags);
     }
 
+    @GuardedBy("mStatsLock")
     private void shutdownLocked() {
         mContext.unregisterReceiver(mTetherReceiver);
         mContext.unregisterReceiver(mPollReceiver);
@@ -431,6 +432,7 @@
         mSystemReady = false;
     }
 
+    @GuardedBy("mStatsLock")
     private void maybeUpgradeLegacyStatsLocked() {
         File file;
         try {
@@ -909,6 +911,7 @@
      * reflect current {@link #mPersistThreshold} value. Always defers to
      * {@link Global} values when defined.
      */
+    @GuardedBy("mStatsLock")
     private void updatePersistThresholdsLocked() {
         mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold));
         mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold));
@@ -1029,6 +1032,7 @@
      * are active on a single {@code iface}, they are combined under a single
      * {@link NetworkIdentitySet}.
      */
+    @GuardedBy("mStatsLock")
     private void updateIfacesLocked(Network[] defaultNetworks) {
         if (!mSystemReady) return;
         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
@@ -1128,6 +1132,7 @@
         return ident;
     }
 
+    @GuardedBy("mStatsLock")
     private void recordSnapshotLocked(long currentTime) throws RemoteException {
         // snapshot and record current counters; read UID stats first to
         // avoid over counting dev stats.
@@ -1163,6 +1168,7 @@
      * Bootstrap initial stats snapshot, usually during {@link #systemReady()}
      * so we have baseline values without double-counting.
      */
+    @GuardedBy("mStatsLock")
     private void bootstrapStatsLocked() {
         final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
                 : System.currentTimeMillis();
@@ -1197,6 +1203,7 @@
      * Periodic poll operation, reading current statistics and recording into
      * {@link NetworkStatsHistory}.
      */
+    @GuardedBy("mStatsLock")
     private void performPollLocked(int flags) {
         if (!mSystemReady) return;
         if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
@@ -1258,6 +1265,7 @@
     /**
      * Sample recent statistics summary into {@link EventLog}.
      */
+    @GuardedBy("mStatsLock")
     private void performSampleLocked() {
         // TODO: migrate trustedtime fixes to separate binary log events
         final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
@@ -1295,6 +1303,7 @@
     /**
      * Clean up {@link #mUidRecorder} after UID is removed.
      */
+    @GuardedBy("mStatsLock")
     private void removeUidsLocked(int... uids) {
         if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
 
@@ -1313,6 +1322,7 @@
     /**
      * Clean up {@link #mUidRecorder} after user is removed.
      */
+    @GuardedBy("mStatsLock")
     private void removeUserLocked(int userId) {
         if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId);
 
@@ -1434,6 +1444,7 @@
         }
     }
 
+    @GuardedBy("mStatsLock")
     private void dumpProtoLocked(FileDescriptor fd) {
         final ProtoOutputStream proto = new ProtoOutputStream(fd);
 
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
index c4de4ac..e8b39c0 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -22,12 +22,14 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
 import android.os.Bundle;
 import android.os.DropBoxManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -128,7 +130,7 @@
                 Slog.e(TAG, "Couldn't find package: " + packageNames);
                 return false;
             }
-            ai = mPm.getApplicationInfo(packageNames[0],0);
+            ai = mPm.getApplicationInfo(packageNames[0], 0);
         } catch (NameNotFoundException e) {
             // Should not happen.
             return false;
@@ -136,7 +138,7 @@
         return (ai.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;
     }
 
-     /**
+    /**
      * Report network watchlist records if we collected enough data.
      */
     public void reportWatchlistIfNecessary() {
@@ -180,6 +182,10 @@
             return true;
         }
         final byte[] digest = getDigestFromUid(uid);
+        if (digest == null) {
+            Slog.e(TAG, "Cannot get digest from uid: " + uid);
+            return false;
+        }
         final boolean result = mDbHelper.insertNewRecord(digest, cncHost, timestamp);
         tryAggregateRecords();
         return result;
@@ -234,15 +240,34 @@
      * if an app is really visited C&C site.
      * (2) App digests that previously recorded in database.
      */
-    private List<String> getAllDigestsForReport(WatchlistReportDbHelper.AggregatedResult record) {
+    @VisibleForTesting
+    List<String> getAllDigestsForReport(WatchlistReportDbHelper.AggregatedResult record) {
         // Step 1: Get all installed application digests.
+        final List<UserInfo> users = ((UserManager) mContext.getSystemService(
+                Context.USER_SERVICE)).getUsers();
+        final int totalUsers = users.size();
         final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
                 PackageManager.MATCH_ANY_USER | PackageManager.MATCH_ALL);
         final HashSet<String> result = new HashSet<>(apps.size() + record.appDigestCNCList.size());
         final int size = apps.size();
         for (int i = 0; i < size; i++) {
-            byte[] digest = getDigestFromUid(apps.get(i).uid);
-            result.add(HexDump.toHexString(digest));
+            final int appUid = apps.get(i).uid;
+            boolean added = false;
+            // As the uid returned by getInstalledApplications() is for primary user only, it
+            // may exist in secondary users but not primary user, so we need to loop and see if
+            // that user has the app enabled.
+            for (int j = 0; j < totalUsers && !added; j++) {
+                int uid = UserHandle.getUid(users.get(j).id, appUid);
+                byte[] digest = getDigestFromUid(uid);
+                if (digest != null) {
+                    result.add(HexDump.toHexString(digest));
+                    added = true;
+                }
+            }
+            if (!added) {
+                Slog.e(TAG, "Cannot get digest from uid: " + apps.get(i).uid
+                        + ",pkg: " + apps.get(i).packageName);
+            }
         }
         // Step 2: Add all digests from records
         result.addAll(record.appDigestCNCList.keySet());
@@ -279,9 +304,9 @@
                         return null;
                     }
                 }
-            } else {
-                Slog.e(TAG, "Should not happen");
             }
+            // Not able to find a package name for this uid, possibly the package is installed on
+            // another user.
             return null;
         });
     }
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index fd435f9..b7842d5 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -376,9 +376,7 @@
     protected void upgradeXml(final int xmlVersion, final int userId) {}
 
     private void loadAllowedComponentsFromSettings() {
-
-        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        for (UserInfo user : userManager.getUsers()) {
+        for (UserInfo user : mUm.getUsers()) {
             final ContentResolver cr = mContext.getContentResolver();
             addApprovedList(Settings.Secure.getStringForUser(
                     cr,
@@ -482,7 +480,9 @@
         for (int i = 0; i < allowedByType.size(); i++) {
             final ArraySet<String> allowed = allowedByType.valueAt(i);
             allowedPackages.addAll(
-                    allowed.stream().map(this::getPackageName).collect(Collectors.toList()));
+                    allowed.stream().map(this::getPackageName).
+                            filter(value -> !TextUtils.isEmpty(value))
+                            .collect(Collectors.toList()));
         }
         return allowedPackages;
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b25124a..3800017 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -25,7 +25,9 @@
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.UserHandle.USER_ALL;
 import static android.os.UserHandle.USER_NULL;
+import static android.os.UserHandle.USER_SYSTEM;
 import static android.service.notification.NotificationListenerService
         .HINT_HOST_DISABLE_CALL_EFFECTS;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
@@ -88,6 +90,7 @@
 import android.companion.ICompanionDeviceManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -115,6 +118,7 @@
 import android.os.IInterface;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -206,6 +210,7 @@
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map.Entry;
@@ -288,6 +293,7 @@
     private ICompanionDeviceManager mCompanionManager;
     private AccessibilityManager mAccessibilityManager;
     private IDeviceIdleController mDeviceIdleController;
+    private IBinder mPermissionOwner;
 
     final IBinder mForegroundToken = new Binder();
     private WorkerHandler mHandler;
@@ -524,7 +530,7 @@
             } catch (FileNotFoundException e) {
                 // No data yet
                 // Load default managed services approvals
-                readDefaultApprovedServices(UserHandle.USER_SYSTEM);
+                readDefaultApprovedServices(USER_SYSTEM);
             } catch (IOException e) {
                 Log.wtf(TAG, "Unable to read notification policy", e);
             } catch (NumberFormatException e) {
@@ -680,6 +686,7 @@
                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
                         REASON_CLICK, null);
+                reportUserInteraction(r);
             }
         }
 
@@ -700,7 +707,7 @@
                         .setSubtype(actionIndex));
                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
-                // TODO: Log action click via UsageStats.
+                reportUserInteraction(r);
             }
         }
 
@@ -821,6 +828,7 @@
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
                     r.recordDirectReplied();
+                    reportUserInteraction(r);
                 }
             }
         }
@@ -974,7 +982,7 @@
                             final int enabled = mPackageManager.getApplicationEnabledSetting(
                                     pkgName,
                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
-                                            UserHandle.USER_SYSTEM);
+                                            USER_SYSTEM);
                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
                                 cancelNotifications = false;
@@ -1061,6 +1069,7 @@
                 }
             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+                mUserProfiles.updateCache(context);
                 mZenModeHelper.onUserRemoved(user);
                 mRankingHelper.onUserRemoved(user);
                 mListeners.onUserRemoved(user);
@@ -1268,7 +1277,7 @@
             NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
             NotificationUsageStats usageStats, AtomicFile policyFile,
-            ActivityManager activityManager, GroupHelper groupHelper) {
+            ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am) {
         Resources resources = getContext().getResources();
         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1276,7 +1285,7 @@
 
         mAccessibilityManager =
                 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-        mAm = ActivityManager.getService();
+        mAm = am;
         mPackageManager = packageManager;
         mPackageManagerClient = packageManagerClient;
         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
@@ -1287,6 +1296,11 @@
         mActivityManager = activityManager;
         mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
+        try {
+            mPermissionOwner = mAm.newUriPermissionOwner("notification");
+        } catch (RemoteException e) {
+            Slog.w(TAG, "AM dead", e);
+        }
 
         mHandler = new WorkerHandler(looper);
         mRankingThread.start();
@@ -1415,7 +1429,7 @@
                 null, snoozeHelper, new NotificationUsageStats(getContext()),
                 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
-                getGroupHelper());
+                getGroupHelper(), ActivityManager.getService());
 
         // register for various Intents
         IntentFilter filter = new IntentFilter();
@@ -1593,7 +1607,7 @@
                     && update.getImportance() == IMPORTANCE_NONE)) {
                 getContext().sendBroadcastAsUser(
                         new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
-                                .putExtra(NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID,
+                                .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
                                         update.getId())
                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
                                         update.getImportance() == IMPORTANCE_NONE)
@@ -1631,7 +1645,7 @@
             if (preUpdate.isBlocked() != update.isBlocked()) {
                 getContext().sendBroadcastAsUser(
                         new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
-                                .putExtra(NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID,
+                                .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
                                         update.getId())
                                 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
                                         update.isBlocked())
@@ -1746,14 +1760,29 @@
         return INotificationManager.Stub.asInterface(mService);
     }
 
+    /**
+     * Report to usage stats that the notification was seen.
+     * @param r notification record
+     */
     protected void reportSeen(NotificationRecord r) {
         final int userId = r.sbn.getUserId();
         mAppUsageStats.reportEvent(r.sbn.getPackageName(),
-                userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
+                userId == UserHandle.USER_ALL ? USER_SYSTEM
                         : userId,
                 UsageEvents.Event.NOTIFICATION_SEEN);
     }
 
+    /**
+     * Report to usage stats that the notification was clicked.
+     * @param r notification record
+     */
+    protected void reportUserInteraction(NotificationRecord r) {
+        final int userId = r.sbn.getUserId();
+        mAppUsageStats.reportEvent(r.sbn.getPackageName(),
+                userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId,
+                UsageEvents.Event.USER_INTERACTION);
+    }
+
     @VisibleForTesting
     NotificationManagerInternal getInternalService() {
         return mInternalService;
@@ -2894,7 +2923,7 @@
             checkCallerIsSystem();
             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
             //TODO: http://b/22388012
-            if (user != UserHandle.USER_SYSTEM) {
+            if (user != USER_SYSTEM) {
                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
                 return null;
             }
@@ -2920,7 +2949,7 @@
                 return;
             }
             //TODO: http://b/22388012
-            if (user != UserHandle.USER_SYSTEM) {
+            if (user != USER_SYSTEM) {
                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
                 return;
             }
@@ -3678,7 +3707,7 @@
             sbn.getNotification().flags =
                     (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
             mRankingHelper.sort(mNotificationList);
-            mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
+            mListeners.notifyPostedLocked(r, sbn /* oldSbn */);
         }
     };
 
@@ -3707,7 +3736,7 @@
         try {
             final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                    (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
+                    (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
             Notification.addFieldsFromContext(ai, notification);
 
             int canColorize = mPackageManagerClient.checkPermission(
@@ -3897,6 +3926,7 @@
         return true;
     }
 
+    @GuardedBy("mNotificationLock")
     protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
             String excludedTag) {
         int count = 0;
@@ -4126,6 +4156,8 @@
                         // Make sure we don't lose the foreground service state.
                         notification.flags |=
                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
+                        // revoke uri permissions for changed uris
+                        revokeUriPermissions(r, old);
                         r.isUpdate = true;
                     }
 
@@ -4147,7 +4179,7 @@
 
                     if (notification.getSmallIcon() != null) {
                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
-                        mListeners.notifyPostedLocked(n, oldSbn);
+                        mListeners.notifyPostedLocked(r, oldSbn);
                         if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
                             mHandler.post(new Runnable() {
                                 @Override
@@ -4912,6 +4944,9 @@
             r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
         }
 
+        // Revoke permissions
+        revokeUriPermissions(null, r);
+
         // tell the app
         if (sendDelete) {
             if (r.getNotification().deleteIntent != null) {
@@ -5009,6 +5044,30 @@
                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
     }
 
+    void revokeUriPermissions(NotificationRecord newRecord, NotificationRecord oldRecord) {
+        Set<Uri> oldUris = oldRecord.getNotificationUris();
+        Set<Uri> newUris = newRecord == null ? new HashSet<>() : newRecord.getNotificationUris();
+        oldUris.removeAll(newUris);
+
+        long ident = Binder.clearCallingIdentity();
+        try {
+            for (Uri uri : oldUris) {
+                if (uri != null) {
+                    int notiUserId = oldRecord.getUserId();
+                    int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
+                            : ContentProvider.getUserIdFromUri(uri, notiUserId);
+                    uri = ContentProvider.getUriWithoutUserId(uri);
+                    mAm.revokeUriPermissionFromOwner(mPermissionOwner,
+                            uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId);
+                }
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Count not revoke uri permissions", e);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     /**
      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
      * and none of the {@code mustNotHaveFlags}.
@@ -5851,10 +5910,13 @@
          * but isn't anymore.
          */
         @GuardedBy("mNotificationLock")
-        public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
+        public void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn) {
             // Lazily initialized snapshots of the notification.
+            StatusBarNotification sbn = r.sbn;
             TrimCache trimCache = new TrimCache(sbn);
 
+            Set<Uri> uris = r.getNotificationUris();
+
             for (final ManagedServiceInfo info : getServices()) {
                 boolean sbnVisible = isVisibleToListener(sbn, info);
                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
@@ -5877,6 +5939,9 @@
                     continue;
                 }
 
+                grantUriPermissions(uris, sbn.getUserId(), info.component.getPackageName(),
+                        info.userid);
+
                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
                 mHandler.post(new Runnable() {
                     @Override
@@ -5887,6 +5952,28 @@
             }
         }
 
+        private void grantUriPermissions(Set<Uri> uris, int notiUserId, String listenerPkg,
+                int listenerUserId) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                for (Uri uri : uris) {
+                    if (uri != null) {
+                        int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
+                                : ContentProvider.getUserIdFromUri(uri, notiUserId);
+                        uri = ContentProvider.getUriWithoutUserId(uri);
+                        mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(),
+                                listenerPkg,
+                                uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId,
+                                listenerUserId == USER_ALL ? USER_SYSTEM : listenerUserId);
+                    }
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Count not grant uri permission to " + listenerPkg, e);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
         /**
          * asynchronously notify all listeners about a removed notification
          */
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 23b9743..1ad8c74 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -38,6 +38,7 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.Adjustment;
@@ -47,6 +48,7 @@
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -64,6 +66,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Holds data about notifications that should not be shared with the
@@ -929,6 +932,42 @@
         mStats.setViewedSettings();
     }
 
+    public Set<Uri> getNotificationUris() {
+        Notification notification = getNotification();
+        Set<Uri> uris = new ArraySet<>();
+
+        if (notification.sound != null) {
+            uris.add(notification.sound);
+        }
+        if (notification.getChannelId() != null) {
+            NotificationChannel channel = getChannel();
+            if (channel != null && channel.getSound() != null) {
+                uris.add(channel.getSound());
+            }
+        }
+        if (notification.extras.containsKey(Notification.EXTRA_AUDIO_CONTENTS_URI)) {
+            uris.add(notification.extras.getParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI));
+        }
+        if (notification.extras.containsKey(Notification.EXTRA_BACKGROUND_IMAGE_URI)) {
+            uris.add(notification.extras.getParcelable(Notification.EXTRA_BACKGROUND_IMAGE_URI));
+        }
+        if (Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
+            Parcelable[] newMessages =
+                    notification.extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+            List<Notification.MessagingStyle.Message> messages
+                    = Notification.MessagingStyle.Message.getMessagesFromBundleArray(newMessages);
+            Parcelable[] histMessages =
+                    notification.extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
+            messages.addAll(
+                    Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages));
+            for (Notification.MessagingStyle.Message message : messages) {
+                uris.add(message.getDataUri());
+            }
+        }
+
+        return uris;
+    }
+
     public LogMaker getLogMaker(long now) {
         if (mLogMaker == null) {
             // initialize fields that only change on update (so a new record)
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 7600e81..6e02db7 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -20,6 +20,8 @@
 import static android.content.om.OverlayInfo.STATE_ENABLED;
 import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
 import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
+import static android.content.om.OverlayInfo.STATE_OVERLAY_UPGRADING;
+import static android.content.om.OverlayInfo.STATE_TARGET_UPGRADING;
 
 import static com.android.server.om.OverlayManagerService.DEBUG;
 import static com.android.server.om.OverlayManagerService.TAG;
@@ -50,6 +52,10 @@
  * @see OverlayManagerService
  */
 final class OverlayManagerServiceImpl {
+    // Flags to use in conjunction with updateState.
+    private static final int FLAG_TARGET_IS_UPGRADING = 1<<0;
+    private static final int FLAG_OVERLAY_IS_UPGRADING = 1<<1;
+
     private final PackageManagerHelper mPackageManager;
     private final IdmapManager mIdmapManager;
     private final OverlayManagerSettings mSettings;
@@ -123,9 +129,7 @@
             }
 
             try {
-                final PackageInfo targetPackage =
-                        mPackageManager.getPackageInfo(overlayPackage.overlayTarget, newUserId);
-                updateState(targetPackage, overlayPackage, newUserId);
+                updateState(overlayPackage.overlayTarget, overlayPackage.packageName, newUserId, 0);
             } catch (OverlayManagerSettings.BadKeyException e) {
                 Slog.e(TAG, "failed to update settings", e);
                 mSettings.remove(overlayPackage.packageName, newUserId);
@@ -168,8 +172,7 @@
             Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
         }
 
-        final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
-        if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+        if (updateAllOverlaysForTarget(packageName, userId, 0)) {
             mListener.onOverlaysChanged(packageName, userId);
         }
     }
@@ -179,18 +182,18 @@
             Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
         }
 
-        final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
-        if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+        if (updateAllOverlaysForTarget(packageName, userId, 0)) {
             mListener.onOverlaysChanged(packageName, userId);
         }
     }
 
     void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) {
         if (DEBUG) {
-            Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId=" + userId);
+            Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId="
+                    + userId);
         }
 
-        if (updateAllOverlaysForTarget(packageName, userId, null)) {
+        if (updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING)) {
             mListener.onOverlaysChanged(packageName, userId);
         }
     }
@@ -200,8 +203,7 @@
             Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
         }
 
-        final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
-        if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+        if (updateAllOverlaysForTarget(packageName, userId, 0)) {
             mListener.onOverlaysChanged(packageName, userId);
         }
     }
@@ -211,7 +213,7 @@
             Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
         }
 
-        if (updateAllOverlaysForTarget(packageName, userId, null)) {
+        if (updateAllOverlaysForTarget(packageName, userId, 0)) {
             mListener.onOverlaysChanged(packageName, userId);
         }
     }
@@ -219,20 +221,21 @@
     /**
      * Returns true if the settings were modified for this target.
      */
-    private boolean updateAllOverlaysForTarget(@NonNull final String packageName, final int userId,
-            @Nullable final PackageInfo targetPackage) {
+    private boolean updateAllOverlaysForTarget(@NonNull final String targetPackageName,
+            final int userId, final int flags) {
         boolean modified = false;
-        final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(packageName, userId);
+        final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(targetPackageName, userId);
         final int N = ois.size();
         for (int i = 0; i < N; i++) {
             final OverlayInfo oi = ois.get(i);
-            final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName, userId);
+            final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName,
+                    userId);
             if (overlayPackage == null) {
                 modified |= mSettings.remove(oi.packageName, oi.userId);
                 removeIdmapIfPossible(oi);
             } else {
                 try {
-                    modified |= updateState(targetPackage, overlayPackage, userId);
+                    modified |= updateState(targetPackageName, oi.packageName, userId, flags);
                 } catch (OverlayManagerSettings.BadKeyException e) {
                     Slog.e(TAG, "failed to update settings", e);
                     modified |= mSettings.remove(oi.packageName, userId);
@@ -254,14 +257,11 @@
             return;
         }
 
-        final PackageInfo targetPackage =
-                mPackageManager.getPackageInfo(overlayPackage.overlayTarget, userId);
-
         mSettings.init(packageName, userId, overlayPackage.overlayTarget,
                 overlayPackage.applicationInfo.getBaseCodePath(),
                 overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority);
         try {
-            if (updateState(targetPackage, overlayPackage, userId)) {
+            if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
                 mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
             }
         } catch (OverlayManagerSettings.BadKeyException e) {
@@ -271,15 +271,64 @@
     }
 
     void onOverlayPackageChanged(@NonNull final String packageName, final int userId) {
-        Slog.wtf(TAG, "onOverlayPackageChanged called, but only pre-installed overlays supported");
+        if (DEBUG) {
+            Slog.d(TAG, "onOverlayPackageChanged packageName=" + packageName + " userId=" + userId);
+        }
+
+        try {
+            final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
+            if (updateState(oi.targetPackageName, packageName, userId, 0)) {
+                mListener.onOverlaysChanged(oi.targetPackageName, userId);
+            }
+        } catch (OverlayManagerSettings.BadKeyException e) {
+            Slog.e(TAG, "failed to update settings", e);
+        }
     }
 
     void onOverlayPackageUpgrading(@NonNull final String packageName, final int userId) {
-        Slog.wtf(TAG, "onOverlayPackageUpgrading called, but only pre-installed overlays supported");
+        if (DEBUG) {
+            Slog.d(TAG, "onOverlayPackageUpgrading packageName=" + packageName + " userId="
+                    + userId);
+        }
+
+        try {
+            final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
+            if (updateState(oi.targetPackageName, packageName, userId, FLAG_OVERLAY_IS_UPGRADING)) {
+                removeIdmapIfPossible(oi);
+                mListener.onOverlaysChanged(oi.targetPackageName, userId);
+            }
+        } catch (OverlayManagerSettings.BadKeyException e) {
+            Slog.e(TAG, "failed to update settings", e);
+        }
     }
 
     void onOverlayPackageUpgraded(@NonNull final String packageName, final int userId) {
-        Slog.wtf(TAG, "onOverlayPackageUpgraded called, but only pre-installed overlays supported");
+        if (DEBUG) {
+            Slog.d(TAG, "onOverlayPackageUpgraded packageName=" + packageName + " userId="
+                    + userId);
+        }
+
+        final PackageInfo pkg = mPackageManager.getPackageInfo(packageName, userId);
+        if (pkg == null) {
+            Slog.w(TAG, "overlay package " + packageName + " was upgraded, but couldn't be found");
+            onOverlayPackageRemoved(packageName, userId);
+            return;
+        }
+
+        try {
+            final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
+            if (!oldOi.targetPackageName.equals(pkg.overlayTarget)) {
+                mSettings.init(packageName, userId, pkg.overlayTarget,
+                        pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
+                        pkg.overlayPriority);
+            }
+
+            if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
+                mListener.onOverlaysChanged(pkg.overlayTarget, userId);
+            }
+        } catch (OverlayManagerSettings.BadKeyException e) {
+            Slog.e(TAG, "failed to update settings", e);
+        }
     }
 
     void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) {
@@ -333,10 +382,8 @@
 
         try {
             final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
-            final PackageInfo targetPackage =
-                    mPackageManager.getPackageInfo(oi.targetPackageName, userId);
             boolean modified = mSettings.setEnabled(packageName, userId, enable);
-            modified |= updateState(targetPackage, overlayPackage, userId);
+            modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0);
 
             if (modified) {
                 mListener.onOverlaysChanged(oi.targetPackageName, userId);
@@ -349,7 +396,8 @@
 
     boolean setEnabledExclusive(@NonNull final String packageName, final int userId) {
         if (DEBUG) {
-            Slog.d(TAG, String.format("setEnabledExclusive packageName=%s userId=%d", packageName, userId));
+            Slog.d(TAG, String.format("setEnabledExclusive packageName=%s userId=%d", packageName,
+                    userId));
         }
 
         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
@@ -359,10 +407,9 @@
 
         try {
             final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
-            final PackageInfo targetPackage =
-                    mPackageManager.getPackageInfo(oi.targetPackageName, userId);
+            final String targetPackageName = oi.targetPackageName;
 
-            List<OverlayInfo> allOverlays = getOverlayInfosForTarget(oi.targetPackageName, userId);
+            List<OverlayInfo> allOverlays = getOverlayInfosForTarget(targetPackageName, userId);
 
             boolean modified = false;
 
@@ -384,15 +431,15 @@
 
                 // Disable the overlay.
                 modified |= mSettings.setEnabled(disabledOverlayPackageName, userId, false);
-                modified |= updateState(targetPackage, disabledOverlayPackageInfo, userId);
+                modified |= updateState(targetPackageName, disabledOverlayPackageName, userId, 0);
             }
 
             // Enable the selected overlay.
             modified |= mSettings.setEnabled(packageName, userId, true);
-            modified |= updateState(targetPackage, overlayPackage, userId);
+            modified |= updateState(targetPackageName, packageName, userId, 0);
 
             if (modified) {
-                mListener.onOverlaysChanged(oi.targetPackageName, userId);
+                mListener.onOverlaysChanged(targetPackageName, userId);
             }
             return true;
         } catch (OverlayManagerSettings.BadKeyException e) {
@@ -477,7 +524,8 @@
 
     List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName,
             final int userId) {
-        final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName, userId);
+        final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName,
+                userId);
         final List<String> paths = new ArrayList<>(overlays.size());
         final int N = overlays.size();
         for (int i = 0; i < N; i++) {
@@ -492,36 +540,59 @@
     /**
      * Returns true if the settings/state was modified, false otherwise.
      */
-    private boolean updateState(@Nullable final PackageInfo targetPackage,
-            @NonNull final PackageInfo overlayPackage, final int userId)
+    private boolean updateState(@NonNull final String targetPackageName,
+            @NonNull final String overlayPackageName, final int userId, final int flags)
             throws OverlayManagerSettings.BadKeyException {
+
+        final PackageInfo targetPackage = mPackageManager.getPackageInfo(targetPackageName, userId);
+        final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName,
+                userId);
+
         // Static RROs targeting to "android", ie framework-res.apk, are handled by native layers.
-        if (targetPackage != null &&
-                !("android".equals(targetPackage.packageName)
+        if (targetPackage != null && overlayPackage != null &&
+                !("android".equals(targetPackageName)
                         && overlayPackage.isStaticOverlayPackage())) {
             mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
         }
 
-        boolean modified = mSettings.setBaseCodePath(overlayPackage.packageName, userId,
-                overlayPackage.applicationInfo.getBaseCodePath());
+        boolean modified = false;
+        if (overlayPackage != null) {
+            modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
+                    overlayPackage.applicationInfo.getBaseCodePath());
+        }
 
-        final int currentState = mSettings.getState(overlayPackage.packageName, userId);
-        final int newState = calculateNewState(targetPackage, overlayPackage, userId);
+        final @OverlayInfo.State int currentState = mSettings.getState(overlayPackageName, userId);
+        final @OverlayInfo.State int newState = calculateNewState(targetPackage, overlayPackage,
+                userId, flags);
         if (currentState != newState) {
             if (DEBUG) {
                 Slog.d(TAG, String.format("%s:%d: %s -> %s",
-                            overlayPackage.packageName, userId,
+                            overlayPackageName, userId,
                             OverlayInfo.stateToString(currentState),
                             OverlayInfo.stateToString(newState)));
             }
-            modified |= mSettings.setState(overlayPackage.packageName, userId, newState);
+            modified |= mSettings.setState(overlayPackageName, userId, newState);
         }
         return modified;
     }
 
-    private int calculateNewState(@Nullable final PackageInfo targetPackage,
-            @NonNull final PackageInfo overlayPackage, final int userId)
+    private @OverlayInfo.State int calculateNewState(@Nullable final PackageInfo targetPackage,
+            @Nullable final PackageInfo overlayPackage, final int userId, final int flags)
         throws OverlayManagerSettings.BadKeyException {
+
+        if ((flags & FLAG_TARGET_IS_UPGRADING) != 0) {
+            return STATE_TARGET_UPGRADING;
+        }
+
+        if ((flags & FLAG_OVERLAY_IS_UPGRADING) != 0) {
+            return STATE_OVERLAY_UPGRADING;
+        }
+
+        // assert expectation on overlay package: can only be null if the flags are used
+        if (DEBUG && overlayPackage == null) {
+            throw new IllegalArgumentException("null overlay package not compatible with no flags");
+        }
+
         if (targetPackage == null) {
             return STATE_MISSING_TARGET;
         }
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 17b38de..a80cae4 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -145,7 +145,8 @@
         return mItems.get(idx).setEnabled(enable);
     }
 
-    int getState(@NonNull final String packageName, final int userId) throws BadKeyException {
+    @OverlayInfo.State int getState(@NonNull final String packageName, final int userId)
+            throws BadKeyException {
         final int idx = select(packageName, userId);
         if (idx < 0) {
             throw new BadKeyException(packageName, userId);
@@ -156,8 +157,8 @@
     /**
      * Returns true if the settings were modified, false if they remain the same.
      */
-    boolean setState(@NonNull final String packageName, final int userId, final int state)
-            throws BadKeyException {
+    boolean setState(@NonNull final String packageName, final int userId,
+            final @OverlayInfo.State int state) throws BadKeyException {
         final int idx = select(packageName, userId);
         if (idx < 0) {
             throw new BadKeyException(packageName, userId);
@@ -413,7 +414,7 @@
         private final String mPackageName;
         private final String mTargetPackageName;
         private String mBaseCodePath;
-        private int mState;
+        private @OverlayInfo.State int mState;
         private boolean mIsEnabled;
         private OverlayInfo mCache;
         private boolean mIsStatic;
@@ -421,7 +422,7 @@
 
         SettingsItem(@NonNull final String packageName, final int userId,
                 @NonNull final String targetPackageName, @NonNull final String baseCodePath,
-                final int state, final boolean isEnabled, final boolean isStatic,
+                final @OverlayInfo.State int state, final boolean isEnabled, final boolean isStatic,
                 final int priority) {
             mPackageName = packageName;
             mUserId = userId;
@@ -462,11 +463,11 @@
             return false;
         }
 
-        private int getState() {
+        private @OverlayInfo.State int getState() {
             return mState;
         }
 
-        private boolean setState(final int state) {
+        private boolean setState(final @OverlayInfo.State int state) {
             if (mState != state) {
                 mState = state;
                 invalidateCache();
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 30088dd..fb81ebf 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -274,7 +274,7 @@
             }
 
             // Propagate permissions before removing any state
-            propagateInstantAppPermissionsIfNeeded(pkg.packageName, userId);
+            propagateInstantAppPermissionsIfNeeded(pkg, userId);
 
             // Track instant apps
             if (ps.getInstantApp(userId)) {
@@ -869,10 +869,10 @@
         return uninstalledApps;
     }
 
-    private void propagateInstantAppPermissionsIfNeeded(@NonNull String packageName,
+    private void propagateInstantAppPermissionsIfNeeded(@NonNull PackageParser.Package pkg,
             @UserIdInt int userId) {
         InstantAppInfo appInfo = peekOrParseUninstalledInstantAppInfo(
-                packageName, userId);
+                pkg.packageName, userId);
         if (appInfo == null) {
             return;
         }
@@ -884,8 +884,8 @@
             for (String grantedPermission : appInfo.getGrantedPermissions()) {
                 final boolean propagatePermission =
                         mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission);
-                if (propagatePermission) {
-                    mService.grantRuntimePermission(packageName, grantedPermission, userId);
+                if (propagatePermission && pkg.requestedPermissions.contains(grantedPermission)) {
+                    mService.grantRuntimePermission(pkg.packageName, grantedPermission, userId);
                 }
             }
         } finally {
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index af446ba..bc9fa4b 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -126,17 +126,16 @@
         final Intent origIntent = requestObj.origIntent;
         final Intent sanitizedIntent = sanitizeIntent(origIntent);
 
-        final InstantAppDigest digest = getInstantAppDigest(origIntent);
-        final int[] shaPrefix = digest.getDigestPrefix();
         AuxiliaryResolveInfo resolveInfo = null;
         @ResolutionStatus int resolutionStatus = RESOLUTION_SUCCESS;
         try {
             final List<InstantAppResolveInfo> instantAppResolveInfoList =
-                    connection.getInstantAppResolveInfoList(sanitizedIntent, shaPrefix, token);
+                    connection.getInstantAppResolveInfoList(sanitizedIntent,
+                            requestObj.digest.getDigestPrefixSecure(), token);
             if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
                 resolveInfo = InstantAppResolver.filterInstantAppIntent(
                         instantAppResolveInfoList, origIntent, requestObj.resolvedType,
-                        requestObj.userId, origIntent.getPackage(), digest, token);
+                        requestObj.userId, origIntent.getPackage(), requestObj.digest, token);
             }
         } catch (ConnectionException e) {
             if (e.failure == ConnectionException.FAILURE_BIND) {
@@ -166,12 +165,6 @@
         return resolveInfo;
     }
 
-    private static InstantAppDigest getInstantAppDigest(Intent origIntent) {
-        return origIntent.getData() != null && !TextUtils.isEmpty(origIntent.getData().getHost())
-                ? new InstantAppDigest(origIntent.getData().getHost(), 5 /*maxDigests*/)
-                : InstantAppDigest.UNDEFINED;
-    }
-
     public static void doInstantAppResolutionPhaseTwo(Context context,
             InstantAppResolverConnection connection, InstantAppRequest requestObj,
             ActivityInfo instantAppInstaller, Handler callbackHandler) {
@@ -182,8 +175,6 @@
         }
         final Intent origIntent = requestObj.origIntent;
         final Intent sanitizedIntent = sanitizeIntent(origIntent);
-        final InstantAppDigest digest = getInstantAppDigest(origIntent);
-        final int[] shaPrefix = digest.getDigestPrefix();
 
         final PhaseTwoCallback callback = new PhaseTwoCallback() {
             @Override
@@ -194,7 +185,8 @@
                     final AuxiliaryResolveInfo instantAppIntentInfo =
                             InstantAppResolver.filterInstantAppIntent(
                                     instantAppResolveInfoList, origIntent, null /*resolvedType*/,
-                                    0 /*userId*/, origIntent.getPackage(), digest, token);
+                                    0 /*userId*/, origIntent.getPackage(), requestObj.digest,
+                                    token);
                     if (instantAppIntentInfo != null) {
                         failureIntent = instantAppIntentInfo.failureIntent;
                     } else {
@@ -225,8 +217,9 @@
             }
         };
         try {
-            connection.getInstantAppIntentFilterList(sanitizedIntent, shaPrefix, token, callback,
-                    callbackHandler, startTime);
+            connection.getInstantAppIntentFilterList(sanitizedIntent,
+                    requestObj.digest.getDigestPrefixSecure(), token, callback, callbackHandler,
+                    startTime);
         } catch (ConnectionException e) {
             @ResolutionStatus int resolutionStatus = RESOLUTION_FAILURE;
             if (e.failure == ConnectionException.FAILURE_BIND) {
@@ -377,7 +370,7 @@
         failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
         failureIntent.setLaunchToken(token);
         ArrayList<AuxiliaryResolveInfo.AuxiliaryFilter> filters = null;
-        boolean isWebIntent = origIntent.isBrowsableWebIntent();
+        boolean isWebIntent = origIntent.isWebIntent();
         for (InstantAppResolveInfo instantAppResolveInfo : instantAppResolveInfoList) {
             if (shaPrefix.length > 0 && instantAppResolveInfo.shouldLetInstallerDecide()) {
                 Slog.e(TAG, "InstantAppResolveInfo with mShouldLetInstallerDecide=true when digest"
@@ -448,7 +441,7 @@
                 instantAppInfo.getIntentFilters();
         if (instantAppFilters == null || instantAppFilters.isEmpty()) {
             // No filters on web intent; no matches, 2nd phase unnecessary.
-            if (origIntent.isBrowsableWebIntent()) {
+            if (origIntent.isWebIntent()) {
                 return null;
             }
             // No filters; we need to start phase two
diff --git a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
index a9ee411..98f421e 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
@@ -141,6 +141,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void waitForBindLocked(String token) throws TimeoutException, InterruptedException {
         final long startMillis = SystemClock.uptimeMillis();
         while (mBindState != STATE_IDLE) {
@@ -250,6 +251,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void handleBinderDiedLocked() {
         if (mRemoteInstance != null) {
             try {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 59f9dae..0b32d1a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -226,6 +226,7 @@
         }
     }
 
+    @GuardedBy("mSessions")
     private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) {
         final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
         final ArraySet<File> unclaimedStages = newArraySet(
@@ -283,6 +284,7 @@
         }
     }
 
+    @GuardedBy("mSessions")
     private void readSessionsLocked() {
         if (LOGD) Slog.v(TAG, "readSessionsLocked()");
 
@@ -340,6 +342,7 @@
         }
     }
 
+    @GuardedBy("mSessions")
     private void addHistoricalSessionLocked(PackageInstallerSession session) {
         CharArrayWriter writer = new CharArrayWriter();
         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "    ");
@@ -352,6 +355,7 @@
                 mHistoricalSessionsByInstaller.get(installerUid) + 1);
     }
 
+    @GuardedBy("mSessions")
     private void writeSessionsLocked() {
         if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
 
@@ -612,6 +616,7 @@
         }
     }
 
+    @GuardedBy("mSessions")
     private int allocateSessionIdLocked() {
         int n = 0;
         int sessionId;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3dd5a34..9c69281 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -318,6 +318,7 @@
     /**
      * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
      */
+    @GuardedBy("mLock")
     private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
         DevicePolicyManagerInternal dpmi =
                 LocalServices.getService(DevicePolicyManagerInternal.class);
@@ -334,6 +335,7 @@
      *
      * @return {@code true} iff we need to ask to confirm the permissions?
      */
+    @GuardedBy("mLock")
     private boolean needToAskForPermissionsLocked() {
         if (mPermissionsManuallyAccepted) {
             return false;
@@ -456,6 +458,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void assertPreparedAndNotSealedLocked(String cookie) {
         assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
         if (mSealed) {
@@ -463,6 +466,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
         assertPreparedAndNotDestroyedLocked(cookie);
         if (mCommitted) {
@@ -470,6 +474,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void assertPreparedAndNotDestroyedLocked(String cookie) {
         if (!mPrepared) {
             throw new IllegalStateException(cookie + " before prepared");
@@ -484,6 +489,7 @@
      * might point at an ASEC mount point, which is why we delay path resolution
      * until someone actively works with the session.
      */
+    @GuardedBy("mLock")
     private File resolveStageDirLocked() throws IOException {
         if (mResolvedStageDir == null) {
             if (stageDir != null) {
@@ -516,6 +522,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void computeProgressLocked(boolean forcePublish) {
         mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
                 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
@@ -728,6 +735,7 @@
      * Check if the caller is the owner of this session. Otherwise throw a
      * {@link SecurityException}.
      */
+    @GuardedBy("mLock")
     private void assertCallerIsOwnerOrRootLocked() {
         final int callingUid = Binder.getCallingUid();
         if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
@@ -738,6 +746,7 @@
     /**
      * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
      */
+    @GuardedBy("mLock")
     private void assertNoWriteFileTransfersOpenLocked() {
         // Verify that all writers are hands-off
         for (RevocableFileDescriptor fd : mFds) {
@@ -820,6 +829,7 @@
      * @throws PackageManagerException if the session was sealed but something went wrong. If the
      *                                 session was sealed this is the only possible exception.
      */
+    @GuardedBy("mLock")
     private void sealAndValidateLocked() throws PackageManagerException, IOException {
         assertNoWriteFileTransfersOpenLocked();
         assertPreparedAndNotDestroyedLocked("sealing of session");
@@ -901,6 +911,7 @@
         mCallback.onSessionSealedBlocking(this);
     }
 
+    @GuardedBy("mLock")
     private void commitLocked()
             throws PackageManagerException {
         if (mDestroyed) {
@@ -1016,6 +1027,7 @@
      * Note that upgrade compatibility is still performed by
      * {@link PackageManagerService}.
      */
+    @GuardedBy("mLock")
     private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
             throws PackageManagerException {
         mPackageName = null;
@@ -1228,6 +1240,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void assertApkConsistentLocked(String tag, ApkLite apk)
             throws PackageManagerException {
         if (!mPackageName.equals(apk.packageName)) {
@@ -1511,6 +1524,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void dumpLocked(IndentingPrintWriter pw) {
         pw.println("Session " + sessionId + ":");
         pw.increaseIndent();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 940d19f..3cd24f9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -797,6 +797,7 @@
             return overlayPackages;
         }
 
+        @GuardedBy("mInstallLock")
         final String[] getStaticOverlayPathsLocked(Collection<PackageParser.Package> allPackages,
                 String targetPackageName, String targetPath) {
             if ("android".equals(targetPackageName)) {
@@ -964,7 +965,7 @@
     volatile boolean mSystemReady;
     volatile boolean mSafeMode;
     volatile boolean mHasSystemUidErrors;
-    private volatile boolean mEphemeralAppsDisabled;
+    private volatile boolean mWebInstantAppsDisabled;
 
     ApplicationInfo mAndroidApplication;
     final ActivityInfo mResolveActivity = new ActivityInfo();
@@ -2746,12 +2747,6 @@
                                 mSettings.getDisabledSystemPkgLPr(ps.name);
                         if (disabledPs.codePath == null || !disabledPs.codePath.exists()
                                 || disabledPs.pkg == null) {
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Possibly deleted app: " + ps.dumpState_temp()
-        + "; path: " + (disabledPs.codePath == null ? "<<NULL>>":disabledPs.codePath)
-        + "; pkg: " + (disabledPs.pkg==null?"<<NULL>>":disabledPs.pkg.toString()));
-}
                             possiblyDeletedUpdatedSystemApps.add(ps.name);
                         }
                     }
@@ -2803,10 +2798,6 @@
                 for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
                     PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
                     mSettings.removeDisabledSystemPackageLPw(deletedAppName);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "remove update; name: " + deletedAppName + ", exists? " + (deletedPkg != null));
-}
                     final String msg;
                     if (deletedPkg == null) {
                         // should have found an update, but, we didn't; remove everything
@@ -5226,7 +5217,13 @@
 
     @Override
     public int checkUidPermission(String permName, int uid) {
-        return mPermissionManager.checkUidPermission(permName, uid, getCallingUid());
+        synchronized (mPackages) {
+            final String[] packageNames = getPackagesForUid(uid);
+            final PackageParser.Package pkg = (packageNames != null && packageNames.length > 0)
+                    ? mPackages.get(packageNames[0])
+                    : null;
+            return mPermissionManager.checkUidPermission(permName, pkg, uid, getCallingUid());
+        }
     }
 
     @Override
@@ -5960,11 +5957,11 @@
     /**
      * Returns whether or not instant apps have been disabled remotely.
      */
-    private boolean isEphemeralDisabled() {
-        return mEphemeralAppsDisabled;
+    private boolean areWebInstantAppsDisabled() {
+        return mWebInstantAppsDisabled;
     }
 
-    private boolean isInstantAppAllowed(
+    private boolean isInstantAppResolutionAllowed(
             Intent intent, List<ResolveInfo> resolvedActivities, int userId,
             boolean skipPackageCheck) {
         if (mInstantAppResolverConnection == null) {
@@ -5982,15 +5979,19 @@
         if (!skipPackageCheck && intent.getPackage() != null) {
             return false;
         }
-        if (!intent.isBrowsableWebIntent()) {
+        if (!intent.isWebIntent()) {
             // for non web intents, we should not resolve externally if an app already exists to
             // handle it or if the caller didn't explicitly request it.
             if ((resolvedActivities != null && resolvedActivities.size() != 0)
                     || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) == 0) {
                 return false;
             }
-        } else if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) {
-            return false;
+        } else {
+            if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) {
+                return false;
+            } else if (areWebInstantAppsDisabled()) {
+                return false;
+            }
         }
         // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
         // Or if there's already an ephemeral app installed that handles the action
@@ -6521,14 +6522,13 @@
                 }
             }
             return applyPostResolutionFilter(
-                    list, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId);
+                    list, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId, intent);
         }
 
         // reader
         boolean sortResult = false;
-        boolean addEphemeral = false;
+        boolean addInstant = false;
         List<ResolveInfo> result;
-        final boolean ephemeralDisabled = isEphemeralDisabled();
         synchronized (mPackages) {
             if (pkgName == null) {
                 List<CrossProfileIntentFilter> matchingFilters =
@@ -6541,14 +6541,14 @@
                     xpResult.add(xpResolveInfo);
                     return applyPostResolutionFilter(
                             filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
-                            allowDynamicSplits, filterCallingUid, userId);
+                            allowDynamicSplits, filterCallingUid, userId, intent);
                 }
 
                 // Check for results in the current profile.
                 result = filterIfNotSystemUser(mActivities.queryIntent(
                         intent, resolvedType, flags, userId), userId);
-                addEphemeral = !ephemeralDisabled
-                        && isInstantAppAllowed(intent, result, userId, false /*skipPackageCheck*/);
+                addInstant = isInstantAppResolutionAllowed(intent, result, userId,
+                        false /*skipPackageCheck*/);
                 // Check for cross profile results.
                 boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
                 xpResolveInfo = queryCrossProfileIntents(
@@ -6575,20 +6575,20 @@
                             // in the result.
                             result.remove(xpResolveInfo);
                         }
-                        if (result.size() == 0 && !addEphemeral) {
+                        if (result.size() == 0 && !addInstant) {
                             // No result in current profile, but found candidate in parent user.
                             // And we are not going to add emphemeral app, so we can return the
                             // result straight away.
                             result.add(xpDomainInfo.resolveInfo);
                             return applyPostResolutionFilter(result, instantAppPkgName,
-                                    allowDynamicSplits, filterCallingUid, userId);
+                                    allowDynamicSplits, filterCallingUid, userId, intent);
                         }
-                    } else if (result.size() <= 1 && !addEphemeral) {
+                    } else if (result.size() <= 1 && !addInstant) {
                         // No result in parent user and <= 1 result in current profile, and we
                         // are not going to add emphemeral app, so we can return the result without
                         // further processing.
                         return applyPostResolutionFilter(result, instantAppPkgName,
-                                allowDynamicSplits, filterCallingUid, userId);
+                                allowDynamicSplits, filterCallingUid, userId, intent);
                     }
                     // We have more than one candidate (combining results from current and parent
                     // profile), so we need filtering and sorting.
@@ -6608,8 +6608,7 @@
                 if (result == null || result.size() == 0) {
                     // the caller wants to resolve for a particular package; however, there
                     // were no installed results, so, try to find an ephemeral result
-                    addEphemeral = !ephemeralDisabled
-                            && isInstantAppAllowed(
+                    addInstant = isInstantAppResolutionAllowed(
                                     intent, null /*result*/, userId, true /*skipPackageCheck*/);
                     if (result == null) {
                         result = new ArrayList<>();
@@ -6617,7 +6616,7 @@
                 }
             }
         }
-        if (addEphemeral) {
+        if (addInstant) {
             result = maybeAddInstantAppInstaller(
                     result, intent, resolvedType, flags, userId, resolveForStart);
         }
@@ -6625,7 +6624,7 @@
             Collections.sort(result, mResolvePrioritySorter);
         }
         return applyPostResolutionFilter(
-                result, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId);
+                result, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId, intent);
     }
 
     private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
@@ -6693,7 +6692,7 @@
                                         ai.packageName, ai.versionCode, null /* splitName */);
             }
         }
-        if (intent.isBrowsableWebIntent() && auxiliaryResponse == null) {
+        if (intent.isWebIntent() && auxiliaryResponse == null) {
             return result;
         }
         final PackageSetting ps = mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
@@ -6829,12 +6828,20 @@
      * @param resolveInfos The pre-filtered list of resolved activities
      * @param ephemeralPkgName The ephemeral package name. If {@code null}, no filtering
      *          is performed.
+     * @param intent
      * @return A filtered list of resolved activities.
      */
     private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos,
-            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, int userId) {
+            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, int userId,
+            Intent intent) {
+        final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled();
         for (int i = resolveInfos.size() - 1; i >= 0; i--) {
             final ResolveInfo info = resolveInfos.get(i);
+            // remove locally resolved instant app web results when disabled
+            if (info.isInstantAppAvailable && blockInstant) {
+                resolveInfos.remove(i);
+                continue;
+            }
             // allow activities that are defined in the provided package
             if (allowDynamicSplits
                     && info.activityInfo != null
@@ -7466,7 +7473,7 @@
                 }
             }
             return applyPostResolutionFilter(
-                    list, instantAppPkgName, allowDynamicSplits, callingUid, userId);
+                    list, instantAppPkgName, allowDynamicSplits, callingUid, userId, intent);
         }
 
         // reader
@@ -7476,14 +7483,14 @@
                 final List<ResolveInfo> result =
                         mReceivers.queryIntent(intent, resolvedType, flags, userId);
                 return applyPostResolutionFilter(
-                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId);
+                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId, intent);
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 final List<ResolveInfo> result = mReceivers.queryIntentForPackage(
                         intent, resolvedType, flags, pkg.receivers, userId);
                 return applyPostResolutionFilter(
-                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId);
+                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId, intent);
             }
             return Collections.emptyList();
         }
@@ -7953,7 +7960,7 @@
 
     @Override
     public ParceledListSlice<InstantAppInfo> getInstantApps(int userId) {
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return null;
         }
         if (!canViewInstantApps(Binder.getCallingUid(), userId)) {
@@ -7978,7 +7985,7 @@
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */,
                 "isInstantApp");
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return false;
         }
 
@@ -8004,7 +8011,7 @@
 
     @Override
     public byte[] getInstantAppCookie(String packageName, int userId) {
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return null;
         }
 
@@ -8022,7 +8029,7 @@
 
     @Override
     public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) {
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return true;
         }
 
@@ -8040,7 +8047,7 @@
 
     @Override
     public Bitmap getInstantAppIcon(String packageName, int userId) {
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return null;
         }
 
@@ -8534,8 +8541,6 @@
         return false;
     }
 
-    // Temporary to catch potential issues with refactoring
-    private static boolean REFACTOR_DEBUG = true;
     /**
      * Adds a new package to the internal data structures during platform initialization.
      * <p>After adding, the package is known to the system and available for querying.
@@ -8576,10 +8581,6 @@
         synchronized (mPackages) {
             renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
             final String realPkgName = getRealPackageName(pkg, renamedPkgName);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Add pkg: " + pkg.packageName + (realPkgName==null?"":", realName: " + realPkgName));
-}
             if (realPkgName != null) {
                 ensurePackageRenamed(pkg, renamedPkgName);
             }
@@ -8594,12 +8595,6 @@
             if (DEBUG_INSTALL && isSystemPkgUpdated) {
                 Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
             }
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "SSP? " + scanSystemPartition
-        + ", exists? " + pkgAlreadyExists + (pkgAlreadyExists?" "+pkgSetting.toString():"")
-        + ", upgraded? " + isSystemPkgUpdated + (isSystemPkgUpdated?" "+disabledPkgSetting.toString():""));
-}
 
             final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null)
                     ? mSettings.getSharedUserLPw(pkg.mSharedUserId,
@@ -8611,12 +8606,6 @@
                 Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
                         + " (uid=" + sharedUserSetting.userId + "):"
                         + " packages=" + sharedUserSetting.packages);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Shared UserID " + pkg.mSharedUserId
-        + " (uid=" + sharedUserSetting.userId + "):"
-        + " packages=" + sharedUserSetting.packages);
-}
             }
 
             if (scanSystemPartition) {
@@ -8625,10 +8614,6 @@
                 // version on /data, cycle through all of its children packages and
                 // remove children that are no longer defined.
                 if (isSystemPkgUpdated) {
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Disable child packages");
-}
                     final int scannedChildCount = (pkg.childPackages != null)
                             ? pkg.childPackages.size() : 0;
                     final int disabledChildCount = disabledPkgSetting.childPackageNames != null
@@ -8640,19 +8625,11 @@
                         for (int j = 0; j < scannedChildCount; j++) {
                             PackageParser.Package childPkg = pkg.childPackages.get(j);
                             if (childPkg.packageName.equals(disabledChildPackageName)) {
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Ignore " + disabledChildPackageName);
-}
                                 disabledPackageAvailable = true;
                                 break;
                             }
                         }
                         if (!disabledPackageAvailable) {
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Disable " + disabledChildPackageName);
-}
                             mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
                         }
                     }
@@ -8661,44 +8638,17 @@
                             disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */,
                             null /* originalPkgSetting */, null, parseFlags, scanFlags,
                             (pkg == mPlatformPackage), user);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Scan disabled system package");
-Slog.e("TODD",
-        "Pre: " + request.pkgSetting.dumpState_temp());
-}
-final ScanResult result =
                     scanPackageOnlyLI(request, mFactoryTest, -1L);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Post: " + (result.success?result.pkgSetting.dumpState_temp():"FAILED scan"));
-}
                 }
             }
         }
 
         final boolean newPkgChangedPaths =
                 pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "paths changed? " + newPkgChangedPaths
-        + "; old: " + pkg.codePath
-        + ", new: " + (pkgSetting==null?"<<NULL>>":pkgSetting.codePathString));
-}
         final boolean newPkgVersionGreater =
                 pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode;
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "version greater? " + newPkgVersionGreater
-        + "; old: " + pkg.getLongVersionCode()
-        + ", new: " + (pkgSetting==null?"<<NULL>>":pkgSetting.versionCode));
-}
         final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
                 && newPkgChangedPaths && newPkgVersionGreater;
-if (REFACTOR_DEBUG) {
-    Slog.e("TODD",
-            "system better? " + isSystemPkgBetter);
-}
         if (isSystemPkgBetter) {
             // The version of the application on /system is greater than the version on
             // /data. Switch back to the application on /system.
@@ -8714,13 +8664,6 @@
                     + " name: " + pkgSetting.name
                     + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
                     + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "System package changed;"
-        + " name: " + pkgSetting.name
-        + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
-        + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
-}
 
             final InstallArgs args = createInstallArgsForExisting(
                     packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString,
@@ -8732,10 +8675,6 @@
         }
 
         if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "THROW exception; system pkg version not good enough");
-}
             // The version of the application on the /system partition is less than or
             // equal to the version on the /data partition. Throw an exception and use
             // the application already installed on the /data partition.
@@ -8766,11 +8705,6 @@
                 logCriticalInfo(Log.WARN,
                         "System package signature mismatch;"
                         + " name: " + pkgSetting.name);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "System package signature mismatch;"
-        + " name: " + pkgSetting.name);
-}
                 try (PackageFreezer freezer = freezePackage(pkg.packageName,
                         "scanPackageInternalLI")) {
                     deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
@@ -8785,13 +8719,6 @@
                         + " name: " + pkgSetting.name
                         + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
                         + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "System package enabled;"
-        + " name: " + pkgSetting.name
-        + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
-        + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
-}
                 InstallArgs args = createInstallArgsForExisting(
                         packageFlagsToInstallFlags(pkgSetting), pkgSetting.codePathString,
                         pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
@@ -8808,35 +8735,13 @@
                         + " name: " + pkgSetting.name
                         + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode
                         + "; new: " + pkg.codePath + " @ " + pkg.codePath);
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "System package disabled;"
-        + " name: " + pkgSetting.name
-        + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode
-        + "; new: " + pkg.codePath + " @ " + pkg.codePath);
-}
             }
         }
 
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Scan package");
-Slog.e("TODD",
-        "Pre: " + (pkgSetting==null?"<<NONE>>":pkgSetting.dumpState_temp()));
-}
         final PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags
                 | SCAN_UPDATE_SIGNATURE, currentTime, user);
-if (REFACTOR_DEBUG) {
-pkgSetting = mSettings.getPackageLPr(pkg.packageName);
-Slog.e("TODD",
-        "Post: " + (pkgSetting==null?"<<NONE>>":pkgSetting.dumpState_temp()));
-}
 
         if (shouldHideSystemApp) {
-if (REFACTOR_DEBUG) {
-Slog.e("TODD",
-        "Disable package: " + pkg.packageName);
-}
             synchronized (mPackages) {
                 mSettings.disableSystemPackageLPw(pkg.packageName, true);
             }
@@ -9127,6 +9032,7 @@
         }
     }
 
+    @GuardedBy("mPackages")
     private void notifyPackageUseLocked(String packageName, int reason) {
         final PackageParser.Package p = mPackages.get(packageName);
         if (p == null) {
@@ -10737,8 +10643,6 @@
                     ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
             pkg.applicationInfo.privateFlags &=
                     ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
-            // clear protected broadcasts
-            pkg.protectedBroadcasts = null;
             // cap permission priorities
             if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) {
                 for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) {
@@ -10747,6 +10651,8 @@
             }
         }
         if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
+            // clear protected broadcasts
+            pkg.protectedBroadcasts = null;
             // ignore export request for single user receivers
             if (pkg.receivers != null) {
                 for (int i = pkg.receivers.size() - 1; i >= 0; --i) {
@@ -14066,6 +13972,7 @@
         }
     }
 
+    @GuardedBy("mPackages")
     private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
         if (isPackageDeviceAdmin(packageName, userId)) {
             Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
@@ -16722,6 +16629,12 @@
                 if (userId != UserHandle.USER_ALL) {
                     ps.setInstalled(true, userId);
                     ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
+                } else {
+                    for (int currentUserId : sUserManager.getUserIds()) {
+                        ps.setInstalled(true, currentUserId);
+                        ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId,
+                                installerPackageName);
+                    }
                 }
 
                 // When replacing an existing package, preserve the original install reason for all
@@ -19205,8 +19118,21 @@
     public void deleteApplicationCacheFilesAsUser(final String packageName, final int userId,
             final IPackageDataObserver observer) {
         final int callingUid = Binder.getCallingUid();
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.DELETE_CACHE_FILES, null);
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES)
+                != PackageManager.PERMISSION_GRANTED) {
+            // If the caller has the old delete cache permission, silently ignore.  Else throw.
+            if (mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.DELETE_CACHE_FILES)
+                    == PackageManager.PERMISSION_GRANTED) {
+                Slog.w(TAG, "Calling uid " + callingUid + " does not have " +
+                        android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES +
+                        ", silently ignoring");
+                return;
+            }
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES, null);
+        }
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 /* requireFullPermission= */ true, /* checkShell= */ false,
                 "delete application cache files");
@@ -20808,7 +20734,7 @@
         ContentObserver co = new ContentObserver(mHandler) {
             @Override
             public void onChange(boolean selfChange) {
-                mEphemeralAppsDisabled =
+                mWebInstantAppsDisabled =
                         (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) ||
                                 (Secure.getInt(resolver, Secure.INSTANT_APPS_ENABLED, 1) == 0);
             }
@@ -20816,7 +20742,7 @@
         mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
                         .getUriFor(Global.ENABLE_EPHEMERAL_FEATURE),
                 false, co, UserHandle.USER_SYSTEM);
-        mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
+        mContext.getContentResolver().registerContentObserver(android.provider.Settings.Secure
                         .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
         co.onChange(true);
 
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 3e2bd4a..ea05b74 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -97,35 +97,6 @@
             + " " + name + "/" + appId + "}";
     }
 
-    // Temporary to catch potential issues with refactoring
-    public String dumpState_temp() {
-        String flags = "";
-        flags += ((pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ? "U" : "");
-        flags += ((pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0 ? "S" : "");
-        if ("".equals(flags)) {
-            flags = "-";
-        }
-        String privFlags = "";
-        privFlags += ((pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0 ? "P" : "");
-        privFlags += ((pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0 ? "O" : "");
-        privFlags += ((pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0 ? "V" : "");
-        if ("".equals(privFlags)) {
-            privFlags = "-";
-        }
-        return "PackageSetting{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + name + (realName == null ? "" : "("+realName+")") + "/" + appId + (sharedUser==null?"":" u:" + sharedUser.name+"("+sharedUserId+")")
-                + ", ver:" + versionCode
-                + ", path: " + codePath
-                + ", pABI: " + primaryCpuAbiString
-                + ", sABI: " + secondaryCpuAbiString
-                + ", oABI: " + cpuAbiOverrideString
-                + ", flags: " + flags
-                + ", privFlags: " + privFlags
-                + ", pkg: " + (pkg == null ? "<<NULL>>" : pkg.dumpState_temp())
-                + "}";
-    }
-
     public void copyFrom(PackageSetting orig) {
         super.copyFrom(orig);
         doCopy(orig);
diff --git a/services/core/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java
index 95f490e..471729e 100644
--- a/services/core/java/com/android/server/pm/PackageSignatures.java
+++ b/services/core/java/com/android/server/pm/PackageSignatures.java
@@ -318,7 +318,7 @@
                         mSigningDetails.signatures[i].hashCode()));
             }
         }
-        buf.append("]}");
+        buf.append("]");
         buf.append(", past signatures:[");
         if (mSigningDetails.pastSigningCertificates != null) {
             for (int i = 0; i < mSigningDetails.pastSigningCertificates.length; i++) {
@@ -329,6 +329,7 @@
                 buf.append(Integer.toHexString(mSigningDetails.pastSigningCertificatesFlags[i]));
             }
         }
+        buf.append("]}");
         return buf.toString();
     }
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a85d6d8..034fd23 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -530,6 +530,7 @@
         return processState <= PROCESS_STATE_FOREGROUND_THRESHOLD;
     }
 
+    @GuardedBy("mLock")
     boolean isUidForegroundLocked(int uid) {
         if (uid == Process.SYSTEM_UID) {
             // IUidObserver doesn't report the state of SYSTEM, but it always has bound services,
@@ -545,6 +546,7 @@
         return isProcessStateForeground(mActivityManagerInternal.getUidProcessState(uid));
     }
 
+    @GuardedBy("mLock")
     long getUidLastForegroundElapsedTimeLocked(int uid) {
         return mUidLastForegroundElapsedTime.get(uid);
     }
@@ -638,6 +640,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void unloadUserLocked(int userId) {
         if (DEBUG) {
             Slog.d(TAG, "unloadUserLocked: user=" + userId);
@@ -864,6 +867,7 @@
         writeAttr(out, name, intent.toUri(/* flags =*/ 0));
     }
 
+    @GuardedBy("mLock")
     @VisibleForTesting
     void saveBaseStateLocked() {
         final AtomicFile file = getBaseStateFile();
@@ -896,6 +900,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void loadBaseStateLocked() {
         mRawLastResetTime = 0;
 
@@ -948,6 +953,7 @@
         return new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
     }
 
+    @GuardedBy("mLock")
     private void saveUserLocked(@UserIdInt int userId) {
         final File path = getUserFile(userId);
         if (DEBUG) {
@@ -974,6 +980,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os,
             boolean forBackup) throws IOException, XmlPullParserException {
 
@@ -1107,12 +1114,14 @@
     }
 
     /** Return the last reset time. */
+    @GuardedBy("mLock")
     long getLastResetTimeLocked() {
         updateTimesLocked();
         return mRawLastResetTime;
     }
 
     /** Return the next reset time. */
+    @GuardedBy("mLock")
     long getNextResetTimeLocked() {
         updateTimesLocked();
         return mRawLastResetTime + mResetInterval;
@@ -1125,6 +1134,7 @@
     /**
      * Update the last reset time.
      */
+    @GuardedBy("mLock")
     private void updateTimesLocked() {
 
         final long now = injectCurrentTimeMillis();
@@ -1220,6 +1230,7 @@
         return ret;
     }
 
+    @GuardedBy("mLock")
     void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) {
         for (int i = mUsers.size() - 1; i >= 0; i--) {
             c.accept(mUsers.valueAt(i));
@@ -1279,6 +1290,7 @@
      * {@link ShortcutBitmapSaver#waitForAllSavesLocked()} to make sure there's no pending bitmap
      * saves are going on.
      */
+    @GuardedBy("mLock")
     private void cleanupDanglingBitmapDirectoriesLocked(@UserIdInt int userId) {
         if (DEBUG) {
             Slog.d(TAG, "cleanupDanglingBitmaps: userId=" + userId);
@@ -2108,6 +2120,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName,
             @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) {
 
@@ -2418,6 +2431,7 @@
      *
      * This is called when an app is uninstalled, or an app gets "clear data"ed.
      */
+    @GuardedBy("mLock")
     @VisibleForTesting
     void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId,
             boolean appStillExists) {
@@ -2508,6 +2522,7 @@
             return setReturnedByServer(ret);
         }
 
+        @GuardedBy("ShortcutService.this.mLock")
         private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
                 @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince,
                 @Nullable ComponentName componentName, int queryFlags,
@@ -2579,6 +2594,7 @@
             }
         }
 
+        @GuardedBy("ShortcutService.this.mLock")
         private ShortcutInfo getShortcutInfoLocked(
                 int launcherUserId, @NonNull String callingPackage,
                 @NonNull String packageName, @NonNull String shortcutId, int userId,
@@ -2940,6 +2956,7 @@
         verifyStates();
     }
 
+    @GuardedBy("mLock")
     private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime) {
         final ShortcutUser user = getUserShortcutsLocked(userId);
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b53d83b..a0577b1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1547,6 +1547,7 @@
         return result;
     }
 
+    @GuardedBy("mRestrictionsLock")
     private EnforcingUser getEnforcingUserLocked(@UserIdInt int userId) {
         int source = mDeviceOwnerUserId == userId ? UserManager.RESTRICTION_SOURCE_DEVICE_OWNER
                 : UserManager.RESTRICTION_SOURCE_PROFILE_OWNER;
@@ -2896,6 +2897,7 @@
         }
     }
 
+    @GuardedBy("mUsersLock")
     @VisibleForTesting
     void addRemovingUserIdLocked(int userId) {
         // We remember deleted user IDs to prevent them from being
@@ -3405,6 +3407,7 @@
         return nextId;
     }
 
+    @GuardedBy("mUsersLock")
     private int scanNextAvailableIdLocked() {
         for (int i = MIN_USER_ID; i < MAX_USER_ID; i++) {
             if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 842f8d0..23185d7 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -122,7 +122,8 @@
             UserManager.DISALLOW_CONFIG_BRIGHTNESS,
             UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE,
             UserManager.DISALLOW_AMBIENT_DISPLAY,
-            UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT
+            UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT,
+            UserManager.DISALLOW_PRINTING
     });
 
     /**
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
index 60c118b..859bbe3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
@@ -146,7 +146,8 @@
 
     public abstract int checkPermission(@NonNull String permName, @NonNull String packageName,
             int callingUid, int userId);
-    public abstract int checkUidPermission(String permName, int uid, int callingUid);
+    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
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 08f8bbd..afaafbc 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -242,7 +242,8 @@
         return PackageManager.PERMISSION_DENIED;
     }
 
-    private int checkUidPermission(String permName, int uid, int callingUid) {
+    private int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
+            int callingUid) {
         final int callingUserId = UserHandle.getUserId(callingUid);
         final boolean isCallerInstantApp =
                 mPackageManagerInt.getInstantAppPackageName(callingUid) != null;
@@ -253,28 +254,13 @@
             return PackageManager.PERMISSION_DENIED;
         }
 
-        final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
-        if (packages != null && packages.length > 0) {
-            PackageParser.Package pkg = null;
-            for (String packageName : packages) {
-                pkg = mPackageManagerInt.getPackage(packageName);
-                if (pkg != null) {
-                    break;
-                }
-            }
-            if (pkg == null) {
-Slog.e(TAG, "TODD: No package not found; UID: " + uid);
-Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
-                return PackageManager.PERMISSION_DENIED;
-            }
+        if (pkg != null) {
             if (pkg.mSharedUserId != null) {
                 if (isCallerInstantApp) {
                     return PackageManager.PERMISSION_DENIED;
                 }
-            } else {
-                if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
-                    return PackageManager.PERMISSION_DENIED;
-                }
+            } else if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
+                return PackageManager.PERMISSION_DENIED;
             }
             final PermissionsState permissionsState =
                     ((PackageSetting) pkg.mExtras).getPermissionsState();
@@ -1210,6 +1196,7 @@
         return false;
     }
 
+    @GuardedBy("mLock")
     private void grantRuntimePermissionsGrantedToDisabledPackageLocked(
             PackageParser.Package pkg, int callingUid, PermissionCallback callback) {
         if (pkg.parentPackage == null) {
@@ -1499,6 +1486,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private int[] revokeUnusedSharedUserPermissionsLocked(
             SharedUserSetting suSetting, int[] allUserIds) {
         // Collect all used permissions in the UID
@@ -2066,8 +2054,9 @@
                     permName, packageName, callingUid, userId);
         }
         @Override
-        public int checkUidPermission(String permName, int uid, int callingUid) {
-            return PermissionManagerService.this.checkUidPermission(permName, uid, callingUid);
+        public int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
+                int callingUid) {
+            return PermissionManagerService.this.checkUidPermission(permName, pkg, uid, callingUid);
         }
         @Override
         public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
index f6c4990..b3f2833 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -201,34 +201,42 @@
         }
     }
 
+    @GuardedBy("mLock")
     @Nullable BasePermission getPermissionLocked(@NonNull String permName) {
         return mPermissions.get(permName);
     }
 
+    @GuardedBy("mLock")
     @Nullable BasePermission getPermissionTreeLocked(@NonNull String permName) {
         return mPermissionTrees.get(permName);
     }
 
+    @GuardedBy("mLock")
     void putPermissionLocked(@NonNull String permName, @NonNull BasePermission permission) {
         mPermissions.put(permName, permission);
     }
 
+    @GuardedBy("mLock")
     void putPermissionTreeLocked(@NonNull String permName, @NonNull BasePermission permission) {
         mPermissionTrees.put(permName, permission);
     }
 
+    @GuardedBy("mLock")
     void removePermissionLocked(@NonNull String permName) {
         mPermissions.remove(permName);
     }
 
+    @GuardedBy("mLock")
     void removePermissionTreeLocked(@NonNull String permName) {
         mPermissionTrees.remove(permName);
     }
 
+    @GuardedBy("mLock")
     @NonNull Collection<BasePermission> getAllPermissionsLocked() {
         return mPermissions.values();
     }
 
+    @GuardedBy("mLock")
     @NonNull Collection<BasePermission> getAllPermissionTreesLocked() {
         return mPermissionTrees.values();
     }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 177d6af..0502848 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5603,7 +5603,9 @@
         final int fl = PolicyControl.getWindowFlags(null,
                 mTopFullscreenOpaqueWindowState.getAttrs());
         if (localLOGV) {
-            Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
+            Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
+                    + " shown position: "
+                    + mTopFullscreenOpaqueWindowState.getShownPositionLw());
             Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
                     + " lp.flags=0x" + Integer.toHexString(fl));
         }
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 3af3fcb..e9c4c5c 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -232,6 +232,14 @@
         public Rect getFrameLw();
 
         /**
+         * Retrieve the current position of the window that is actually shown.
+         * Must be called with the window manager lock held.
+         *
+         * @return Point The point holding the shown window position.
+         */
+        public Point getShownPositionLw();
+
+        /**
          * Retrieve the frame of the display that this window was last
          * laid out in.  Must be called with the
          * window manager lock held.
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 847c90a..08dc97e 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -306,6 +306,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     @VisibleForTesting
     void updateConstantsLocked(final String setting, final String deviceSpecificSetting) {
         mSettings = setting;
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index a536270..3072f21 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -85,6 +85,7 @@
     private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
     private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 4;
     private static final int MSG_PROFILE_TIMED_OUT = 5;
+    private static final int MSG_WIRED_CHARGING_STARTED = 6;
 
     private final Object mLock = new Object();
 
@@ -571,6 +572,20 @@
         mHandler.sendMessage(msg);
     }
 
+    /**
+     * Called when wired charging has started so as to provide user feedback
+     */
+    public void onWiredChargingStarted() {
+        if (DEBUG) {
+            Slog.d(TAG, "onWiredChargingStarted");
+        }
+
+        mSuspendBlocker.acquire();
+        Message msg = mHandler.obtainMessage(MSG_WIRED_CHARGING_STARTED);
+        msg.setAsynchronous(true);
+        mHandler.sendMessage(msg);
+    }
+
     private void updatePendingBroadcastLocked() {
         if (!mBroadcastInProgress
                 && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
@@ -703,11 +718,14 @@
         }
     };
 
-    private void playWirelessChargingStartedSound() {
+    /**
+     * Plays the wireless charging sound for both wireless and non-wireless charging
+     */
+    private void playChargingStartedSound() {
         final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0;
         final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.WIRELESS_CHARGING_STARTED_SOUND);
+                Settings.Global.CHARGING_STARTED_SOUND);
         if (enabled && soundPath != null) {
             final Uri soundUri = Uri.parse("file://" + soundPath);
             if (soundUri != null) {
@@ -721,11 +739,16 @@
     }
 
     private void showWirelessChargingStarted(int batteryLevel) {
-        playWirelessChargingStartedSound();
+        playChargingStartedSound();
         mStatusBarManagerInternal.showChargingAnimation(batteryLevel);
         mSuspendBlocker.release();
     }
 
+    private void showWiredChargingStarted() {
+        playChargingStartedSound();
+        mSuspendBlocker.release();
+    }
+
     private void lockProfile(@UserIdInt int userId) {
         mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
     }
@@ -753,6 +776,8 @@
                 case MSG_PROFILE_TIMED_OUT:
                     lockProfile(msg.arg1);
                     break;
+                case MSG_WIRED_CHARGING_STARTED:
+                    showWiredChargingStarted();
             }
         }
     }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index db83158..38dc820 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -120,9 +120,6 @@
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_SPEW = DEBUG && true;
 
-    // if DEBUG_WIRELESS=true, plays wireless charging animation w/ sound on every plug + unplug
-    private static final boolean DEBUG_WIRELESS = false;
-
     // Message: Sent when a user activity timeout occurs to update the power state.
     private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
     // Message: Sent when the device enters or exits a dreaming or dozing state.
@@ -1743,10 +1740,15 @@
                 userActivityNoUpdateLocked(
                         now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
 
-                // Tell the notifier whether wireless charging has started so that
-                // it can provide feedback to the user.
-                if (dockedOnWirelessCharger || DEBUG_WIRELESS) {
-                    mNotifier.onWirelessChargingStarted(mBatteryLevel);
+                // only play charging sounds if boot is completed so charging sounds don't play
+                // with potential notification sounds
+                if (mBootCompleted) {
+                    if (mIsPowered && !BatteryManager.isPlugWired(oldPlugType)
+                            && BatteryManager.isPlugWired(mPlugType)) {
+                        mNotifier.onWiredChargingStarted();
+                    } else if (dockedOnWirelessCharger) {
+                        mNotifier.onWirelessChargingStarted(mBatteryLevel);
+                    }
                 }
             }
 
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
index b0b07ea..37df94f 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
@@ -285,6 +285,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void transitionStateLocked(int newState) {
         if (mCurrentState == newState) {
             return;
@@ -298,6 +299,7 @@
         mMetricsLoggerHelper.transitionState(newState, now, batteryLevel, batteryPercent);
     }
 
+    @GuardedBy("mLock")
     private void endLastStateLocked(long now, int batteryLevel, int batteryPercent) {
         if (mCurrentState < 0) {
             return;
@@ -338,6 +340,7 @@
 
     }
 
+    @GuardedBy("mLock")
     private void startNewStateLocked(int newState, long now, int batteryLevel, int batteryPercent) {
         if (DEBUG) {
             Slog.d(TAG, "New state: " + stateToString(newState));
@@ -363,7 +366,7 @@
             indent = indent + "  ";
 
             pw.print(indent);
-            pw.println("Battery Saver:       Off                                        On");
+            pw.println("Battery Saver:     w/Off                                      w/On");
             dumpLineLocked(pw, indent, InteractiveState.NON_INTERACTIVE, "NonIntr",
                     DozeState.NOT_DOZING, "NonDoze");
             dumpLineLocked(pw, indent, InteractiveState.INTERACTIVE, "   Intr",
diff --git a/services/core/java/com/android/server/power/batterysaver/FileUpdater.java b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
index e0ab9e9..c08b610 100644
--- a/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
+++ b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
@@ -306,6 +306,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void saveDefaultValuesLocked() {
         final AtomicFile file = new AtomicFile(injectDefaultValuesFilename());
 
@@ -334,6 +335,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     @VisibleForTesting
     boolean loadDefaultValuesLocked() {
         final AtomicFile file = new AtomicFile(injectDefaultValuesFilename());
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index f498cdd..ef6067a 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -85,11 +85,9 @@
     public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
 
     static final String TAG = "StatsCompanionService";
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
-    public static final String ACTION_TRIGGER_COLLECTION =
-        "com.android.server.stats.action.TRIGGER_COLLECTION";
-
+    public static final int CODE_DATA_BROADCAST = 1;
     public static final int CODE_SUBSCRIBER_BROADCAST = 1;
 
     private final Context mContext;
@@ -110,10 +108,9 @@
     private TelephonyManager mTelephony = null;
     private final StatFs mStatFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
     private final StatFs mStatFsSystem =
-        new StatFs(Environment.getRootDirectory().getAbsolutePath());
+            new StatFs(Environment.getRootDirectory().getAbsolutePath());
     private final StatFs mStatFsTemp =
-        new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
-    private final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+            new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
 
     public StatsCompanionService(Context context) {
         super();
@@ -123,7 +120,7 @@
         mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
                 new Intent(mContext, AnomalyAlarmReceiver.class), 0);
         mPullingAlarmIntent = PendingIntent.getBroadcast(
-            mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
+                mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
         mAppUpdateReceiver = new AppUpdateReceiver();
         mUserUpdateReceiver = new BroadcastReceiver() {
             @Override
@@ -154,17 +151,21 @@
         for (int i = 0; i < numClusters; i++) {
             final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i);
             mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster,
-                            numSpeedSteps);
+                    numSpeedSteps);
             firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i);
         }
     }
 
     @Override
-    public void sendBroadcast(String pkg, String cls) {
-        // TODO: Use a pending intent.
+    public void sendDataBroadcast(IBinder intentSenderBinder) {
         enforceCallingPermission();
-        mContext.sendBroadcastAsUser(new Intent(ACTION_TRIGGER_COLLECTION).setClassName(pkg, cls),
-                UserHandle.SYSTEM);
+        IntentSender intentSender = new IntentSender(intentSenderBinder);
+        Intent intent = new Intent();
+        try {
+            intentSender.sendIntent(mContext, CODE_DATA_BROADCAST, intent, null, null);
+        } catch (IntentSender.SendIntentException e) {
+            Slog.w(TAG, "Unable to send using IntentSender");
+        }
     }
 
     @Override
@@ -210,6 +211,7 @@
     }
 
     // Assumes that sStatsdLock is held.
+    @GuardedBy("sStatsdLock")
     private final void informAllUidsLocked(Context context) throws RemoteException {
         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
         PackageManager pm = context.getPackageManager();
@@ -285,7 +287,7 @@
         }
     }
 
-    private final static class AnomalyAlarmReceiver extends BroadcastReceiver {
+    public final static class AnomalyAlarmReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred.");
@@ -305,25 +307,24 @@
         }
     }
 
-    private final static class PullingAlarmReceiver extends BroadcastReceiver {
-      @Override
-      public void onReceive(Context context, Intent intent) {
-        if (DEBUG)
-          Slog.d(TAG, "Time to poll something.");
-        synchronized (sStatsdLock) {
-          if (sStatsd == null) {
-            Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
-            return;
-          }
-          try {
-            // Two-way call to statsd to retain AlarmManager wakelock
-            sStatsd.informPollAlarmFired();
-          } catch (RemoteException e) {
-            Slog.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
-          }
+    public final static class PullingAlarmReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG)
+                Slog.d(TAG, "Time to poll something.");
+            synchronized (sStatsdLock) {
+                if (sStatsd == null) {
+                    Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
+                    return;
+                }
+                try {
+                    // Two-way call to statsd to retain AlarmManager wakelock
+                    sStatsd.informPollAlarmFired();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
+                }
+            }
         }
-        // AlarmManager releases its own wakelock here.
-      }
     }
 
     private final static class ShutdownEventReceiver extends BroadcastReceiver {
@@ -333,9 +334,9 @@
              * Skip immediately if intent is not relevant to device shutdown.
              */
             if (!intent.getAction().equals(Intent.ACTION_REBOOT)
-                && !(intent.getAction().equals(Intent.ACTION_SHUTDOWN)
-                       && (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0)) {
-              return;
+                    && !(intent.getAction().equals(Intent.ACTION_SHUTDOWN)
+                    && (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0)) {
+                return;
             }
 
             Slog.i(TAG, "StatsCompanionService noticed a shutdown.");
@@ -382,50 +383,50 @@
 
     @Override // Binder call
     public void setPullingAlarms(long timestampMs, long intervalMs) {
-      enforceCallingPermission();
-      if (DEBUG)
-        Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
-      final long callingToken = Binder.clearCallingIdentity();
-      try {
-        // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
-        // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
-        // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
-        mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent);
-      } finally {
-        Binder.restoreCallingIdentity(callingToken);
-      }
+        enforceCallingPermission();
+        if (DEBUG)
+            Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+            // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
+            // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
+            mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
     }
 
     @Override // Binder call
     public void cancelPullingAlarms() {
-      enforceCallingPermission();
-      if (DEBUG)
-        Slog.d(TAG, "Cancelling pulling alarm");
-      final long callingToken = Binder.clearCallingIdentity();
-      try {
-        mAlarmManager.cancel(mPullingAlarmIntent);
-      } finally {
-        Binder.restoreCallingIdentity(callingToken);
-      }
+        enforceCallingPermission();
+        if (DEBUG)
+            Slog.d(TAG, "Cancelling pulling alarm");
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            mAlarmManager.cancel(mPullingAlarmIntent);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
     }
 
     private void addNetworkStats(
-        int tag, List<StatsLogEventWrapper> ret, NetworkStats stats, boolean withFGBG) {
-      int size = stats.size();
-      NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
-      for (int j = 0; j < size; j++) {
-        stats.getValues(j, entry);
-        StatsLogEventWrapper e = new StatsLogEventWrapper(tag, withFGBG ? 6 : 5);
-        e.writeInt(entry.uid);
-        if (withFGBG) {
-          e.writeInt(entry.set);
+            int tag, List<StatsLogEventWrapper> ret, NetworkStats stats, boolean withFGBG) {
+        int size = stats.size();
+        NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
+        for (int j = 0; j < size; j++) {
+            stats.getValues(j, entry);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tag, withFGBG ? 6 : 5);
+            e.writeInt(entry.uid);
+            if (withFGBG) {
+                e.writeInt(entry.set);
+            }
+            e.writeLong(entry.rxBytes);
+            e.writeLong(entry.rxPackets);
+            e.writeLong(entry.txBytes);
+            e.writeLong(entry.txPackets);
+            ret.add(e);
         }
-        e.writeLong(entry.rxBytes);
-        e.writeLong(entry.rxPackets);
-        e.writeLong(entry.txBytes);
-        e.writeLong(entry.txPackets);
-        ret.add(e);
-      }
     }
 
     /**
@@ -492,219 +493,220 @@
     }
 
     private void pullKernelWakelock(int tagId, List<StatsLogEventWrapper> pulledData) {
-      final KernelWakelockStats wakelockStats =
-          mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
-      for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
-        String name = ent.getKey();
-        KernelWakelockStats.Entry kws = ent.getValue();
-        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4);
-        e.writeString(name);
-        e.writeInt(kws.mCount);
-        e.writeInt(kws.mVersion);
-        e.writeLong(kws.mTotalTime);
-        pulledData.add(e);
-      }
+        final KernelWakelockStats wakelockStats =
+                mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
+        for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
+            String name = ent.getKey();
+            KernelWakelockStats.Entry kws = ent.getValue();
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4);
+            e.writeString(name);
+            e.writeInt(kws.mCount);
+            e.writeInt(kws.mVersion);
+            e.writeLong(kws.mTotalTime);
+            pulledData.add(e);
+        }
     }
 
     private void pullWifiBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
-      long token = Binder.clearCallingIdentity();
-      try {
-        // TODO: Consider caching the following call to get BatteryStatsInternal.
-        BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
-        String[] ifaces = bs.getWifiIfaces();
-        if (ifaces.length == 0) {
-          return;
+        long token = Binder.clearCallingIdentity();
+        try {
+            // TODO: Consider caching the following call to get BatteryStatsInternal.
+            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+            String[] ifaces = bs.getWifiIfaces();
+            if (ifaces.length == 0) {
+                return;
+            }
+            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            // Combine all the metrics per Uid into one record.
+            NetworkStats stats =
+                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
+                            .groupedByUid();
+            addNetworkStats(tagId, pulledData, stats, false);
+        } catch (java.io.IOException e) {
+            Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
-        NetworkStatsFactory nsf = new NetworkStatsFactory();
-        // Combine all the metrics per Uid into one record.
-        NetworkStats stats =
-            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
-                .groupedByUid();
-        addNetworkStats(tagId, pulledData, stats, false);
-      } catch (java.io.IOException e) {
-        Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
-      } finally {
-        Binder.restoreCallingIdentity(token);
-      }
     }
 
     private void pullWifiBytesTransferByFgBg(int tagId, List<StatsLogEventWrapper> pulledData) {
-      long token = Binder.clearCallingIdentity();
-      try {
-        BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
-        String[] ifaces = bs.getWifiIfaces();
-        if (ifaces.length == 0) {
-          return;
+        long token = Binder.clearCallingIdentity();
+        try {
+            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+            String[] ifaces = bs.getWifiIfaces();
+            if (ifaces.length == 0) {
+                return;
+            }
+            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            NetworkStats stats = rollupNetworkStatsByFGBG(
+                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
+            addNetworkStats(tagId, pulledData, stats, true);
+        } catch (java.io.IOException e) {
+            Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
-        NetworkStatsFactory nsf = new NetworkStatsFactory();
-        NetworkStats stats = rollupNetworkStatsByFGBG(
-            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
-        addNetworkStats(tagId, pulledData, stats, true);
-      } catch (java.io.IOException e) {
-        Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
-      } finally {
-        Binder.restoreCallingIdentity(token);
-      }
     }
 
     private void pullMobileBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
-      long token = Binder.clearCallingIdentity();
-      try {
-        BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
-        String[] ifaces = bs.getMobileIfaces();
-        if (ifaces.length == 0) {
-          return;
+        long token = Binder.clearCallingIdentity();
+        try {
+            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+            String[] ifaces = bs.getMobileIfaces();
+            if (ifaces.length == 0) {
+                return;
+            }
+            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            // Combine all the metrics per Uid into one record.
+            NetworkStats stats =
+                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
+                            .groupedByUid();
+            addNetworkStats(tagId, pulledData, stats, false);
+        } catch (java.io.IOException e) {
+            Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
-        NetworkStatsFactory nsf = new NetworkStatsFactory();
-        // Combine all the metrics per Uid into one record.
-        NetworkStats stats =
-            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null)
-                .groupedByUid();
-        addNetworkStats(tagId, pulledData, stats, false);
-      } catch (java.io.IOException e) {
-        Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
-      } finally {
-        Binder.restoreCallingIdentity(token);
-      }
     }
 
     private void pullBluetoothBytesTransfer(int tagId, List<StatsLogEventWrapper> pulledData) {
-      BluetoothActivityEnergyInfo info = pullBluetoothData();
-      for (UidTraffic traffic : info.getUidTraffic()) {
-        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
-        e.writeInt(traffic.getUid());
-        e.writeLong(traffic.getRxBytes());
-        e.writeLong(traffic.getTxBytes());
-        pulledData.add(e);
-      }
+        BluetoothActivityEnergyInfo info = pullBluetoothData();
+        for (UidTraffic traffic : info.getUidTraffic()) {
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
+            e.writeInt(traffic.getUid());
+            e.writeLong(traffic.getRxBytes());
+            e.writeLong(traffic.getTxBytes());
+            pulledData.add(e);
+        }
     }
 
     private void pullMobileBytesTransferByFgBg(int tagId, List<StatsLogEventWrapper> pulledData) {
-      long token = Binder.clearCallingIdentity();
-      try {
-        BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
-        String[] ifaces = bs.getMobileIfaces();
-        if (ifaces.length == 0) {
-          return;
+        long token = Binder.clearCallingIdentity();
+        try {
+            BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+            String[] ifaces = bs.getMobileIfaces();
+            if (ifaces.length == 0) {
+                return;
+            }
+            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            NetworkStats stats = rollupNetworkStatsByFGBG(
+                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
+            addNetworkStats(tagId, pulledData, stats, true);
+        } catch (java.io.IOException e) {
+            Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
-        NetworkStatsFactory nsf = new NetworkStatsFactory();
-        NetworkStats stats = rollupNetworkStatsByFGBG(
-            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, null));
-        addNetworkStats(tagId, pulledData, stats, true);
-      } catch (java.io.IOException e) {
-        Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
-      } finally {
-        Binder.restoreCallingIdentity(token);
-      }
     }
 
     private void pullCpuTimePerFreq(int tagId, List<StatsLogEventWrapper> pulledData) {
-      for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
-        long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
-        if (clusterTimeMs != null) {
-          for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
-            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
-            e.writeInt(cluster);
-            e.writeInt(speed);
-            e.writeLong(clusterTimeMs[speed]);
-            pulledData.add(e);
-          }
+        for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
+            long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
+            if (clusterTimeMs != null) {
+                for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
+                    StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
+                    e.writeInt(cluster);
+                    e.writeInt(speed);
+                    e.writeLong(clusterTimeMs[speed]);
+                    pulledData.add(e);
+                }
+            }
         }
-      }
     }
 
     private void pullWifiActivityEnergyInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
-      long token = Binder.clearCallingIdentity();
-      if (mWifiManager == null) {
-        mWifiManager =
-            IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE));
-      }
-      if (mWifiManager != null) {
-        try {
-          SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
-          mWifiManager.requestActivityInfo(wifiReceiver);
-          final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
-          StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
-          e.writeLong(wifiInfo.getTimeStamp());
-          e.writeInt(wifiInfo.getStackState());
-          e.writeLong(wifiInfo.getControllerTxTimeMillis());
-          e.writeLong(wifiInfo.getControllerRxTimeMillis());
-          e.writeLong(wifiInfo.getControllerIdleTimeMillis());
-          e.writeLong(wifiInfo.getControllerEnergyUsed());
-          pulledData.add(e);
-        } catch (RemoteException e) {
-          Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e);
-        } finally {
-          Binder.restoreCallingIdentity(token);
+        long token = Binder.clearCallingIdentity();
+        if (mWifiManager == null) {
+            mWifiManager =
+                    IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE));
         }
-      }
+        if (mWifiManager != null) {
+            try {
+                SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
+                mWifiManager.requestActivityInfo(wifiReceiver);
+                final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
+                StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
+                e.writeLong(wifiInfo.getTimeStamp());
+                e.writeInt(wifiInfo.getStackState());
+                e.writeLong(wifiInfo.getControllerTxTimeMillis());
+                e.writeLong(wifiInfo.getControllerRxTimeMillis());
+                e.writeLong(wifiInfo.getControllerIdleTimeMillis());
+                e.writeLong(wifiInfo.getControllerEnergyUsed());
+                pulledData.add(e);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Pulling wifiManager for wifi controller activity energy info has error", e);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
     }
 
     private void pullModemActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
-      long token = Binder.clearCallingIdentity();
-      if (mTelephony == null) {
-        mTelephony = TelephonyManager.from(mContext);
-      }
-      if (mTelephony != null) {
-        SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
-        mTelephony.requestModemActivityInfo(modemReceiver);
-        final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
-        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
-        e.writeLong(modemInfo.getTimestamp());
-        e.writeLong(modemInfo.getSleepTimeMillis());
-        e.writeLong(modemInfo.getIdleTimeMillis());
-        e.writeLong(modemInfo.getTxTimeMillis()[0]);
-        e.writeLong(modemInfo.getTxTimeMillis()[1]);
-        e.writeLong(modemInfo.getTxTimeMillis()[2]);
-        e.writeLong(modemInfo.getTxTimeMillis()[3]);
-        e.writeLong(modemInfo.getTxTimeMillis()[4]);
-        e.writeLong(modemInfo.getRxTimeMillis());
-        e.writeLong(modemInfo.getEnergyUsed());
-        pulledData.add(e);
-      }
+        long token = Binder.clearCallingIdentity();
+        if (mTelephony == null) {
+            mTelephony = TelephonyManager.from(mContext);
+        }
+        if (mTelephony != null) {
+            SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
+            mTelephony.requestModemActivityInfo(modemReceiver);
+            final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
+            e.writeLong(modemInfo.getTimestamp());
+            e.writeLong(modemInfo.getSleepTimeMillis());
+            e.writeLong(modemInfo.getIdleTimeMillis());
+            e.writeLong(modemInfo.getTxTimeMillis()[0]);
+            e.writeLong(modemInfo.getTxTimeMillis()[1]);
+            e.writeLong(modemInfo.getTxTimeMillis()[2]);
+            e.writeLong(modemInfo.getTxTimeMillis()[3]);
+            e.writeLong(modemInfo.getTxTimeMillis()[4]);
+            e.writeLong(modemInfo.getRxTimeMillis());
+            e.writeLong(modemInfo.getEnergyUsed());
+            pulledData.add(e);
+        }
     }
 
     private void pullBluetoothActivityInfo(int tagId, List<StatsLogEventWrapper> pulledData) {
-      BluetoothActivityEnergyInfo info = pullBluetoothData();
-      StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
-      e.writeLong(info.getTimeStamp());
-      e.writeInt(info.getBluetoothStackState());
-      e.writeLong(info.getControllerTxTimeMillis());
-      e.writeLong(info.getControllerRxTimeMillis());
-      e.writeLong(info.getControllerIdleTimeMillis());
-      e.writeLong(info.getControllerEnergyUsed());
-      pulledData.add(e);
+        BluetoothActivityEnergyInfo info = pullBluetoothData();
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
+        e.writeLong(info.getTimeStamp());
+        e.writeInt(info.getBluetoothStackState());
+        e.writeLong(info.getControllerTxTimeMillis());
+        e.writeLong(info.getControllerRxTimeMillis());
+        e.writeLong(info.getControllerIdleTimeMillis());
+        e.writeLong(info.getControllerEnergyUsed());
+        pulledData.add(e);
     }
 
     private synchronized BluetoothActivityEnergyInfo pullBluetoothData() {
-      if (adapter != null) {
-        SynchronousResultReceiver bluetoothReceiver = null;
-        bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
-        adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
-        return awaitControllerInfo(bluetoothReceiver);
-      } else {
-        return null;
-      }
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
+            adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+            return awaitControllerInfo(bluetoothReceiver);
+        } else {
+            Slog.e(TAG, "Failed to get bluetooth adapter!");
+            return null;
+        }
     }
 
     private void pullSystemElapsedRealtime(int tagId, List<StatsLogEventWrapper> pulledData) {
-      StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
-      e.writeLong(SystemClock.elapsedRealtime());
-      pulledData.add(e);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
+        e.writeLong(SystemClock.elapsedRealtime());
+        pulledData.add(e);
     }
 
     private void pullDiskSpace(int tagId, List<StatsLogEventWrapper> pulledData) {
-      StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
-      e.writeLong(mStatFsData.getAvailableBytes());
-      e.writeLong(mStatFsSystem.getAvailableBytes());
-      e.writeLong(mStatFsTemp.getAvailableBytes());
-      pulledData.add(e);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
+        e.writeLong(mStatFsData.getAvailableBytes());
+        e.writeLong(mStatFsSystem.getAvailableBytes());
+        e.writeLong(mStatFsTemp.getAvailableBytes());
+        pulledData.add(e);
     }
 
     private void pullSystemUpTime(int tagId, List<StatsLogEventWrapper> pulledData) {
-      StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
-      e.writeLong(SystemClock.uptimeMillis());
-      pulledData.add(e);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 1);
+        e.writeLong(SystemClock.uptimeMillis());
+        pulledData.add(e);
     }
 
     /**
@@ -718,56 +720,56 @@
         List<StatsLogEventWrapper> ret = new ArrayList();
         switch (tagId) {
             case StatsLog.WIFI_BYTES_TRANSFER: {
-              pullWifiBytesTransfer(tagId, ret);
-              break;
+                pullWifiBytesTransfer(tagId, ret);
+                break;
             }
             case StatsLog.MOBILE_BYTES_TRANSFER: {
-              pullMobileBytesTransfer(tagId, ret);
-              break;
+                pullMobileBytesTransfer(tagId, ret);
+                break;
             }
             case StatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: {
-              pullWifiBytesTransferByFgBg(tagId, ret);
-              break;
+                pullWifiBytesTransferByFgBg(tagId, ret);
+                break;
             }
             case StatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: {
-              pullMobileBytesTransferByFgBg(tagId, ret);
-              break;
+                pullMobileBytesTransferByFgBg(tagId, ret);
+                break;
             }
             case StatsLog.BLUETOOTH_BYTES_TRANSFER: {
-              pullBluetoothBytesTransfer(tagId, ret);
-              break;
+                pullBluetoothBytesTransfer(tagId, ret);
+                break;
             }
             case StatsLog.KERNEL_WAKELOCK: {
-              pullKernelWakelock(tagId, ret);
-              break;
+                pullKernelWakelock(tagId, ret);
+                break;
             }
             case StatsLog.CPU_TIME_PER_FREQ: {
-              pullCpuTimePerFreq(tagId, ret);
-              break;
+                pullCpuTimePerFreq(tagId, ret);
+                break;
             }
             case StatsLog.WIFI_ACTIVITY_ENERGY_INFO: {
-              pullWifiActivityEnergyInfo(tagId, ret);
-              break;
+                pullWifiActivityEnergyInfo(tagId, ret);
+                break;
             }
             case StatsLog.MODEM_ACTIVITY_INFO: {
-              pullModemActivityInfo(tagId, ret);
-              break;
+                pullModemActivityInfo(tagId, ret);
+                break;
             }
             case StatsLog.BLUETOOTH_ACTIVITY_INFO: {
-              pullBluetoothActivityInfo(tagId, ret);
-              break;
+                pullBluetoothActivityInfo(tagId, ret);
+                break;
             }
             case StatsLog.SYSTEM_UPTIME: {
-              pullSystemUpTime(tagId, ret);
-              break;
+                pullSystemUpTime(tagId, ret);
+                break;
             }
             case StatsLog.SYSTEM_ELAPSED_REALTIME: {
-              pullSystemElapsedRealtime(tagId, ret);
-              break;
+                pullSystemElapsedRealtime(tagId, ret);
+                break;
             }
             case StatsLog.DISK_SPACE: {
-              pullDiskSpace(tagId, ret);
-              break;
+                pullDiskSpace(tagId, ret);
+                break;
             }
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
@@ -788,14 +790,14 @@
 
     @Override
     public void triggerUidSnapshot() {
-      enforceCallingPermission();
-      synchronized (sStatsdLock) {
-        try {
-          informAllUidsLocked(mContext);
-        } catch (RemoteException e) {
-          Slog.e(TAG, "Failed to trigger uid snapshot.", e);
+        enforceCallingPermission();
+        synchronized (sStatsdLock) {
+            try {
+                informAllUidsLocked(mContext);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to trigger uid snapshot.", e);
+            }
         }
-      }
     }
 
     private void enforceCallingPermission() {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 7c170ae..343fb91 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -321,7 +321,7 @@
         public void showChargingAnimation(int batteryLevel) {
             if (mBar != null) {
                 try {
-                    mBar.showChargingAnimation(batteryLevel);
+                    mBar.showWirelessChargingAnimation(batteryLevel);
                 } catch (RemoteException ex){
                 }
             }
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 853c7eb..0ac853b 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -22,7 +22,6 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -43,7 +42,6 @@
 import java.util.LinkedList;
 import java.util.Queue;
 import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
 
 /**
  * A manager for TextClassifier services.
@@ -54,9 +52,6 @@
 
     private static final String LOG_TAG = "TextClassificationManagerService";
 
-    // How long after the last interaction with the service we would unbind
-    private static final long TIMEOUT_IDLE_BIND_MILLIS = TimeUnit.MINUTES.toMillis(1);
-
     public static final class Lifecycle extends SystemService {
 
         private final TextClassificationManagerService mManagerService;
@@ -79,10 +74,8 @@
     }
 
     private final Context mContext;
-    private final Handler mHandler;
     private final Intent mServiceIntent;
     private final ServiceConnection mConnection;
-    private final Runnable mUnbind;
     private final Object mLock;
     @GuardedBy("mLock")
     private final Queue<PendingRequest> mPendingRequests;
@@ -94,7 +87,6 @@
 
     private TextClassificationManagerService(Context context) {
         mContext = Preconditions.checkNotNull(context);
-        mHandler = new Handler();
         mServiceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE)
                 .setComponent(TextClassifierService.getServiceComponentName(mContext));
         mConnection = new ServiceConnection() {
@@ -131,7 +123,6 @@
             }
         };
         mPendingRequests = new LinkedList<>();
-        mUnbind = this::unbind;
         mLock = new Object();
     }
 
@@ -152,7 +143,6 @@
             if (isBoundLocked()) {
                 mService.onSuggestSelection(
                         text, selectionStartIndex, selectionEndIndex, options, callback);
-                scheduleUnbindLocked();
             } else {
                 final Callable<Void> request = () -> {
                     onSuggestSelection(
@@ -184,7 +174,6 @@
         synchronized (mLock) {
             if (isBoundLocked()) {
                 mService.onClassifyText(text, startIndex, endIndex, options, callback);
-                scheduleUnbindLocked();
             } else {
                 final Callable<Void> request = () -> {
                     onClassifyText(text, startIndex, endIndex, options, callback);
@@ -213,7 +202,6 @@
         synchronized (mLock) {
             if (isBoundLocked()) {
                 mService.onGenerateLinks(text, options, callback);
-                scheduleUnbindLocked();
             } else {
                 final Callable<Void> request = () -> {
                     onGenerateLinks(text, options, callback);
@@ -270,27 +258,6 @@
         mBinding = binding;
     }
 
-    private void unbind() {
-        synchronized (mLock) {
-            if (!isBoundLocked()) {
-                return;
-            }
-
-            Slog.d(LOG_TAG, "Unbinding from " + mServiceIntent.getComponent());
-            mContext.unbindService(mConnection);
-
-            synchronized (mLock) {
-                mService = null;
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void scheduleUnbindLocked() {
-        mHandler.removeCallbacks(mUnbind);
-        mHandler.postDelayed(mUnbind, TIMEOUT_IDLE_BIND_MILLIS);
-    }
-
     @GuardedBy("mLock")
     private void enqueueRequestLocked(
             Callable<Void> request, Callable<Void> onServiceFailure, IBinder binder) {
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
index 0e8d8bc..8f4cada 100644
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -59,7 +59,7 @@
     private static final String TAG = "timezone.PackageTracker";
 
     private final PackageManagerHelper mPackageManagerHelper;
-    private final IntentHelper mIntentHelper;
+    private final PackageTrackerIntentHelper mIntentHelper;
     private final ConfigHelper mConfigHelper;
     private final PackageStatusStorage mPackageStatusStorage;
     private final Clock mElapsedRealtimeClock;
@@ -103,13 +103,13 @@
                 helperImpl /* configHelper */,
                 helperImpl /* packageManagerHelper */,
                 new PackageStatusStorage(storageDir),
-                new IntentHelperImpl(context));
+                new PackageTrackerIntentHelperImpl(context));
     }
 
     // A constructor that can be used by tests to supply mocked / faked dependencies.
     PackageTracker(Clock elapsedRealtimeClock, ConfigHelper configHelper,
             PackageManagerHelper packageManagerHelper, PackageStatusStorage packageStatusStorage,
-            IntentHelper intentHelper) {
+            PackageTrackerIntentHelper intentHelper) {
         mElapsedRealtimeClock = elapsedRealtimeClock;
         mConfigHelper = configHelper;
         mPackageManagerHelper = packageManagerHelper;
diff --git a/services/core/java/com/android/server/timezone/IntentHelper.java b/services/core/java/com/android/server/timezone/PackageTrackerIntentHelper.java
similarity index 97%
rename from services/core/java/com/android/server/timezone/IntentHelper.java
rename to services/core/java/com/android/server/timezone/PackageTrackerIntentHelper.java
index 5de5432..3753ece 100644
--- a/services/core/java/com/android/server/timezone/IntentHelper.java
+++ b/services/core/java/com/android/server/timezone/PackageTrackerIntentHelper.java
@@ -21,7 +21,7 @@
  * it is not possible to test various cases with the real one because of the need to simulate
  * receiving and broadcasting intents.
  */
-interface IntentHelper {
+interface PackageTrackerIntentHelper {
 
     void initialize(String updateAppPackageName, String dataAppPackageName,
             PackageTracker packageTracker);
diff --git a/services/core/java/com/android/server/timezone/IntentHelperImpl.java b/services/core/java/com/android/server/timezone/PackageTrackerIntentHelperImpl.java
similarity index 93%
rename from services/core/java/com/android/server/timezone/IntentHelperImpl.java
rename to services/core/java/com/android/server/timezone/PackageTrackerIntentHelperImpl.java
index 6e6259d..4110d88 100644
--- a/services/core/java/com/android/server/timezone/IntentHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/PackageTrackerIntentHelperImpl.java
@@ -28,16 +28,16 @@
 import android.util.Slog;
 
 /**
- * The bona fide implementation of {@link IntentHelper}.
+ * The bona fide implementation of {@link PackageTrackerIntentHelper}.
  */
-final class IntentHelperImpl implements IntentHelper {
+final class PackageTrackerIntentHelperImpl implements PackageTrackerIntentHelper {
 
-    private final static String TAG = "timezone.IntentHelperImpl";
+    private final static String TAG = "timezone.PackageTrackerIntentHelperImpl";
 
     private final Context mContext;
     private String mUpdaterAppPackageName;
 
-    IntentHelperImpl(Context context) {
+    PackageTrackerIntentHelperImpl(Context context) {
         mContext = context;
     }
 
diff --git a/services/core/java/com/android/server/timezone/RulesManagerIntentHelper.java b/services/core/java/com/android/server/timezone/RulesManagerIntentHelper.java
new file mode 100644
index 0000000..bb317cf
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/RulesManagerIntentHelper.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezone;
+
+/**
+ * An easy-to-mock interface around intent sending / receiving for use by
+ * {@link RulesManagerService}; it is not possible to test various cases with the real one because
+ * of the need to simulate broadcasting intents.
+ */
+interface RulesManagerIntentHelper {
+
+    /**
+     * Send a broadcast informing listeners that a time zone operation is staged.
+     */
+    void sendTimeZoneOperationStaged();
+
+    /**
+     * Send a broadcast informing listeners that a time zone operation is no longer staged.
+     */
+    void sendTimeZoneOperationUnstaged();
+}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index be9b204..872d723 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -99,6 +99,7 @@
     private final PermissionHelper mPermissionHelper;
     private final PackageTracker mPackageTracker;
     private final Executor mExecutor;
+    private final RulesManagerIntentHelper mIntentHelper;
     private final TimeZoneDistroInstaller mInstaller;
 
     private static RulesManagerService create(Context context) {
@@ -106,16 +107,19 @@
         return new RulesManagerService(
                 helper /* permissionHelper */,
                 helper /* executor */,
+                helper /* intentHelper */,
                 PackageTracker.create(context),
                 new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR));
     }
 
     // A constructor that can be used by tests to supply mocked / faked dependencies.
-    RulesManagerService(PermissionHelper permissionHelper,
-            Executor executor, PackageTracker packageTracker,
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    RulesManagerService(PermissionHelper permissionHelper, Executor executor,
+            RulesManagerIntentHelper intentHelper, PackageTracker packageTracker,
             TimeZoneDistroInstaller timeZoneDistroInstaller) {
         mPermissionHelper = permissionHelper;
         mExecutor = executor;
+        mIntentHelper = intentHelper;
         mPackageTracker = packageTracker;
         mInstaller = timeZoneDistroInstaller;
     }
@@ -271,6 +275,10 @@
 
                 TimeZoneDistro distro = new TimeZoneDistro(is);
                 int installerResult = mInstaller.stageInstallWithErrorCode(distro);
+
+                // Notify interested parties that something is staged.
+                sendInstallNotificationIntentIfRequired(installerResult);
+
                 int resultCode = mapInstallerResultToApiCode(installerResult);
                 EventLogTags.writeTimezoneInstallComplete(toStringOrNull(mCheckToken), resultCode);
                 sendFinishedStatus(mCallback, resultCode);
@@ -291,6 +299,12 @@
             }
         }
 
+        private void sendInstallNotificationIntentIfRequired(int installerResult) {
+            if (installerResult == TimeZoneDistroInstaller.INSTALL_SUCCESS) {
+                mIntentHelper.sendTimeZoneOperationStaged();
+            }
+        }
+
         private int mapInstallerResultToApiCode(int installerResult) {
             switch (installerResult) {
                 case TimeZoneDistroInstaller.INSTALL_SUCCESS:
@@ -351,6 +365,10 @@
             boolean packageTrackerStatus = false;
             try {
                 int uninstallResult = mInstaller.stageUninstall();
+
+                // Notify interested parties that something is staged.
+                sendUninstallNotificationIntentIfRequired(uninstallResult);
+
                 packageTrackerStatus = (uninstallResult == TimeZoneDistroInstaller.UNINSTALL_SUCCESS
                         || uninstallResult == TimeZoneDistroInstaller.UNINSTALL_NOTHING_INSTALLED);
 
@@ -374,6 +392,20 @@
                 mOperationInProgress.set(false);
             }
         }
+
+        private void sendUninstallNotificationIntentIfRequired(int uninstallResult) {
+            switch (uninstallResult) {
+                case TimeZoneDistroInstaller.UNINSTALL_SUCCESS:
+                    mIntentHelper.sendTimeZoneOperationStaged();
+                    break;
+                case TimeZoneDistroInstaller.UNINSTALL_NOTHING_INSTALLED:
+                    mIntentHelper.sendTimeZoneOperationUnstaged();
+                    break;
+                case TimeZoneDistroInstaller.UNINSTALL_FAIL:
+                default:
+                    // No-op - unknown or nothing to notify about.
+            }
+        }
     }
 
     private void sendFinishedStatus(ICallback callback, int resultCode) {
diff --git a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
index e8a401e..8f5c7a7 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
@@ -18,22 +18,20 @@
 
 import com.android.internal.util.DumpUtils;
 
+import android.app.timezone.RulesManager;
 import android.content.Context;
-import android.content.pm.PackageManager;
+import android.content.Intent;
 import android.os.AsyncTask;
-import android.os.Binder;
-import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
 
-import java.io.FileInputStream;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.concurrent.Executor;
-import libcore.io.Streams;
 
 /**
  * A single class that implements multiple helper interfaces for use by {@link RulesManagerService}.
  */
-final class RulesManagerServiceHelperImpl implements PermissionHelper, Executor {
+final class RulesManagerServiceHelperImpl
+        implements PermissionHelper, Executor, RulesManagerIntentHelper {
 
     private final Context mContext;
 
@@ -55,4 +53,22 @@
     public void execute(Runnable runnable) {
         AsyncTask.execute(runnable);
     }
+
+    @Override
+    public void sendTimeZoneOperationStaged() {
+        sendOperationIntent(true /* staged */);
+    }
+
+    @Override
+    public void sendTimeZoneOperationUnstaged() {
+        sendOperationIntent(false /* staged */);
+    }
+
+    private void sendOperationIntent(boolean staged) {
+        Intent intent = new Intent(RulesManager.ACTION_RULES_UPDATE_OPERATION);
+        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        intent.putExtra(RulesManager.EXTRA_OPERATION_STAGED, staged);
+        mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+    }
+
 }
diff --git a/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java b/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java
index 116fe7f..0450816 100644
--- a/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java
@@ -33,7 +33,7 @@
     @Override
     protected void postInstall(Context context, Intent intent) {
         ContentResolver resolver = context.getContentResolver();
-        resolver.update(Uri.withAppendedPath(Telephony.CarrierIdentification.CONTENT_URI,
+        resolver.update(Uri.withAppendedPath(Telephony.CarrierIdentification.All.CONTENT_URI,
                 "update_db"), new ContentValues(), null, null);
     }
 }
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index b435605..4394a99 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import android.util.ArrayMap;
 import android.view.SurfaceControl;
 import android.graphics.Rect;
 
@@ -124,17 +123,30 @@
         }
     }
 
-    @VisibleForTesting
-    ArrayMap<WindowContainer, DimState> mDimLayerUsers = new ArrayMap<>();
-
     /**
      * The {@link WindowContainer} that our Dim's are bounded to. We may be dimming on behalf of the
      * host, some controller of it, or one of the hosts children.
      */
     private WindowContainer mHost;
+    private WindowContainer mLastRequestedDimContainer;
+    @VisibleForTesting
+    DimState mDimState;
+
+    private final SurfaceAnimatorStarter mSurfaceAnimatorStarter;
+
+    @VisibleForTesting
+    interface SurfaceAnimatorStarter {
+        void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t,
+                AnimationAdapter anim, boolean hidden);
+    }
 
     Dimmer(WindowContainer host) {
+        this(host, SurfaceAnimator::startAnimation);
+    }
+
+    Dimmer(WindowContainer host, SurfaceAnimatorStarter surfaceAnimatorStarter) {
         mHost = host;
+        mSurfaceAnimatorStarter = surfaceAnimatorStarter;
     }
 
     private SurfaceControl makeDimLayer() {
@@ -146,29 +158,32 @@
     }
 
     /**
-     * Retreive the DimState for a given child of the host.
+     * Retrieve the DimState, creating one if it doesn't exist.
      */
     private DimState getDimState(WindowContainer container) {
-        DimState state = mDimLayerUsers.get(container);
-        if (state == null) {
+        if (mDimState == null) {
             final SurfaceControl ctl = makeDimLayer();
-            state = new DimState(ctl);
+            mDimState = new DimState(ctl);
             /**
              * See documentation on {@link #dimAbove} to understand lifecycle management of Dim's
              * via state resetting for Dim's with containers.
              */
             if (container == null) {
-                state.mDontReset = true;
+                mDimState.mDontReset = true;
             }
-            mDimLayerUsers.put(container, state);
         }
-        return state;
+
+        mLastRequestedDimContainer = container;
+        return mDimState;
     }
 
     private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer,
             float alpha) {
         final DimState d = getDimState(container);
         if (container != null) {
+            // The dim method is called from WindowState.prepareSurfaces(), which is always called
+            // in the correct Z from lowest Z to highest. This ensures that the dim layer is always
+            // relative to the highest Z layer with a dim.
             t.setRelativeLayer(d.mDimLayer, container.getSurfaceControl(), relativeLayer);
         } else {
             t.setLayer(d.mDimLayer, Integer.MAX_VALUE);
@@ -237,11 +252,8 @@
      * a chance to request dims to continue.
      */
     void resetDimStates() {
-        for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) {
-            final DimState state = mDimLayerUsers.valueAt(i);
-            if (!state.mDontReset) {
-                state.mDimming = false;
-            }
+        if (mDimState != null && !mDimState.mDontReset) {
+            mDimState.mDimming = false;
         }
     }
 
@@ -254,30 +266,25 @@
      * @return true if any Dims were updated.
      */
     boolean updateDims(SurfaceControl.Transaction t, Rect bounds) {
-        boolean didSomething = false;
-        for (int i = mDimLayerUsers.size() - 1; i >= 0; i--) {
-            DimState state = mDimLayerUsers.valueAt(i);
-            WindowContainer container = mDimLayerUsers.keyAt(i);
-
-            // TODO: We want to animate the addition and removal of Dim's instead of immediately
-            // acting. When we do this we need to take care to account for the "Replacing Windows"
-            // case (and seamless dim transfer).
-            if (!state.mDimming) {
-                mDimLayerUsers.removeAt(i);
-                startDimExit(container, state.mSurfaceAnimator, t);
-            } else {
-                didSomething = true;
-                // TODO: Once we use geometry from hierarchy this falls away.
-                t.setSize(state.mDimLayer, bounds.width(), bounds.height());
-                t.setPosition(state.mDimLayer, bounds.left, bounds.top);
-                if (!state.isVisible) {
-                    state.isVisible = true;
-                    t.show(state.mDimLayer);
-                    startDimEnter(container, state.mSurfaceAnimator, t);
-                }
-            }
+        if (mDimState == null) {
+            return false;
         }
-        return didSomething;
+
+        if (!mDimState.mDimming) {
+            startDimExit(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
+            mDimState = null;
+            return false;
+        } else {
+            // TODO: Once we use geometry from hierarchy this falls away.
+            t.setSize(mDimState.mDimLayer, bounds.width(), bounds.height());
+            t.setPosition(mDimState.mDimLayer, bounds.left, bounds.top);
+            if (!mDimState.isVisible) {
+                mDimState.isVisible = true;
+                t.show(mDimState.mDimLayer);
+                startDimEnter(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
+            }
+            return true;
+        }
     }
 
     private void startDimEnter(WindowContainer container, SurfaceAnimator animator,
@@ -292,7 +299,7 @@
 
     private void startAnim(WindowContainer container, SurfaceAnimator animator,
             SurfaceControl.Transaction t, float startAlpha, float endAlpha) {
-        animator.startAnimation(t, new LocalAnimationAdapter(
+        mSurfaceAnimatorStarter.startAnimation(animator, t, new LocalAnimationAdapter(
                 new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)),
                 mHost.mService.mSurfaceAnimationRunner), false /* hidden */);
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2512dbd..41a6e2b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -725,8 +725,9 @@
      *                            wallpaper windows in the window list.
      */
     DisplayContent(Display display, WindowManagerService service,
-            WallpaperController wallpaperController) {
+            WallpaperController wallpaperController, DisplayWindowController controller) {
         super(service);
+        setController(controller);
         if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
             throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
                     + " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -1941,6 +1942,8 @@
         } finally {
             mRemovingDisplay = false;
         }
+
+        mService.onDisplayRemoved(mDisplayId);
     }
 
     /** Returns true if a removal action is still being deferred. */
@@ -1950,7 +1953,6 @@
 
         if (!stillDeferringRemoval && mDeferredRemoval) {
             removeImmediately();
-            mService.onDisplayRemoved(mDisplayId);
             return false;
         }
         return true;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index ad4957e..0e12838 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -16,11 +16,14 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.content.res.Configuration;
+import android.os.Binder;
 import android.util.Slog;
+import android.view.Display;
 
 /**
  * Controller for the display container. This is created by activity manager to link activity
@@ -36,9 +39,16 @@
         mDisplayId = displayId;
 
         synchronized (mWindowMap) {
-            // TODO: Convert to setContainer() from DisplayContent once everything is hooked up.
-            // Currently we are not setup to register for config changes.
-            mContainer = mRoot.getDisplayContentOrCreate(displayId);
+            final Display display = mService.mDisplayManager.getDisplay(displayId);
+            if (display != null) {
+                final long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mRoot.createDisplayContent(display, this /* controller */);
+                } finally {
+                    Binder.restoreCallingIdentity(callingIdentity);
+                }
+            }
+
             if (mContainer == null) {
                 throw new IllegalArgumentException("Trying to add displayId=" + displayId);
             }
@@ -47,14 +57,22 @@
 
     @Override
     public void removeContainer() {
-        // TODO: Pipe through from ActivityDisplay to remove the display
-        throw new UnsupportedOperationException("To be implemented");
+        synchronized (mWindowMap) {
+            if(mContainer == null) {
+                if (DEBUG_DISPLAY) Slog.i(TAG_WM, "removeDisplay: could not find displayId="
+                        + mDisplayId);
+                return;
+            }
+            mContainer.removeIfPossible();
+            super.removeContainer();
+        }
     }
 
     @Override
     public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
-        // TODO: Pipe through from ActivityDisplay to update the configuration for the display
-        throw new UnsupportedOperationException("To be implemented");
+        // TODO: The container receives override configuration changes through other means. enabling
+        // callbacks through the controller causes layout issues. Investigate consolidating
+        // override configuration propagation to just here.
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index fe5b65c..e869f58 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -62,6 +62,7 @@
 
     // The recents component app token that is shown behind the visibile tasks
     private AppWindowToken mHomeAppToken;
+    private Rect mMinimizedHomeBounds = new Rect();
 
     // We start the RecentsAnimationController in a pending-start state since we need to wait for
     // the wallpaper/activity to draw before we can give control to the handler to start animating
@@ -105,7 +106,7 @@
                             final AppWindowToken topChild = task.getTopChild();
                             final WindowState mainWindow = topChild.findMainWindow();
                             return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
-                                    mainWindow.mStableInsets,
+                                    mainWindow.mContentInsets,
                                     ActivityManager.isLowRamDeviceStatic() /* reduced */,
                                     1.0f /* scale */);
                         }
@@ -163,8 +164,6 @@
      * @param remoteAnimationRunner The remote runner which should be notified when the animation is
      *                              ready to start or has been canceled
      * @param callbacks Callbacks to be made when the animation finishes
-     * @param restoreHomeBehindStackId The stack id to restore the home stack behind once the
-     *                                 animation is complete. Will be passed to the callback.
      */
     RecentsAnimationController(WindowManagerService service,
             IRecentsAnimationRunner remoteAnimationRunner, RecentsAnimationCallbacks callbacks,
@@ -200,13 +199,15 @@
         if (recentsComponentAppToken != null) {
             if (DEBUG) Log.d(TAG, "setHomeApp(" + recentsComponentAppToken.getName() + ")");
             mHomeAppToken = recentsComponentAppToken;
-            final WallpaperController wc = dc.mWallpaperController;
             if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
                 dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                 dc.setLayoutNeeded();
             }
         }
 
+        // Save the minimized home height
+        dc.getDockedDividerController().getHomeStackBoundsInDockedMode(mMinimizedHomeBounds);
+
         mService.mWindowPlacerLocked.performSurfacePlacement();
     }
 
@@ -232,7 +233,15 @@
                 appAnimations[i] = mPendingAnimations.get(i).createRemoteAnimationApp();
             }
             mPendingStart = false;
-            mRunner.onAnimationStart(mController, appAnimations);
+
+            final Rect minimizedHomeBounds =
+                    mHomeAppToken != null && mHomeAppToken.inSplitScreenSecondaryWindowingMode()
+                            ? mMinimizedHomeBounds : null;
+            final Rect contentInsets =
+                    mHomeAppToken != null && mHomeAppToken.findMainWindow() != null
+                            ? mHomeAppToken.findMainWindow().mContentInsets : null;
+            mRunner.onAnimationStart_New(mController, appAnimations, contentInsets,
+                    minimizedHomeBounds);
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to start recents animation", e);
         }
@@ -334,11 +343,15 @@
         }
 
         RemoteAnimationTarget createRemoteAnimationApp() {
-            // TODO: Do we need position and stack bounds?
+            final Point position = new Point();
+            final Rect bounds = new Rect();
+            final WindowContainer container = mTask.getParent();
+            container.getRelativePosition(position);
+            container.getBounds(bounds);
+            final WindowState mainWindow = mTask.getTopVisibleAppMainWindow();
             return new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
-                    !mTask.fillsParent(),
-                    mTask.getTopVisibleAppMainWindow().mWinAnimator.mLastClipRect,
-                    mTask.getPrefixOrderIndex(), new Point(), new Rect(),
+                    !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
+                    mainWindow.mContentInsets, mTask.getPrefixOrderIndex(), position, bounds,
                     mTask.getWindowConfiguration());
         }
 
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 5bc739e..c353c1d 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -96,17 +96,13 @@
         // Scale the timeout with the animator scale the controlling app is using.
         mHandler.postDelayed(mTimeoutRunnable,
                 (long) (TIMEOUT_MS * mService.getCurrentAnimatorScale()));
-
-        final RemoteAnimationTarget[] animations = createAnimations();
-        mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
-            try {
-                mRemoteAnimationAdapter.getRunner().onAnimationStart(animations,
-                        mFinishedCallback);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to start remote animation", e);
-                onAnimationFinished();
-            }
-        });
+        try {
+            mRemoteAnimationAdapter.getRunner().onAnimationStart(createAnimations(),
+                    mFinishedCallback);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to start remote animation", e);
+            onAnimationFinished();
+        }
     }
 
     private RemoteAnimationTarget[] createAnimations() {
@@ -170,7 +166,7 @@
             }
             return new RemoteAnimationTarget(task.mTaskId, getMode(),
                     mCapturedLeash, !mAppWindowToken.fillsParent(),
-                    mainWindow.mWinAnimator.mLastClipRect,
+                    mainWindow.mWinAnimator.mLastClipRect, mainWindow.mContentInsets,
                     mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
                     task.getWindowConfiguration());
         }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8d1a822..f5760e5 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -193,30 +193,6 @@
         }
     }
 
-    /**
-     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
-     * there is a Display for the displayId.
-     *
-     * @param displayId The display the caller is interested in.
-     * @return The DisplayContent associated with displayId or null if there is no Display for it.
-     */
-    DisplayContent getDisplayContentOrCreate(int displayId) {
-        DisplayContent dc = getDisplayContent(displayId);
-
-        if (dc == null) {
-            final Display display = mService.mDisplayManager.getDisplay(displayId);
-            if (display != null) {
-                final long callingIdentity = Binder.clearCallingIdentity();
-                try {
-                    dc = createDisplayContent(display);
-                } finally {
-                    Binder.restoreCallingIdentity(callingIdentity);
-                }
-            }
-        }
-        return dc;
-    }
-
     DisplayContent getDisplayContent(int displayId) {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final DisplayContent current = mChildren.get(i);
@@ -227,9 +203,9 @@
         return null;
     }
 
-    private DisplayContent createDisplayContent(final Display display) {
-        final DisplayContent dc = new DisplayContent(display, mService,
-                mWallpaperController);
+    DisplayContent createDisplayContent(final Display display, DisplayWindowController controller) {
+        final DisplayContent dc =
+                new DisplayContent(display, mService, mWallpaperController, controller);
         final int displayId = display.getDisplayId();
 
         if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
@@ -612,8 +588,6 @@
                     "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
         }
 
-        mService.mAnimator.executeAfterPrepareSurfacesRunnables();
-
         final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
 
         // If we are ready to perform an app transition, check through all of the app tokens to be
@@ -750,19 +724,6 @@
                     (mSustainedPerformanceModeEnabled ? 1 : 0));
         }
 
-        if (mService.mTurnOnScreen) {
-            if (mService.mAllowTheaterModeWakeFromLayout
-                    || Settings.Global.getInt(mService.mContext.getContentResolver(),
-                    Settings.Global.THEATER_MODE_ON, 0) == 0) {
-                if (DEBUG_VISIBILITY || DEBUG_POWER) {
-                    Slog.v(TAG, "Turning screen on after layout!");
-                }
-                mService.mPowerManager.wakeUp(SystemClock.uptimeMillis(),
-                        "android.server.wm:TURN_ON");
-            }
-            mService.mTurnOnScreen = false;
-        }
-
         if (mUpdateRotation) {
             if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
             // TODO(multi-display): Update rotation for different displays separately.
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index dc62cc8..98fcb0b 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -151,6 +151,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void startPendingAnimationsLocked() {
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             startAnimationLocked(mPendingAnimations.valueAt(i));
@@ -158,6 +159,7 @@
         mPendingAnimations.clear();
     }
 
+    @GuardedBy("mLock")
     private void startAnimationLocked(RunningAnimation a) {
         final ValueAnimator anim = mAnimatorFactory.makeAnimator();
 
@@ -167,7 +169,12 @@
         anim.addUpdateListener(animation -> {
             synchronized (mCancelLock) {
                 if (!a.mCancelled) {
-                    applyTransformation(a, mFrameTransaction, anim.getCurrentPlayTime());
+                    final long duration = anim.getDuration();
+                    long currentPlayTime = anim.getCurrentPlayTime();
+                    if (currentPlayTime > duration) {
+                        currentPlayTime = duration;
+                    }
+                    applyTransformation(a, mFrameTransaction, currentPlayTime);
                 }
             }
 
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 0512a08..83baee1 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -53,7 +53,8 @@
     SurfaceControl mLeash;
     private final Animatable mAnimatable;
     private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
-    private final Runnable mAnimationFinishedCallback;
+    @VisibleForTesting
+    final Runnable mAnimationFinishedCallback;
     private boolean mAnimationStartDelayed;
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 7b047a8..621bee7 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -281,11 +281,13 @@
             mSnapshot = snapshot;
         }
 
+        @GuardedBy("mLock")
         @Override
         void onQueuedLocked() {
             mStoreQueueItems.offer(this);
         }
 
+        @GuardedBy("mLock")
         @Override
         void onDequeuedLocked() {
             mStoreQueueItems.remove(this);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index da3a035..f2ad6fb 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -272,8 +272,6 @@
     }
 
     boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
-        int xOffset = 0;
-        int yOffset = 0;
         boolean rawChanged = false;
         // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to
         // match the behavior of most Launchers
@@ -285,8 +283,11 @@
         if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
             offset += mLastWallpaperDisplayOffsetX;
         }
-        xOffset = offset;
-
+        boolean changed = wallpaperWin.mXOffset != offset;
+        if (changed) {
+            if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset);
+            wallpaperWin.mXOffset = offset;
+        }
         if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
             wallpaperWin.mWallpaperX = wpx;
             wallpaperWin.mWallpaperXStep = wpxs;
@@ -300,16 +301,17 @@
         if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
             offset += mLastWallpaperDisplayOffsetY;
         }
-        yOffset = offset;
-
+        if (wallpaperWin.mYOffset != offset) {
+            if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset);
+            changed = true;
+            wallpaperWin.mYOffset = offset;
+        }
         if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
             wallpaperWin.mWallpaperY = wpy;
             wallpaperWin.mWallpaperYStep = wpys;
             rawChanged = true;
         }
 
-        boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset);
-
         if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
                 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
             try {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index ddda027..2ae5c7b 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -74,6 +74,10 @@
         for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
             final WindowState wallpaper = mChildren.get(wallpaperNdx);
             if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) {
+                final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
+                winAnimator.computeShownFrameLocked();
+                // No need to lay out the windows - we can just set the wallpaper position directly.
+                winAnimator.setWallpaperOffset(wallpaper.mShownPosition);
                 // We only want to be synchronous with one wallpaper.
                 sync = false;
             }
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index b0d42f2..49a30d5 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -92,7 +92,6 @@
      * executed and the corresponding transaction is closed and applied.
      */
     private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
-    private boolean mInExecuteAfterPrepareSurfacesRunnables;
 
     WindowAnimator(final WindowManagerService service) {
         mService = service;
@@ -162,7 +161,7 @@
                 final int numDisplays = mDisplayContentsAnimators.size();
                 for (int i = 0; i < numDisplays; i++) {
                     final int displayId = mDisplayContentsAnimators.keyAt(i);
-                    final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
                     DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
 
                     final ScreenRotationAnimation screenRotationAnimation =
@@ -196,7 +195,7 @@
 
                 for (int i = 0; i < numDisplays; i++) {
                     final int displayId = mDisplayContentsAnimators.keyAt(i);
-                    final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
 
                     dc.checkAppWindowsReadyToShow();
 
@@ -229,7 +228,7 @@
             final int numDisplays = mDisplayContentsAnimators.size();
             for (int i = 0; i < numDisplays; i++) {
                 final int displayId = mDisplayContentsAnimators.keyAt(i);
-                final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
                 dc.onPendingTransactionApplied();
             }
 
@@ -306,7 +305,7 @@
                     pw.println(":");
             final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
             final DisplayContent dc =
-                    mService.mRoot.getDisplayContentOrCreate(mDisplayContentsAnimators.keyAt(i));
+                    mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i));
             dc.dumpWindowAnimators(pw, subPrefix);
             if (displayAnimator.mScreenRotationAnimation != null) {
                 pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
@@ -340,7 +339,7 @@
         if (displayId < 0) {
             return 0;
         }
-        final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId);
+        final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
         return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
     }
 
@@ -348,7 +347,7 @@
         if (displayId < 0) {
             return;
         }
-        final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId);
+        final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
         if (displayContent != null) {
             displayContent.pendingLayoutChanges |= changes;
         }
@@ -439,13 +438,7 @@
         scheduleAnimation();
     }
 
-    void executeAfterPrepareSurfacesRunnables() {
-
-        // Don't even think about to start recursing!
-        if (mInExecuteAfterPrepareSurfacesRunnables) {
-            return;
-        }
-        mInExecuteAfterPrepareSurfacesRunnables = true;
+    private void executeAfterPrepareSurfacesRunnables() {
 
         // Traverse in order they were added.
         final int size = mAfterPrepareSurfacesRunnables.size();
@@ -453,6 +446,5 @@
             mAfterPrepareSurfacesRunnables.get(i).run();
         }
         mAfterPrepareSurfacesRunnables.clear();
-        mInExecuteAfterPrepareSurfacesRunnables = false;
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d565a6a..c2ed2ae 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -737,7 +737,6 @@
     final InputManagerService mInputManager;
     final DisplayManagerInternal mDisplayManagerInternal;
     final DisplayManager mDisplayManager;
-    private final Display[] mDisplays;
 
     // Indicates whether this device supports wide color gamut rendering
     private boolean mHasWideColorGamutSupport;
@@ -746,8 +745,6 @@
     private Session mHoldingScreenOn;
     private PowerManager.WakeLock mHoldingScreenWakeLock;
 
-    boolean mTurnOnScreen;
-
     // Whether or not a layout can cause a wake up when theater mode is enabled.
     boolean mAllowTheaterModeWakeFromLayout;
 
@@ -904,16 +901,9 @@
     public static WindowManagerService main(final Context context, final InputManagerService im,
             final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
             WindowManagerPolicy policy) {
-        return main(context, im, haveInputMethods, showBootMsgs, onlyCore, policy,
-                new SurfaceAnimationRunner());
-    }
-
-    public static WindowManagerService main(final Context context, final InputManagerService im,
-            final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
-            WindowManagerPolicy policy, SurfaceAnimationRunner surfaceAnimationRunner) {
         DisplayThread.getHandler().runWithScissors(() ->
                 sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
-                        onlyCore, policy, surfaceAnimationRunner), 0);
+                        onlyCore, policy), 0);
         return sInstance;
     }
 
@@ -922,7 +912,6 @@
             @Override
             public void run() {
                 WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
-
                 mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
             }
         }, 0);
@@ -936,7 +925,7 @@
 
     private WindowManagerService(Context context, InputManagerService inputManager,
             boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
-            WindowManagerPolicy policy, SurfaceAnimationRunner surfaceAnimationRunner) {
+            WindowManagerPolicy policy) {
         installLock(this, INDEX_WINDOW);
         mContext = context;
         mHaveInputMethods = haveInputMethods;
@@ -981,10 +970,6 @@
         }
 
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
-        mDisplays = mDisplayManager.getDisplays();
-        for (Display display : mDisplays) {
-            createDisplayContentLocked(display);
-        }
 
         mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
 
@@ -1063,7 +1048,7 @@
                 PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM);
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
-        mSurfaceAnimationRunner = surfaceAnimationRunner;
+        mSurfaceAnimationRunner = new SurfaceAnimationRunner();
 
         mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
@@ -1073,6 +1058,13 @@
         mDragDropController = new DragDropController(this, mH.getLooper());
 
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
+    }
+
+    /**
+     * Called after all entities (such as the {@link ActivityManagerService}) have been set up and
+     * associated with the {@link WindowManagerService}.
+     */
+    public void onInitReady() {
         initPolicy();
 
         // Add ourself to the Watchdog monitors.
@@ -1088,6 +1080,7 @@
         showEmulatorDisplayOverlayIfNeeded();
     }
 
+
     public InputMonitor getInputMonitor() {
         return mInputMonitor;
     }
@@ -1138,7 +1131,7 @@
                 throw new IllegalStateException("Display has not been initialialized");
             }
 
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
                 Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
                         + displayId + ".  Aborting.");
@@ -2284,7 +2277,7 @@
         }
 
         synchronized(mWindowMap) {
-            final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent dc = mRoot.getDisplayContent(displayId);
             WindowToken token = dc.getWindowToken(binder);
             if (token != null) {
                 Slog.w(TAG_WM, "addWindowToken: Attempted to add binder token: " + binder
@@ -3673,7 +3666,7 @@
             boolean wallpaperOnly) {
         final DisplayContent displayContent;
         synchronized(mWindowMap) {
-            displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
                 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot returning null. No Display for "
                         + "displayId=" + displayId);
@@ -3892,7 +3885,7 @@
     public boolean registerWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
             int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
                 throw new IllegalArgumentException("Trying to register visibility event "
                         + "for invalid display: " + displayId);
@@ -4449,10 +4442,13 @@
     }
 
     public void displayReady() {
-        for (Display display : mDisplays) {
+        final int displayCount = mRoot.mChildren.size();
+        for (int i = 0; i < displayCount; ++i) {
+            final DisplayContent display = mRoot.mChildren.get(i);
             displayReady(display.getDisplayId());
         }
 
+
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
             if (mMaxUiWidth > 0) {
@@ -4483,7 +4479,7 @@
 
     private void displayReady(int displayId) {
         synchronized(mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null) {
                 mAnimator.addDisplayLocked(displayId);
                 displayContent.initializeDisplayBaseInfo();
@@ -5032,7 +5028,7 @@
     @Override
     public void getInitialDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 size.x = displayContent.mInitialDisplayWidth;
                 size.y = displayContent.mInitialDisplayHeight;
@@ -5043,7 +5039,7 @@
     @Override
     public void getBaseDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 size.x = displayContent.mBaseDisplayWidth;
                 size.y = displayContent.mBaseDisplayHeight;
@@ -5070,7 +5066,7 @@
                 final int MIN_WIDTH = 200;
                 final int MIN_HEIGHT = 200;
                 final int MAX_SCALE = 2;
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     width = Math.min(Math.max(width, MIN_WIDTH),
                             displayContent.mInitialDisplayWidth * MAX_SCALE);
@@ -5100,7 +5096,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     if (mode < 0 || mode > 1) {
                         mode = 0;
@@ -5182,7 +5178,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
                             displayContent.mInitialDisplayHeight);
@@ -5198,7 +5194,7 @@
     @Override
     public int getInitialDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 return displayContent.mInitialDisplayDensity;
             }
@@ -5209,7 +5205,7 @@
     @Override
     public int getBaseDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 return displayContent.mBaseDisplayDensity;
             }
@@ -5235,7 +5231,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null && mCurrentUserId == targetUserId) {
                     setForcedDisplayDensityLocked(displayContent, density);
                 }
@@ -5266,7 +5262,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null && mCurrentUserId == callingUserId) {
                     setForcedDisplayDensityLocked(displayContent,
                             displayContent.mInitialDisplayDensity);
@@ -5358,7 +5354,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     setOverscanLocked(displayContent, left, top, right, bottom);
                 }
@@ -6621,19 +6617,11 @@
         synchronized (mWindowMap) { }
     }
 
-    // TODO: All the display method below should probably be moved into the RootWindowContainer...
-    private void createDisplayContentLocked(final Display display) {
-        if (display == null) {
-            throw new IllegalArgumentException("getDisplayContent: display must not be null");
-        }
-        mRoot.getDisplayContentOrCreate(display.getDisplayId());
-    }
-
     // There is an inherent assumption that this will never return null.
     // TODO(multi-display): Inspect all the call-points of this method to see if they make sense to
     // support non-default display.
     DisplayContent getDefaultDisplayContentLocked() {
-        return mRoot.getDisplayContentOrCreate(DEFAULT_DISPLAY);
+        return mRoot.getDisplayContent(DEFAULT_DISPLAY);
     }
 
     public void onDisplayAdded(int displayId) {
@@ -6648,10 +6636,6 @@
 
     public void onDisplayRemoved(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
-            if (displayContent != null) {
-                displayContent.removeIfPossible();
-            }
             mAnimator.removeDisplayLocked(displayId);
             mWindowPlacerLocked.requestTraversal();
         }
@@ -6667,7 +6651,7 @@
 
     public void onDisplayChanged(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null) {
                 displayContent.updateDisplayInfo();
             }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3bee1e8..21b4361 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+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;
@@ -137,6 +138,7 @@
 import static com.android.server.wm.proto.WindowStateProto.REMOVE_ON_EXIT;
 import static com.android.server.wm.proto.WindowStateProto.REQUESTED_HEIGHT;
 import static com.android.server.wm.proto.WindowStateProto.REQUESTED_WIDTH;
+import static com.android.server.wm.proto.WindowStateProto.SHOWN_POSITION;
 import static com.android.server.wm.proto.WindowStateProto.STABLE_INSETS;
 import static com.android.server.wm.proto.WindowStateProto.STACK_ID;
 import static com.android.server.wm.proto.WindowStateProto.SURFACE_INSETS;
@@ -166,6 +168,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.MergedConfiguration;
@@ -264,7 +267,7 @@
     // This is a non-system overlay window that is currently force hidden.
     private boolean mForceHideNonSystemOverlayWindow;
     boolean mAppFreezing;
-    boolean mHidden;    // Used to determine if to show child windows.
+    boolean mHidden = true;    // Used to determine if to show child windows.
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
     private boolean mDragResizing;
     private boolean mDragResizingChangeReported = true;
@@ -284,7 +287,6 @@
     int mLayer;
     boolean mHaveFrame;
     boolean mObscured;
-    boolean mTurnOnScreen;
 
     int mLayoutSeq = -1;
 
@@ -296,6 +298,12 @@
     private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration();
 
     /**
+     * Actual position of the surface shown on-screen (may be modified by animation). These are
+     * in the screen's coordinate space (WITH the compatibility scale applied).
+     */
+    final Point mShownPosition = new Point();
+
+    /**
      * Insets that determine the actually visible area.  These are in the application's
      * coordinate space (without compatibility scale applied).
      */
@@ -454,6 +462,10 @@
     int mWallpaperDisplayOffsetX = Integer.MIN_VALUE;
     int mWallpaperDisplayOffsetY = Integer.MIN_VALUE;
 
+    // Wallpaper windows: pixels offset based on above variables.
+    int mXOffset;
+    int mYOffset;
+
     /**
      * This is set after IWindowSession.relayout() has been called at
      * least once for the window.  It allows us to detect the situation
@@ -624,6 +636,11 @@
     private TapExcludeRegionHolder mTapExcludeRegionHolder;
 
     /**
+     * Used for testing because the real PowerManager is final.
+     */
+    private PowerManagerWrapper mPowerManagerWrapper;
+
+    /**
      * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
      * of z-order and 1 otherwise.
      */
@@ -652,9 +669,34 @@
 
     private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
 
+    interface PowerManagerWrapper {
+        void wakeUp(long time, String reason);
+
+        boolean isInteractive();
+
+    }
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
-           WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
-           int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
+            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
+            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
+        this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId,
+                ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
+                    @Override
+                    public void wakeUp(long time, String reason) {
+                        service.mPowerManager.wakeUp(time, reason);
+                    }
+
+                    @Override
+                    public boolean isInteractive() {
+                        return service.mPowerManager.isInteractive();
+                    }
+                });
+    }
+
+    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
+            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
+            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
+            PowerManagerWrapper powerManagerWrapper) {
         super(service);
         mSession = s;
         mClient = c;
@@ -671,6 +713,7 @@
         DeathRecipient deathRecipient = new DeathRecipient();
         mSeq = seq;
         mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
+        mPowerManagerWrapper = powerManagerWrapper;
         if (localLOGV) Slog.v(
             TAG, "Window " + this + " client=" + c.asBinder()
             + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -734,6 +777,8 @@
         mRequestedHeight = 0;
         mLastRequestedWidth = 0;
         mLastRequestedHeight = 0;
+        mXOffset = 0;
+        mYOffset = 0;
         mLayer = 0;
         mInputWindowHandle = new InputWindowHandle(
                 mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c,
@@ -1099,6 +1144,11 @@
     }
 
     @Override
+    public Point getShownPositionLw() {
+        return mShownPosition;
+    }
+
+    @Override
     public Rect getDisplayFrameLw() {
         return mDisplayFrame;
     }
@@ -2257,9 +2307,34 @@
 
     void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
         // We need to turn on screen regardless of visibility.
-        if ((mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0) {
-            if (DEBUG_VISIBILITY) Slog.v(TAG, "Relayout window turning screen on: " + this);
-            mTurnOnScreen = true;
+        boolean hasTurnScreenOnFlag = (mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0;
+        boolean allowTheaterMode =
+                mService.mAllowTheaterModeWakeFromLayout || Settings.Global.getInt(
+                        mService.mContext.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0)
+                        == 0;
+        boolean canTurnScreenOn = mAppToken == null || mAppToken.canTurnScreenOn();
+
+        // The screen will turn on if the following conditions are met
+        // 1. The window has the flag FLAG_TURN_SCREEN_ON
+        // 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
+        // canTurnScreenOn will be set to false so the window doesn't turn the screen on again
+        // during this resume.
+        // 4. When the screen is not interactive. This is because when the screen is already
+        // interactive, the value may persist until the next animation, which could potentially
+        // be occurring while turning off the screen. This would lead to the screen incorrectly
+        // turning back on.
+        if (hasTurnScreenOnFlag && allowTheaterMode && canTurnScreenOn
+                && !mPowerManagerWrapper.isInteractive()) {
+            if (DEBUG_VISIBILITY || DEBUG_POWER) {
+                Slog.v(TAG, "Relayout window turning screen on: " + this);
+            }
+            mPowerManagerWrapper.wakeUp(SystemClock.uptimeMillis(),
+                    "android.server.wm:TURN_ON");
+        }
+        if (mAppToken != null) {
+            mAppToken.setCanTurnScreenOn(false);
         }
 
         // If we were already visible, skip rest of preparation.
@@ -2553,8 +2628,7 @@
                 // in wake lock statistics.  So in particular, we don't want to include the
                 // window's hash code as in toString().
                 final CharSequence tag = getWindowTag();
-                mDrawLock = mService.mPowerManager.newWakeLock(
-                        PowerManager.DRAW_WAKE_LOCK, "Window:" + tag);
+                mDrawLock = mService.mPowerManager.newWakeLock(DRAW_WAKE_LOCK, "Window:" + tag);
                 mDrawLock.setReferenceCounted(false);
                 mDrawLock.setWorkSource(new WorkSource(mOwnerUid, mAttrs.packageName));
             }
@@ -3116,6 +3190,7 @@
         mContentInsets.writeToProto(proto, CONTENT_INSETS);
         mAttrs.surfaceInsets.writeToProto(proto, SURFACE_INSETS);
         mSurfacePosition.writeToProto(proto, SURFACE_POSITION);
+        mShownPosition.writeToProto(proto, SHOWN_POSITION);
         mWinAnimator.writeToProto(proto, ANIMATOR);
         proto.write(ANIMATING_EXIT, mAnimatingExit);
         for (int i = 0; i < mChildren.size(); i++) {
@@ -3231,6 +3306,10 @@
             pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
                     pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded);
         }
+        if (mXOffset != 0 || mYOffset != 0) {
+            pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
+                    pw.print(" y="); pw.println(mYOffset);
+        }
         if (dumpAll) {
             pw.print(prefix); pw.print("mGivenContentInsets=");
                     mGivenContentInsets.printShortString(pw);
@@ -3249,6 +3328,7 @@
                     pw.println(getLastReportedConfiguration());
         }
         pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
+                pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
                 pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
                 pw.print(" mWindowRemovalAllowed="); pw.println(mWindowRemovalAllowed);
         if (dumpAll) {
@@ -3303,15 +3383,13 @@
                     pw.print(" mDestroying="); pw.print(mDestroying);
                     pw.print(" mRemoved="); pw.println(mRemoved);
         }
-        if (getOrientationChanging() || mAppFreezing || mTurnOnScreen
-                || mReportOrientationChanged) {
+        if (getOrientationChanging() || mAppFreezing || mReportOrientationChanged) {
             pw.print(prefix); pw.print("mOrientationChanging=");
                     pw.print(mOrientationChanging);
                     pw.print(" configOrientationChanging=");
                     pw.print(getLastReportedConfiguration().orientation
                             != getConfiguration().orientation);
                     pw.print(" mAppFreezing="); pw.print(mAppFreezing);
-                    pw.print(" mTurnOnScreen="); pw.print(mTurnOnScreen);
                     pw.print(" mReportOrientationChanged="); pw.println(mReportOrientationChanged);
         }
         if (mLastFreezeDuration != 0) {
@@ -4171,8 +4249,9 @@
         final int width = mFrame.width();
         final int height = mFrame.height();
 
-        final int left = mFrame.left;
-        final int top = mFrame.top;
+        // Compute the offset of the window in relation to the decor rect.
+        final int left = mXOffset + mFrame.left;
+        final int top = mYOffset + mFrame.top;
 
         // Initialize the decor rect to the entire frame.
         if (isDockedResizing()) {
@@ -4367,8 +4446,8 @@
         float9[Matrix.MSKEW_Y] = mWinAnimator.mDtDx;
         float9[Matrix.MSKEW_X] = mWinAnimator.mDtDy;
         float9[Matrix.MSCALE_Y] = mWinAnimator.mDsDy;
-        int x = mSurfacePosition.x;
-        int y = mSurfacePosition.y;
+        int x = mSurfacePosition.x + mShownPosition.x;
+        int y = mSurfacePosition.y + mShownPosition.y;
 
         // If changed, also adjust transformFrameToSurfacePosition
         final WindowContainer parent = getParent();
@@ -4480,8 +4559,12 @@
         if (!mAnimatingExit && mAppDied) {
             mIsDimming = true;
             dimmer.dimAbove(getPendingTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW);
-        } else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0
-                && !mAnimatingExit && isVisible() && !mWinAnimator.mLastHidden) {
+        } else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && isVisibleNow() && !mHidden) {
+            // Only show a dim behind when the following is satisfied:
+            // 1. The window has the flag FLAG_DIM_BEHIND
+            // 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
+            // 3. The WS is considered visible according to the isVisible() method
+            // 4. The WS is not hidden.
             mIsDimming = true;
             dimmer.dimBelow(getPendingTransaction(), this, mAttrs.dimAmount);
         }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 499322c..9621ee5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -209,14 +209,10 @@
     float mExtraHScale = (float) 1.0;
     float mExtraVScale = (float) 1.0;
 
-    // An offset in pixel of the surface contents from the window position. Used for Wallpaper
-    // to provide the effect of scrolling within a large surface. We just use these values as
-    // a cache.
-    int mXOffset = 0;
-    int mYOffset = 0;
-
     private final Rect mTmpSize = new Rect();
 
+    private final SurfaceControl.Transaction mReparentTransaction = new SurfaceControl.Transaction();
+
     WindowStateAnimator(final WindowState win) {
         final WindowManagerService service = win.mService;
 
@@ -377,9 +373,9 @@
                 // child layers need to be reparented to the new surface to make this
                 // transparent to the app.
                 if (mWin.mAppToken == null || mWin.mAppToken.isRelaunching() == false) {
-                    SurfaceControl.openTransaction();
-                    mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController);
-                    SurfaceControl.closeTransaction();
+                    mReparentTransaction.reparentChildren(mPendingDestroySurface.mSurfaceControl,
+                            mSurfaceController.mSurfaceControl.getHandle())
+                            .apply();
                 }
             }
         }
@@ -442,7 +438,7 @@
             flags |= SurfaceControl.SECURE;
         }
 
-        mTmpSize.set(0, 0, 0, 0);
+        mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
         calculateSurfaceBounds(w, attrs);
         final int width = mTmpSize.width();
         final int height = mTmpSize.height();
@@ -593,7 +589,7 @@
                         if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
                             WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
                         }
-                        mPendingDestroySurface.destroyInTransaction();
+                        mPendingDestroySurface.destroyNotInTransaction();
                     }
                     mPendingDestroySurface = mSurfaceController;
                 }
@@ -630,7 +626,7 @@
                 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
                     WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
                 }
-                mPendingDestroySurface.destroyInTransaction();
+                mPendingDestroySurface.destroyNotInTransaction();
                 // Don't hide wallpaper if we're destroying a deferred surface
                 // after a surface mode change.
                 if (!mDestroyPreservedSurfaceUponRedraw) {
@@ -683,8 +679,8 @@
 
             // WindowState.prepareSurfaces expands for surface insets (in order they don't get
             // clipped by the WindowState surface), so we need to go into the other direction here.
-            tmpMatrix.postTranslate(mWin.mAttrs.surfaceInsets.left,
-                    mWin.mAttrs.surfaceInsets.top);
+            tmpMatrix.postTranslate(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
+                    mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
 
 
             // "convert" it into SurfaceFlinger's format
@@ -699,6 +695,9 @@
             mDtDx = tmpFloats[Matrix.MSKEW_Y];
             mDtDy = tmpFloats[Matrix.MSKEW_X];
             mDsDy = tmpFloats[Matrix.MSCALE_Y];
+            float x = tmpFloats[Matrix.MTRANS_X];
+            float y = tmpFloats[Matrix.MTRANS_Y];
+            mWin.mShownPosition.set(Math.round(x), Math.round(y));
 
             // Now set the alpha...  but because our current hardware
             // can't do alpha transformation on a non-opaque surface,
@@ -708,7 +707,8 @@
             mShownAlpha = mAlpha;
             if (!mService.mLimitedAlphaCompositing
                     || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
-                    || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)))) {
+                    || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)
+                            && x == frame.left && y == frame.top))) {
                 //Slog.i(TAG_WM, "Applying alpha transform");
                 if (screenAnimation) {
                     mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha();
@@ -738,6 +738,10 @@
                 TAG, "computeShownFrameLocked: " + this +
                 " not attached, mAlpha=" + mAlpha);
 
+        // WindowState.prepareSurfaces expands for surface insets (in order they don't get
+        // clipped by the WindowState surface), so we need to go into the other direction here.
+        mWin.mShownPosition.set(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left,
+                mWin.mYOffset + mWin.mAttrs.surfaceInsets.top);
         mShownAlpha = mAlpha;
         mHaveMatrix = false;
         mDsDx = mWin.mGlobalScale;
@@ -788,6 +792,12 @@
         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
                 + " fullscreen=" + fullscreen);
 
+        if (isFreeformResizing && !w.isChildWindow()) {
+            // For freeform resizing non child windows, we are using the big surface positioned
+            // at 0,0. Thus we must express the crop in that coordinate space.
+            clipRect.offset(w.mShownPosition.x, w.mShownPosition.y);
+        }
+
         w.expandForSurfaceInsets(clipRect);
 
         // The clip rect was generated assuming (0,0) as the window origin,
@@ -829,7 +839,7 @@
             return;
         }
 
-        mTmpSize.set(0, 0, 0, 0);
+        mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
         calculateSurfaceBounds(w, attrs);
 
         mExtraHScale = (float) 1.0;
@@ -963,6 +973,11 @@
             // then take over the scaling until the new buffer arrives, and things
             // will be seamless.
             mForceScaleUntilResize = true;
+        } else {
+            if (!w.mSeamlesslyRotated) {
+                mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
+                        recoveringMemory);
+            }
         }
 
         // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
@@ -1093,31 +1108,6 @@
                         w.setOrientationChanging(false);
                     }
                 }
-                // We process mTurnOnScreen even for windows which have already
-                // been shown, to handle cases where windows are not necessarily
-                // hidden while the screen is turning off.
-                // TODO(b/63773439): These cases should be eliminated, though we probably still
-                // want to process mTurnOnScreen in this way for clarity.
-                if (mWin.mTurnOnScreen &&
-                        (mWin.mAppToken == null || mWin.mAppToken.canTurnScreenOn())) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
-                    mWin.mTurnOnScreen = false;
-
-                    // The window should only turn the screen on once per resume, but
-                    // prepareSurfaceLocked can be called multiple times. Set canTurnScreenOn to
-                    // false so the window doesn't turn the screen on again during this resume.
-                    if (mWin.mAppToken != null) {
-                        mWin.mAppToken.setCanTurnScreenOn(false);
-                    }
-
-                    // We do not add {@code SET_TURN_ON_SCREEN} when the screen is already
-                    // interactive as the value may persist until the next animation, which could
-                    // potentially occurring while turning off the screen. This would lead to the
-                    // screen incorrectly turning back on.
-                    if (!mService.mPowerManager.isInteractive()) {
-                        mService.mTurnOnScreen = true;
-                    }
-                }
             }
             if (hasSurface()) {
                 w.mToken.hasVisible = true;
@@ -1154,26 +1144,24 @@
         mSurfaceController.setTransparentRegionHint(region);
     }
 
-    boolean setWallpaperOffset(int dx, int dy) {
-        if (mXOffset == dx && mYOffset == dy) {
-            return false;
-        }
-        mXOffset = dx;
-        mYOffset = dy;
+    void setWallpaperOffset(Point shownPosition) {
+        final LayoutParams attrs = mWin.getAttrs();
+        final int left = shownPosition.x - attrs.surfaceInsets.left;
+        final int top = shownPosition.y - attrs.surfaceInsets.top;
 
         try {
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
             mService.openSurfaceTransaction();
-            mSurfaceController.setPositionInTransaction(dx, dy, false);
+            mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
+                    mWin.mFrame.top + top, false);
             applyCrop(null, false);
         } catch (RuntimeException e) {
             Slog.w(TAG, "Error positioning surface of " + mWin
-                    + " pos=(" + dx + "," + dy + ")", e);
+                    + " pos=(" + left + "," + top + ")", e);
         } finally {
             mService.closeSurfaceTransaction("setWallpaperOffset");
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     "<<< CLOSE TRANSACTION setWallpaperOffset");
-            return true;
         }
     }
 
@@ -1408,7 +1396,7 @@
     void destroySurface() {
         try {
             if (mSurfaceController != null) {
-                mSurfaceController.destroyInTransaction();
+                mSurfaceController.destroyNotInTransaction();
             }
         } catch (RuntimeException e) {
             Slog.w(TAG, "Exception thrown when destroying surface " + this
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 2f38556..554a600 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -168,7 +168,7 @@
         }
     }
 
-    void destroyInTransaction() {
+    void destroyNotInTransaction() {
         if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
             Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
         }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 7540e26..72f95fb 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -24,6 +24,7 @@
         "com_android_server_connectivity_Vpn.cpp",
         "com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
         "com_android_server_ConsumerIrService.cpp",
+        "com_android_server_devicepolicy_CryptoTestHelper.cpp",
         "com_android_server_HardwarePropertiesManagerService.cpp",
         "com_android_server_hdmi_HdmiCecController.cpp",
         "com_android_server_input_InputApplicationHandle.cpp",
@@ -109,7 +110,6 @@
         "android.hardware.audio.common@2.0",
         "android.hardware.broadcastradio@1.0",
         "android.hardware.broadcastradio@1.1",
-        "android.hardware.broadcastradio@1.2",
         "android.hardware.contexthub@1.0",
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
@@ -123,6 +123,7 @@
         "android.hardware.tv.input@1.0",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
+        "android.hardware.vibrator@1.2",
         "android.hardware.vr@1.0",
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
diff --git a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
index 176ae81..14e3578 100644
--- a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
+++ b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
@@ -23,7 +23,7 @@
 #include "convert.h"
 
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
-#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <broadcastradio-utils-1x/Utils.h>
 #include <core_jni_helpers.h>
@@ -45,7 +45,6 @@
 
 namespace V1_0 = hardware::broadcastradio::V1_0;
 namespace V1_1 = hardware::broadcastradio::V1_1;
-namespace V1_2 = hardware::broadcastradio::V1_2;
 namespace utils = hardware::broadcastradio::utils;
 
 using V1_0::BandConfig;
@@ -149,11 +148,7 @@
 
         auto halRev = HalRevision::V1_0;
         auto halMinor = 0;
-        if (V1_2::IBroadcastRadioFactory::castFrom(factory).withDefault(nullptr) != nullptr) {
-            halRev = HalRevision::V1_2;
-            halMinor = 2;
-        } else if (V1_1::IBroadcastRadioFactory::castFrom(factory).withDefault(nullptr)
-                != nullptr) {
+        if (V1_1::IBroadcastRadioFactory::castFrom(factory).withDefault(nullptr) != nullptr) {
             halRev = HalRevision::V1_1;
             halMinor = 1;
         }
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index 42c1332..36d2994 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -22,7 +22,7 @@
 #include "convert.h"
 #include "TunerCallback.h"
 
-#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
 #include <binder/IPCThreadState.h>
 #include <broadcastradio-utils-1x/Utils.h>
 #include <core_jni_helpers.h>
@@ -44,16 +44,15 @@
 
 namespace V1_0 = hardware::broadcastradio::V1_0;
 namespace V1_1 = hardware::broadcastradio::V1_1;
-namespace V1_2 = hardware::broadcastradio::V1_2;
 namespace utils = hardware::broadcastradio::utils;
 
 using V1_0::Band;
 using V1_0::BandConfig;
 using V1_0::MetaData;
 using V1_0::Result;
+using V1_1::ITunerCallback;
 using V1_1::ProgramListResult;
 using V1_1::VendorKeyValue;
-using V1_2::ITunerCallback;
 using utils::HalRevision;
 
 static mutex gContextMutex;
@@ -94,7 +93,6 @@
     wp<V1_1::IBroadcastRadio> mHalModule11;
     sp<V1_0::ITuner> mHalTuner;
     sp<V1_1::ITuner> mHalTuner11;
-    sp<V1_2::ITuner> mHalTuner12;
     sp<HalDeathRecipient> mHalDeathRecipient;
 
 private:
@@ -181,11 +179,8 @@
 
     ctx.mHalTuner = halTuner;
     ctx.mHalTuner11 = V1_1::ITuner::castFrom(halTuner).withDefault(nullptr);
-    ctx.mHalTuner12 = V1_2::ITuner::castFrom(halTuner).withDefault(nullptr);
     ALOGW_IF(ctx.mHalRev >= HalRevision::V1_1 && ctx.mHalTuner11 == nullptr,
             "Provided tuner does not implement 1.1 HAL");
-    ALOGW_IF(ctx.mHalRev >= HalRevision::V1_2 && ctx.mHalTuner12 == nullptr,
-            "Provided tuner does not implement 1.2 HAL");
 
     ctx.mHalDeathRecipient = new HalDeathRecipient(getNativeCallback(env, jTuner));
     halTuner->linkToDeath(ctx.mHalDeathRecipient, 0);
@@ -209,11 +204,6 @@
     return getNativeContext(nativeContext).mHalTuner11;
 }
 
-static sp<V1_2::ITuner> getHalTuner12(jlong nativeContext) {
-    lock_guard<mutex> lk(gContextMutex);
-    return getNativeContext(nativeContext).mHalTuner12;
-}
-
 sp<ITunerCallback> getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner) {
     return TunerCallback::getNativeCallback(env,
             env->GetObjectField(tuner.get(), gjni.Tuner.tunerCallback));
@@ -243,7 +233,6 @@
     ctx.mHalDeathRecipient = nullptr;
 
     ctx.mHalTuner11 = nullptr;
-    ctx.mHalTuner12 = nullptr;
     ctx.mHalTuner = nullptr;
 }
 
@@ -466,48 +455,6 @@
     convert::ThrowIfFailed(env, halResult);
 }
 
-static jobject nativeSetParameters(JNIEnv *env, jobject obj, jlong nativeContext, jobject jParameters) {
-    ALOGV("%s", __func__);
-
-    auto halTuner = getHalTuner12(nativeContext);
-    if (halTuner == nullptr) {
-        ALOGI("Parameters are not supported with HAL < 1.2");
-        return nullptr;
-    }
-
-    JavaRef<jobject> jResults = nullptr;
-    auto parameters = convert::VendorInfoToHal(env, jParameters);
-    auto hidlResult = halTuner->setParameters(parameters,
-            [&](const hidl_vec<VendorKeyValue> results) {
-        jResults = convert::VendorInfoFromHal(env, results);
-    });
-
-    if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
-
-    return jResults.release();
-}
-
-static jobject nativeGetParameters(JNIEnv *env, jobject obj, jlong nativeContext, jobject jKeys) {
-    ALOGV("%s", __func__);
-
-    auto halTuner = getHalTuner12(nativeContext);
-    if (halTuner == nullptr) {
-        ALOGI("Parameters are not supported with HAL < 1.2");
-        return nullptr;
-    }
-
-    JavaRef<jobject> jResults = nullptr;
-    auto keys = convert::StringListToHal(env, jKeys);
-    auto hidlResult = halTuner->getParameters(keys,
-            [&](const hidl_vec<VendorKeyValue> parameters) {
-        jResults = convert::VendorInfoFromHal(env, parameters);
-    });
-
-    if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
-
-    return jResults.release();
-}
-
 static const JNINativeMethod gTunerMethods[] = {
     { "nativeInit", "(IZI)J", (void*)nativeInit },
     { "nativeFinalize", "(J)V", (void*)nativeFinalize },
@@ -528,8 +475,6 @@
     { "nativeGetImage", "(JI)[B", (void*)nativeGetImage},
     { "nativeIsAnalogForced", "(J)Z", (void*)nativeIsAnalogForced },
     { "nativeSetAnalogForced", "(JZ)V", (void*)nativeSetAnalogForced },
-    { "nativeSetParameters", "(JLjava/util/Map;)Ljava/util/Map;", (void*)nativeSetParameters },
-    { "nativeGetParameters", "(JLjava/util/List;)Ljava/util/Map;", (void*)nativeGetParameters },
 };
 
 } // namespace Tuner
diff --git a/services/core/jni/BroadcastRadio/Tuner.h b/services/core/jni/BroadcastRadio/Tuner.h
index 48c3bc7..818597b 100644
--- a/services/core/jni/BroadcastRadio/Tuner.h
+++ b/services/core/jni/BroadcastRadio/Tuner.h
@@ -22,8 +22,8 @@
 #include "JavaRef.h"
 
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
-#include <android/hardware/broadcastradio/1.2/ITuner.h>
-#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.1/ITuner.h>
+#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
 #include <jni.h>
 #include <utils/StrongPointer.h>
 
@@ -39,7 +39,7 @@
         sp<hardware::broadcastradio::V1_0::IBroadcastRadio> halModule,
         sp<hardware::broadcastradio::V1_0::ITuner> halTuner);
 
-sp<hardware::broadcastradio::V1_2::ITunerCallback>
+sp<hardware::broadcastradio::V1_1::ITunerCallback>
 getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner);
 
 Region getRegion(JNIEnv *env, jobject obj);
diff --git a/services/core/jni/BroadcastRadio/TunerCallback.cpp b/services/core/jni/BroadcastRadio/TunerCallback.cpp
index 39f2c05..085a86a 100644
--- a/services/core/jni/BroadcastRadio/TunerCallback.cpp
+++ b/services/core/jni/BroadcastRadio/TunerCallback.cpp
@@ -40,18 +40,17 @@
 
 namespace V1_0 = hardware::broadcastradio::V1_0;
 namespace V1_1 = hardware::broadcastradio::V1_1;
-namespace V1_2 = hardware::broadcastradio::V1_2;
 namespace utils = hardware::broadcastradio::utils;
 
 using V1_0::Band;
 using V1_0::BandConfig;
 using V1_0::MetaData;
 using V1_0::Result;
+using V1_1::ITunerCallback;
 using V1_1::ProgramInfo;
 using V1_1::ProgramListResult;
 using V1_1::ProgramSelector;
 using V1_1::VendorKeyValue;
-using V1_2::ITunerCallback;
 using utils::HalRevision;
 
 static JavaVM *gvm = nullptr;
@@ -70,7 +69,6 @@
         jmethodID onBackgroundScanAvailabilityChange;
         jmethodID onBackgroundScanComplete;
         jmethodID onProgramListChanged;
-        jmethodID onParametersUpdated;
     } TunerCallback;
 } gjni;
 
@@ -122,7 +120,6 @@
     virtual Return<void> backgroundScanComplete(ProgramListResult result);
     virtual Return<void> programListChanged();
     virtual Return<void> currentProgramInfoChanged(const ProgramInfo& info);
-    virtual Return<void> parametersUpdated(const hidl_vec<VendorKeyValue>& parameters);
 };
 
 struct TunerCallbackContext {
@@ -344,17 +341,6 @@
     return Return<void>();
 }
 
-Return<void> NativeCallback::parametersUpdated(const hidl_vec<VendorKeyValue>& parameters) {
-    ALOGV("%s", __func__);
-
-    mCallbackThread.enqueue([this, parameters](JNIEnv *env) {
-        auto jParameters = convert::VendorInfoFromHal(env, parameters);
-        env->CallVoidMethod(mJCallback, gjni.TunerCallback.onParametersUpdated, jParameters.get());
-    });
-
-    return {};
-}
-
 static TunerCallbackContext& getNativeContext(jlong nativeContextHandle) {
     auto nativeContext = reinterpret_cast<TunerCallbackContext*>(nativeContextHandle);
     LOG_ALWAYS_FATAL_IF(nativeContext == nullptr, "Native context not initialized");
@@ -441,8 +427,6 @@
             "onBackgroundScanComplete", "()V");
     gjni.TunerCallback.onProgramListChanged = GetMethodIDOrDie(env, tunerCbClass,
             "onProgramListChanged", "()V");
-    gjni.TunerCallback.onParametersUpdated = GetMethodIDOrDie(env, tunerCbClass,
-            "onParametersUpdated", "(Ljava/util/Map;)V");
 
     auto res = jniRegisterNativeMethods(env, "com/android/server/broadcastradio/hal1/TunerCallback",
             gTunerCallbackMethods, NELEM(gTunerCallbackMethods));
diff --git a/services/core/jni/BroadcastRadio/TunerCallback.h b/services/core/jni/BroadcastRadio/TunerCallback.h
index 7e776c2..af12d21 100644
--- a/services/core/jni/BroadcastRadio/TunerCallback.h
+++ b/services/core/jni/BroadcastRadio/TunerCallback.h
@@ -21,7 +21,7 @@
 #include "NativeCallbackThread.h"
 #include "types.h"
 
-#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
 #include <jni.h>
 
 namespace android {
@@ -32,7 +32,7 @@
 namespace BroadcastRadio {
 namespace TunerCallback {
 
-sp<hardware::broadcastradio::V1_2::ITunerCallback>
+sp<hardware::broadcastradio::V1_1::ITunerCallback>
 getNativeCallback(JNIEnv *env, jobject jTunerCallback);
 
 } // namespace TunerCallback
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index bcb0b4f..47350c1 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -385,20 +385,21 @@
     delete impl;
 }
 
-static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
+static jint android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
 {
     AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
     struct timespec ts;
     ts.tv_sec = seconds;
     ts.tv_nsec = nanoseconds;
 
-    int result = impl->set(type, &ts);
+    const int result = impl->set(type, &ts);
     if (result < 0)
     {
         ALOGE("Unable to set alarm to %lld.%09lld: %s\n",
               static_cast<long long>(seconds),
               static_cast<long long>(nanoseconds), strerror(errno));
     }
+    return result >= 0 ? 0 : errno;
 }
 
 static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
@@ -424,7 +425,7 @@
      /* name, signature, funcPtr */
     {"init", "()J", (void*)android_server_AlarmManagerService_init},
     {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
-    {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
+    {"set", "(JIJJ)I", (void*)android_server_AlarmManagerService_set},
     {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
     {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
     {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
diff --git a/services/core/jni/com_android_server_ArcVideoService.cpp b/services/core/jni/com_android_server_ArcVideoService.cpp
index 7df8276..f93cd90 100644
--- a/services/core/jni/com_android_server_ArcVideoService.cpp
+++ b/services/core/jni/com_android_server_ArcVideoService.cpp
@@ -32,7 +32,7 @@
 #include <arc/Future.h>
 #include <arc/IArcBridgeService.h>
 #include <arc/MojoProcessSupport.h>
-#include <video.mojom.h>
+#include <components/arc/common/video.mojom.h>
 
 namespace {
 
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index d2f374d..016de14 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -18,7 +18,10 @@
 
 #include <android/hardware/vibrator/1.0/IVibrator.h>
 #include <android/hardware/vibrator/1.0/types.h>
-#include <android/hardware/vibrator/1.1/IVibrator.h>
+#include <android/hardware/vibrator/1.0/IVibrator.h>
+#include <android/hardware/vibrator/1.1/types.h>
+#include <android/hardware/vibrator/1.2/IVibrator.h>
+#include <android/hardware/vibrator/1.2/types.h>
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
@@ -32,15 +35,15 @@
 #include <stdio.h>
 
 using android::hardware::Return;
-using android::hardware::vibrator::V1_0::Effect;
 using android::hardware::vibrator::V1_0::EffectStrength;
-using android::hardware::vibrator::V1_0::IVibrator;
 using android::hardware::vibrator::V1_0::Status;
 using android::hardware::vibrator::V1_1::Effect_1_1;
-using IVibrator_1_1 = android::hardware::vibrator::V1_1::IVibrator;
 
-namespace android
-{
+namespace V1_0 = android::hardware::vibrator::V1_0;
+namespace V1_1 = android::hardware::vibrator::V1_1;
+namespace V1_2 = android::hardware::vibrator::V1_2;
+
+namespace android {
 
 static constexpr int NUM_TRIES = 2;
 
@@ -84,19 +87,29 @@
     return ret;
 }
 
+template<class R>
+bool isValidEffect(jlong effect) {
+    if (effect < 0) {
+        return false;
+    }
+    R val = static_cast<R>(effect);
+    auto iter = hardware::hidl_enum_iterator<R>();
+    return val >= *iter.begin() && val < *std::prev(iter.end());
+}
+
 static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
 {
-    halCall(&IVibrator::ping).isOk();
+    halCall(&V1_0::IVibrator::ping).isOk();
 }
 
 static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
 {
-    return halCall(&IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
+    return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
 }
 
 static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
 {
-    Status retStatus = halCall(&IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
+    Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
     if (retStatus != Status::OK) {
         ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
     }
@@ -104,18 +117,18 @@
 
 static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
 {
-    Status retStatus = halCall(&IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
+    Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
     if (retStatus != Status::OK) {
         ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
     }
 }
 
 static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jobject) {
-    return halCall(&IVibrator::supportsAmplitudeControl).withDefault(false);
+    return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
 }
 
 static void vibratorSetAmplitude(JNIEnv*, jobject, jint amplitude) {
-    Status status = halCall(&IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
+    Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
         .withDefault(Status::UNKNOWN_ERROR);
     if (status != Status::OK) {
       ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
@@ -132,22 +145,25 @@
     };
     EffectStrength effectStrength(static_cast<EffectStrength>(strength));
 
-    if (effect < 0  || effect > static_cast<uint32_t>(Effect_1_1::TICK)) {
+    Return<void> ret;
+    if (isValidEffect<V1_0::Effect>(effect)) {
+        ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
+                effectStrength, callback);
+    } else if (isValidEffect<Effect_1_1>(effect)) {
+        ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect),
+                           effectStrength, callback);
+    } else if (isValidEffect<V1_2::Effect>(effect)) {
+        ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
+                           effectStrength, callback);
+    } else {
         ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
                 static_cast<int32_t>(effect));
-    } else if (effect == static_cast<uint32_t>(Effect_1_1::TICK)) {
-        auto ret = halCall(&IVibrator_1_1::perform_1_1, static_cast<Effect_1_1>(effect),
-                           effectStrength, callback);
-        if (!ret.isOk()) {
-            ALOGW("Failed to perform effect (%" PRId32 "), insufficient HAL version",
-                    static_cast<int32_t>(effect));
-        }
-    } else {
-        auto ret = halCall(&IVibrator::perform, static_cast<Effect>(effect), effectStrength,
-                           callback);
-        if (!ret.isOk()) {
-            ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
-        }
+        return -1;
+    }
+
+    if (!ret.isOk()) {
+        ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
+        return -1;
     }
 
     if (status == Status::OK) {
@@ -160,6 +176,7 @@
                 ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
                 static_cast<int32_t>(strength), static_cast<uint32_t>(status));
     }
+
     return -1;
 }
 
diff --git a/services/core/jni/com_android_server_devicepolicy_CryptoTestHelper.cpp b/services/core/jni/com_android_server_devicepolicy_CryptoTestHelper.cpp
new file mode 100644
index 0000000..b53ea92
--- /dev/null
+++ b/services/core/jni/com_android_server_devicepolicy_CryptoTestHelper.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+#include "core_jni_helpers.h"
+
+#include <openssl/crypto.h>
+
+namespace {
+
+static jint runSelfTest(JNIEnv* env, jobject /* clazz */) {
+    return BORINGSSL_self_test();
+}
+
+static const JNINativeMethod methods[] = {
+    /* name, signature, funcPtr */
+    {"runSelfTest", "()I", (void*) runSelfTest}
+};
+
+} // anonymous namespace
+
+namespace android {
+
+int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv *env) {
+    return jniRegisterNativeMethods(
+            env, "com/android/server/devicepolicy/CryptoTestHelper", methods, NELEM(methods));
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 07ddb05..bf2a637 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -42,6 +42,7 @@
 int register_android_server_location_GnssLocationProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
 int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv*);
+int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv*);
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
 int register_android_server_tv_TvUinputBridge(JNIEnv* env);
 int register_android_server_tv_TvInputHal(JNIEnv* env);
@@ -88,6 +89,7 @@
     register_android_server_location_GnssLocationProvider(env);
     register_android_server_connectivity_Vpn(env);
     register_android_server_connectivity_tethering_OffloadHardwareInterface(env);
+    register_android_server_devicepolicy_CryptoTestHelper(env);
     register_android_server_ConsumerIrService(env);
     register_android_server_BatteryStatsService(env);
     register_android_server_hdmi_HdmiCecController(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 9fcf3ee..3557dc9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -122,16 +122,6 @@
     }
 
     @Override
-    public void setPrintingEnabled(ComponentName admin, boolean enabled) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean isPrintingEnabled() {
-        return true;
-    }
-
-    @Override
     public List<String> setMeteredDataDisabled(ComponentName admin, List<String> packageNames) {
         return packageNames;
     }
@@ -177,4 +167,9 @@
             String packageName, int userId) {
         return false;
     }
+
+    @Override
+    public long forceSecurityLogs() {
+        return 0;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CryptoTestHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/CryptoTestHelper.java
new file mode 100644
index 0000000..a20758e
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/CryptoTestHelper.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.app.admin.SecurityLog;
+
+/**
+ * Helper to call native BoringSSL self test.
+ */
+public class CryptoTestHelper {
+    public static void runAndLogSelfTest() {
+        final int result = runSelfTest();
+        SecurityLog.writeEvent(SecurityLog.TAG_CRYPTO_SELF_TEST_COMPLETED, result);
+    }
+    private static native int runSelfTest();
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
index 60f204d..0c0ce8d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
@@ -193,6 +193,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void disconnectServiceOnUserLocked(int userId, @NonNull String actionForLog) {
         final DevicePolicyServiceConnection conn = mConnections.get(userId);
         if (conn != null) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4c57f7f..8753344 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -305,8 +305,6 @@
 
     private static final String TAG_PASSWORD_VALIDITY = "password-validity";
 
-    private static final String TAG_PRINTING_ENABLED = "printing-enabled";
-
     private static final String TAG_TRANSFER_OWNERSHIP_BUNDLE = "transfer-ownership-bundle";
 
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
@@ -615,8 +613,6 @@
 
         long mPasswordTokenHandle = 0;
 
-        boolean mPrintingEnabled = true;
-
         public DevicePolicyData(int userHandle) {
             mUserHandle = userHandle;
         }
@@ -2048,6 +2044,10 @@
         public TransferOwnershipMetadataManager newTransferOwnershipMetadataManager() {
             return new TransferOwnershipMetadataManager();
         }
+
+        public void runCryptoSelfTest() {
+            CryptoTestHelper.runAndLogSelfTest();
+        }
     }
 
     /**
@@ -2300,6 +2300,7 @@
 
             if (hasDeviceOwner && mInjector.securityLogGetLoggingEnabledProperty()) {
                 mSecurityLogMonitor.start();
+                mInjector.runCryptoSelfTest();
                 maybePauseDeviceWideLoggingLocked();
             }
         }
@@ -2948,12 +2949,6 @@
                 out.endTag(null, TAG_CURRENT_INPUT_METHOD_SET);
             }
 
-            if (!policy.mPrintingEnabled) {
-                out.startTag(null, TAG_PRINTING_ENABLED);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(policy.mPrintingEnabled));
-                out.endTag(null, TAG_PRINTING_ENABLED);
-            }
-
             for (final String cert : policy.mOwnerInstalledCaCerts) {
                 out.startTag(null, TAG_OWNER_INSTALLED_CA_CERT);
                 out.attribute(null, ATTR_ALIAS, cert);
@@ -3172,9 +3167,6 @@
                     policy.mCurrentInputMethodSet = true;
                 } else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) {
                     policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS));
-                } else if (TAG_PRINTING_ENABLED.equals(tag)) {
-                    String enabled = parser.getAttributeValue(null, ATTR_VALUE);
-                    policy.mPrintingEnabled = Boolean.toString(true).equals(enabled);
                 } else {
                     Slog.w(LOG_TAG, "Unknown tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -10234,6 +10226,7 @@
             mInjector.registerContentObserver(mDefaultImeChanged, false, this, UserHandle.USER_ALL);
         }
 
+        @GuardedBy("DevicePolicyManagerService.this")
         private void addPendingChangeByOwnerLocked(int userId) {
             mUserIdsWithPendingChangesByOwner.add(userId);
         }
@@ -10417,7 +10410,7 @@
         public CharSequence getPrintingDisabledReasonForUser(@UserIdInt int userId) {
             synchronized (DevicePolicyManagerService.this) {
                 DevicePolicyData policy = getUserData(userId);
-                if (policy.mPrintingEnabled) {
+                if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_PRINTING)) {
                     Log.e(LOG_TAG, "printing is enabled");
                     return null;
                 }
@@ -11659,6 +11652,15 @@
         return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
     }
 
+    @Override
+    public long forceSecurityLogs() {
+        enforceShell("forceSecurityLogs");
+        if (!mInjector.securityLogGetLoggingEnabledProperty()) {
+            throw new IllegalStateException("logging is not available");
+        }
+        return mSecurityLogMonitor.forceLogs();
+    }
+
     private void enforceCanManageDeviceAdmin() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS,
                 null);
@@ -12780,27 +12782,6 @@
         }
     }
 
-    private boolean hasPrinting() {
-        return mInjector.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PRINTING);
-    }
-
-    @Override
-    public void setPrintingEnabled(ComponentName admin, boolean enabled) {
-        if (!mHasFeature || !hasPrinting()) {
-            return;
-        }
-        Preconditions.checkNotNull(admin, "Admin cannot be null.");
-        enforceProfileOrDeviceOwner(admin);
-        synchronized (this) {
-            final int userHandle = mInjector.userHandleGetCallingUserId();
-            DevicePolicyData policy = getUserData(userHandle);
-            if (policy.mPrintingEnabled != enabled) {
-                policy.mPrintingEnabled = enabled;
-                saveSettingsLocked(userHandle);
-            }
-        }
-    }
-
     private void deleteTransferOwnershipMetadataFileLocked() {
         mTransferOwnershipMetadataManager.deleteMetadataFile();
     }
@@ -12830,25 +12811,6 @@
         }
     }
 
-    /**
-     * Returns whether printing is enabled for current user.
-     * @hide
-     */
-    @Override
-    public boolean isPrintingEnabled() {
-        if (!hasPrinting()) {
-            return false;
-        }
-        if (!mHasFeature) {
-            return true;
-        }
-        synchronized (this) {
-            final int userHandle = mInjector.userHandleGetCallingUserId();
-            DevicePolicyData policy = getUserData(userHandle);
-            return policy.mPrintingEnabled;
-        }
-    }
-
     @Override
     public int addOverrideApn(@NonNull ComponentName who, @NonNull ApnSetting apnSetting) {
         if (!mHasFeature) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index 3277adf..fb34913 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -16,6 +16,9 @@
 
 package com.android.server.devicepolicy;
 
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
 import android.app.admin.DeviceAdminReceiver;
 import android.app.admin.SecurityLog;
 import android.app.admin.SecurityLog.SecurityEvent;
@@ -30,6 +33,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
@@ -55,6 +59,7 @@
     SecurityLogMonitor(DevicePolicyManagerService service, long id) {
         this.mService = service;
         this.mId = id;
+        this.mLastForceNanos = System.nanoTime();
     }
 
     private static final boolean DEBUG = false;  // STOPSHIP if true.
@@ -77,20 +82,22 @@
     /**
      * How often should Device Owner be notified under normal circumstances.
      */
-    private static final long RATE_LIMIT_INTERVAL_MILLISECONDS = TimeUnit.HOURS.toMillis(2);
+    private static final long RATE_LIMIT_INTERVAL_MS = TimeUnit.HOURS.toMillis(2);
     /**
      * How often to retry the notification about available logs if it is ignored or missed by DO.
      */
-    private static final long BROADCAST_RETRY_INTERVAL_MILLISECONDS = TimeUnit.MINUTES.toMillis(30);
+    private static final long BROADCAST_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(30);
     /**
      * Internally how often should the monitor poll the security logs from logd.
      */
-    private static final long POLLING_INTERVAL_MILLISECONDS = TimeUnit.MINUTES.toMillis(1);
+    private static final long POLLING_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
     /**
      * Overlap between two subsequent log requests, required to avoid losing out of order events.
      */
-    private static final long OVERLAP_NANOS = TimeUnit.SECONDS.toNanos(3);
+    private static final long OVERLAP_NS = TimeUnit.SECONDS.toNanos(3);
 
+    /** Minimum time between forced fetch attempts. */
+    private static final long FORCE_FETCH_THROTTLE_NS = TimeUnit.SECONDS.toNanos(10);
 
     @GuardedBy("mLock")
     private Thread mMonitorThread = null;
@@ -122,6 +129,13 @@
     @GuardedBy("mLock")
     private boolean mPaused = false;
 
+    /** Semaphore used to force log fetching on request from adb. */
+    private final Semaphore mForceSemaphore = new Semaphore(0 /* permits */);
+
+    /** The last timestamp when force fetch was used, to prevent abuse. */
+    @GuardedBy("mForceSemaphore")
+    private long mLastForceNanos = 0;
+
     void start() {
         Slog.i(TAG, "Starting security logging.");
         SecurityLog.writeEvent(SecurityLog.TAG_LOGGING_STARTED);
@@ -203,7 +217,7 @@
 
         Slog.i(TAG, "Resumed.");
         try {
-            notifyDeviceOwnerIfNeeded();
+            notifyDeviceOwnerIfNeeded(false /* force */);
         } catch (InterruptedException e) {
             Log.w(TAG, "Thread interrupted.", e);
         }
@@ -231,7 +245,7 @@
             if (mAllowedToRetrieve) {
                 mAllowedToRetrieve = false;
                 mNextAllowedRetrievalTimeMillis = SystemClock.elapsedRealtime()
-                        + RATE_LIMIT_INTERVAL_MILLISECONDS;
+                        + RATE_LIMIT_INTERVAL_MS;
                 List<SecurityEvent> result = mPendingLogs;
                 mPendingLogs = new ArrayList<>();
                 mCriticalLevelLogged = false;
@@ -247,8 +261,7 @@
     /**
      * Requests the next (or the first) batch of events from the log with appropriate timestamp.
      */
-    private void getNextBatch(ArrayList<SecurityEvent> newLogs)
-            throws IOException, InterruptedException {
+    private void getNextBatch(ArrayList<SecurityEvent> newLogs) throws IOException {
         if (mLastEventNanos < 0) {
             // Non-blocking read that returns all logs immediately.
             if (DEBUG) Slog.d(TAG, "SecurityLog.readEvents");
@@ -257,7 +270,7 @@
             // If we have last events from the previous batch, request log events with time overlap
             // with previously retrieved messages to avoid losing events due to reordering in logd.
             final long startNanos = mLastEvents.isEmpty()
-                    ? mLastEventNanos : Math.max(0, mLastEventNanos - OVERLAP_NANOS);
+                    ? mLastEventNanos : Math.max(0, mLastEventNanos - OVERLAP_NS);
             if (DEBUG) Slog.d(TAG, "SecurityLog.readEventsSince: " + startNanos);
             // Non-blocking read that returns all logs with timestamps >= startNanos immediately.
             SecurityLog.readEventsSince(startNanos, newLogs);
@@ -293,7 +306,7 @@
         // Position of the earliest event that has to be saved. Start from the penultimate event,
         // going backward.
         int pos = newLogs.size() - 2;
-        while (pos >= 0 && mLastEventNanos - newLogs.get(pos).getTimeNanos() < OVERLAP_NANOS) {
+        while (pos >= 0 && mLastEventNanos - newLogs.get(pos).getTimeNanos() < OVERLAP_NS) {
             pos--;
         }
         // We either run past the start of the list or encountered an event that is too old to keep.
@@ -401,10 +414,11 @@
     public void run() {
         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
 
-        ArrayList<SecurityEvent> newLogs = new ArrayList<>();
+        final ArrayList<SecurityEvent> newLogs = new ArrayList<>();
         while (!Thread.currentThread().isInterrupted()) {
             try {
-                Thread.sleep(POLLING_INTERVAL_MILLISECONDS);
+                final boolean force = mForceSemaphore.tryAcquire(POLLING_INTERVAL_MS, MILLISECONDS);
+
                 getNextBatch(newLogs);
 
                 mLock.lockInterruptibly();
@@ -416,7 +430,7 @@
 
                 saveLastEvents(newLogs);
                 newLogs.clear();
-                notifyDeviceOwnerIfNeeded();
+                notifyDeviceOwnerIfNeeded(force);
             } catch (IOException e) {
                 Log.e(TAG, "Failed to read security log", e);
             } catch (InterruptedException e) {
@@ -437,7 +451,7 @@
         Slog.i(TAG, "MonitorThread exit.");
     }
 
-    private void notifyDeviceOwnerIfNeeded() throws InterruptedException {
+    private void notifyDeviceOwnerIfNeeded(boolean force) throws InterruptedException {
         boolean allowRetrievalAndNotifyDO = false;
         mLock.lockInterruptibly();
         try {
@@ -445,8 +459,8 @@
                 return;
             }
             final int logSize = mPendingLogs.size();
-            if (logSize >= BUFFER_ENTRIES_NOTIFICATION_LEVEL) {
-                // Allow DO to retrieve logs if too many pending logs
+            if (logSize >= BUFFER_ENTRIES_NOTIFICATION_LEVEL || (force && logSize > 0)) {
+                // Allow DO to retrieve logs if too many pending logs or if forced.
                 if (!mAllowedToRetrieve) {
                     allowRetrievalAndNotifyDO = true;
                 }
@@ -461,7 +475,7 @@
                 mAllowedToRetrieve = true;
                 // Set the timeout to retry the notification if the DO misses it.
                 mNextAllowedRetrievalTimeMillis = SystemClock.elapsedRealtime()
-                        + BROADCAST_RETRY_INTERVAL_MILLISECONDS;
+                        + BROADCAST_RETRY_INTERVAL_MS;
             }
         } finally {
             mLock.unlock();
@@ -472,4 +486,26 @@
                     null);
         }
     }
+
+    /**
+     * Forces the logs to be fetched and made available. Returns 0 on success or timeout to wait
+     * before attempting in milliseconds.
+     */
+    public long forceLogs() {
+        final long nowNanos = System.nanoTime();
+        // We only synchronize with another calls to this function, not with the fetching thread.
+        synchronized (mForceSemaphore) {
+            final long toWaitNanos = mLastForceNanos + FORCE_FETCH_THROTTLE_NS - nowNanos;
+            if (toWaitNanos > 0) {
+                return NANOSECONDS.toMillis(toWaitNanos) + 1; // Round up.
+            }
+            mLastForceNanos = nowNanos;
+            // There is a race condition with the fetching thread below, but if the last permit is
+            // acquired just after we do the check, logs are forced anyway and that's what we need.
+            if (mForceSemaphore.availablePermits() == 0) {
+                mForceSemaphore.release();
+            }
+            return 0;
+        }
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3210f1a..75bb5e4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -65,7 +65,6 @@
 import com.android.server.audio.AudioService;
 import com.android.server.broadcastradio.BroadcastRadioService;
 import com.android.server.camera.CameraServiceProxy;
-import com.android.server.car.CarServiceHelperService;
 import com.android.server.clipboard.ClipboardService;
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.coverage.CoverageService;
@@ -220,6 +219,8 @@
             "com.google.android.things.services.IoTSystemService";
     private static final String SLICE_MANAGER_SERVICE_CLASS =
             "com.android.server.slice.SliceManagerService$Lifecycle";
+    private static final String CAR_SERVICE_HELPER_SERVICE_CLASS =
+            "com.android.internal.car.CarServiceHelperService";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -723,7 +724,6 @@
         MmsServiceBroker mmsService = null;
         HardwarePropertiesManagerService hardwarePropertiesService = null;
 
-        boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false);
         boolean disableSystemTextClassifier = SystemProperties.getBoolean(
                 "config.disable_systemtextclassifier", false);
         boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
@@ -842,6 +842,14 @@
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
             traceEnd();
 
+            traceBeginAndSlog("SetWindowManagerService");
+            mActivityManagerService.setWindowManager(wm);
+            traceEnd();
+
+            traceBeginAndSlog("WindowManagerServiceOnInitReady");
+            wm.onInitReady();
+            traceEnd();
+
             // Start receiving calls from HIDL services. Start in in a separate thread
             // because it need to connect to SensorManager. This have to start
             // after START_SENSOR_SERVICE is done.
@@ -859,10 +867,6 @@
                 traceEnd();
             }
 
-            traceBeginAndSlog("SetWindowManagerService");
-            mActivityManagerService.setWindowManager(wm);
-            traceEnd();
-
             traceBeginAndSlog("StartInputManager");
             inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
             inputManager.start();
@@ -1104,18 +1108,12 @@
                 traceEnd();
             }
 
-            if (!disableRtt) {
-                traceBeginAndSlog("StartWifiRtt");
-                mSystemServiceManager.startService("com.android.server.wifi.RttService");
+            if (context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_WIFI_RTT)) {
+                traceBeginAndSlog("StartRttService");
+                mSystemServiceManager.startService(
+                    "com.android.server.wifi.rtt.RttService");
                 traceEnd();
-
-                if (context.getPackageManager().hasSystemFeature(
-                    PackageManager.FEATURE_WIFI_RTT)) {
-                    traceBeginAndSlog("StartRttService");
-                    mSystemServiceManager.startService(
-                        "com.android.server.wifi.rtt.RttService");
-                    traceEnd();
-                }
             }
 
             if (context.getPackageManager().hasSystemFeature(
@@ -1750,7 +1748,7 @@
 
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
                 traceBeginAndSlog("StartCarServiceHelperService");
-                mSystemServiceManager.startService(CarServiceHelperService.class);
+                mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
                 traceEnd();
             }
 
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 7d9736e..d190432 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -1068,6 +1068,7 @@
         mLastInstallEvent.flags = ApfProgramEvent.flagsFor(mIPv4Address != null, mMulticastFilter);
     }
 
+    @GuardedBy("this")
     private void logApfProgramEventLocked(long now) {
         if (mLastInstallEvent == null) {
             return;
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 49a1e79..8fbc01e 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -268,6 +268,7 @@
         mUnicastResponder = null;
     }
 
+    @GuardedBy("mLock")
     private void assembleRaLocked() {
         final ByteBuffer ra = ByteBuffer.wrap(mRA);
         ra.order(ByteOrder.BIG_ENDIAN);
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index e1c1eb2..e8620ed 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -21,7 +21,6 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
-import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.ComponentName;
 import android.content.Context;
@@ -115,12 +114,9 @@
 
         private final SparseArray<UserState> mUserStates = new SparseArray<>();
 
-        private final DevicePolicyManager mDpm;
-
         PrintManagerImpl(Context context) {
             mContext = context;
             mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-            mDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
             registerContentObservers();
             registerBroadcastReceivers();
         }
@@ -722,7 +718,7 @@
         }
 
         private boolean isPrintingEnabled() {
-            return mDpm == null || mDpm.isPrintingEnabled();
+            return !mUserManager.hasUserRestriction(UserManager.DISALLOW_PRINTING);
         }
 
         private void dump(@NonNull DualDumpOutputStream dumpStream,
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index ba5dde0..c1c32c2 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -596,6 +596,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void bindLocked() throws TimeoutException, InterruptedException {
         while (mIsBinding) {
             mLock.wait();
diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
index e103464..a5beed0 100644
--- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
@@ -17,17 +17,21 @@
 package com.android.server.backup;
 
 import static com.android.server.backup.testing.TransportData.backupTransport;
-import static com.android.server.backup.testing.TransportTestUtils.setUpTransport;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
@@ -40,7 +44,10 @@
 import android.app.IActivityManager;
 import android.app.IBackupAgent;
 import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupManager;
+import android.app.backup.BackupTransport;
 import android.app.backup.FullBackupDataOutput;
 import android.app.backup.IBackupManager;
 import android.app.backup.IBackupManagerMonitor;
@@ -53,6 +60,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
@@ -65,6 +73,7 @@
 import com.android.server.backup.internal.OnTaskFinishedListener;
 import com.android.server.backup.internal.PerformBackupTask;
 import com.android.server.backup.testing.TransportData;
+import com.android.server.backup.testing.TransportTestUtils;
 import com.android.server.backup.testing.TransportTestUtils.TransportMock;
 import com.android.server.backup.transport.TransportClient;
 import com.android.server.testing.FrameworkRobolectricTestRunner;
@@ -80,6 +89,8 @@
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
@@ -88,6 +99,7 @@
 import org.robolectric.shadows.ShadowQueuedWork;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Stream;
@@ -124,31 +136,25 @@
     @Mock private IBackupManagerMonitor mMonitor;
     @Mock private OnTaskFinishedListener mListener;
     private TransportData mTransport;
-    private IBackupTransport mTransportBinder;
-    private TransportClient mTransportClient;
     private ShadowLooper mShadowBackupLooper;
     private BackupHandler mBackupHandler;
     private PowerManager.WakeLock mWakeLock;
     private ShadowPackageManager mShadowPackageManager;
     private FakeIBackupManager mBackupManager;
+    private File mBaseStateDir;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         mTransport = backupTransport();
-        TransportMock transportMock = setUpTransport(mTransportManager, mTransport);
-        mTransportBinder = transportMock.transport;
-        mTransportClient = transportMock.transportClient;
 
         Application application = RuntimeEnvironment.application;
         File cacheDir = application.getCacheDir();
-        File baseStateDir = new File(cacheDir, "base_state_dir");
+        mBaseStateDir = new File(cacheDir, "base_state_dir");
         File dataDir = new File(cacheDir, "data_dir");
-        File stateDir = new File(baseStateDir, mTransport.transportDirName);
-        assertThat(baseStateDir.mkdir()).isTrue();
+        assertThat(mBaseStateDir.mkdir()).isTrue();
         assertThat(dataDir.mkdir()).isTrue();
-        assertThat(stateDir.mkdir()).isTrue();
 
         PackageManager packageManager = application.getPackageManager();
         mShadowPackageManager = Shadow.extract(packageManager);
@@ -174,7 +180,7 @@
         when(mBackupManagerService.getWakelock()).thenReturn(mWakeLock);
         when(mBackupManagerService.getCurrentOpLock()).thenReturn(new Object());
         when(mBackupManagerService.getQueueLock()).thenReturn(new Object());
-        when(mBackupManagerService.getBaseStateDir()).thenReturn(baseStateDir);
+        when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir);
         when(mBackupManagerService.getDataDir()).thenReturn(dataDir);
         when(mBackupManagerService.getCurrentOperations()).thenReturn(new SparseArray<>());
         when(mBackupManagerService.getBackupHandler()).thenReturn(mBackupHandler);
@@ -184,36 +190,55 @@
 
     @Test
     public void testRunTask_whenTransportProvidesFlags_passesThemToTheAgent() throws Exception {
-        BackupAgent agent = setUpAgent(PACKAGE_1);
+        TransportMock transportMock = setUpTransport(mTransport);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
         int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
-        when(mTransportBinder.getTransportFlags()).thenReturn(flags);
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        when(transportMock.transport.getTransportFlags()).thenReturn(flags);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
 
         runTask(task);
 
-        verify(agent).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
+        verify(agentMock.agent)
+                .onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
     }
 
     @Test
     public void testRunTask_whenTransportDoesNotProvidesFlags() throws Exception {
-        BackupAgent agent = setUpAgent(PACKAGE_1);
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        TransportMock transportMock = setUpTransport(mTransport);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
 
         runTask(task);
 
-        verify(agent).onBackup(any(), argThat(dataOutputWithTransportFlags(0)), any());
+        verify(agentMock.agent).onBackup(any(), argThat(dataOutputWithTransportFlags(0)), any());
     }
 
     @Test
     public void testRunTask_whenTransportProvidesFlagsAndMultipleAgents_passesToAll()
             throws Exception {
-        List<BackupAgent> agents = setUpAgents(PACKAGE_1, PACKAGE_2);
-        BackupAgent agent1 = agents.get(0);
-        BackupAgent agent2 = agents.get(1);
+        TransportMock transportMock = setUpTransport(mTransport);
+        List<AgentMock> agentMocks = setUpAgents(PACKAGE_1, PACKAGE_2);
+        BackupAgent agent1 = agentMocks.get(0).agent;
+        BackupAgent agent2 = agentMocks.get(1).agent;
         int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
-        when(mTransportBinder.getTransportFlags()).thenReturn(flags);
+        when(transportMock.transport.getTransportFlags()).thenReturn(flags);
         PerformBackupTask task =
-                createPerformBackupTask(emptyList(), false, true, PACKAGE_1, PACKAGE_2);
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1,
+                        PACKAGE_2);
 
         runTask(task);
 
@@ -223,14 +248,267 @@
 
     @Test
     public void testRunTask_whenTransportChangeFlagsAfterTaskCreation() throws Exception {
-        BackupAgent agent = setUpAgent(PACKAGE_1);
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        TransportMock transportMock = setUpTransport(mTransport);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
         int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
-        when(mTransportBinder.getTransportFlags()).thenReturn(flags);
+        when(transportMock.transport.getTransportFlags()).thenReturn(flags);
 
         runTask(task);
 
-        verify(agent).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
+        verify(agentMock.agent)
+                .onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
+    }
+
+    @Test
+    public void testRunTask_callsListenerAndObserver() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        verify(mListener).onFinished(any());
+        verify(mObserver).backupFinished(eq(BackupManager.SUCCESS));
+    }
+
+    @Test
+    public void testRunTask_callsTransportPerformBackupWithAgentData() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        IBackupTransport transportBinder = transportMock.transport;
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
+        agentOnBackupDo(
+                agentMock.agent,
+                (oldState, dataOutput, newState) -> {
+                    writeData(dataOutput, "key1", "foo".getBytes());
+                    writeData(dataOutput, "key2", "bar".getBytes());
+                });
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+        // We need to verify at call time because the file is deleted right after
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .then(this::mockAndVerifyTransportPerformBackupData);
+
+        runTask(task);
+
+        // Already verified data in mockAndVerifyPerformBackupData
+        verify(transportBinder).performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
+    }
+
+    private int mockAndVerifyTransportPerformBackupData(InvocationOnMock invocation)
+            throws IOException {
+        ParcelFileDescriptor data = invocation.getArgument(1);
+
+        // Verifying that what we passed to the transport is what the agent wrote
+        BackupDataInput dataInput = new BackupDataInput(data.getFileDescriptor());
+
+        // "key1" => "foo"
+        assertThat(dataInput.readNextHeader()).isTrue();
+        assertThat(dataInput.getKey()).isEqualTo("key1");
+        int size1 = dataInput.getDataSize();
+        byte[] data1 = new byte[size1];
+        dataInput.readEntityData(data1, 0, size1);
+        assertThat(data1).isEqualTo("foo".getBytes());
+
+        // "key2" => "bar"
+        assertThat(dataInput.readNextHeader()).isTrue();
+        assertThat(dataInput.getKey()).isEqualTo("key2");
+        int size2 = dataInput.getDataSize();
+        byte[] data2 = new byte[size2];
+        dataInput.readEntityData(data2, 0, size2);
+        assertThat(data2).isEqualTo("bar".getBytes());
+
+        // No more
+        assertThat(dataInput.readNextHeader()).isFalse();
+
+        return BackupTransport.TRANSPORT_OK;
+    }
+
+    @Test
+    public void testRunTask_whenPerformBackupSucceeds_callsTransportFinishBackup()
+            throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        IBackupTransport transportBinder = transportMock.transport;
+        setUpAgent(PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_OK);
+
+        runTask(task);
+
+        verify(transportBinder).finishBackup();
+    }
+
+    @Test
+    public void testRunTask_whenProhibitedKey_failsAgent() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
+        agentOnBackupDo(
+                agentMock.agent,
+                (oldState, dataOutput, newState) -> {
+                    char prohibitedChar = 0xff00;
+                    writeData(dataOutput, prohibitedChar + "key", "foo".getBytes());
+                });
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        // TODO: Should it not call mListener.onFinished()? PerformBackupTask:891 return?
+        // verify(mListener).onFinished(any());
+        verify(mObserver).onResult(eq(PACKAGE_1), eq(BackupManager.ERROR_AGENT_FAILURE));
+        verify(agentMock.agentBinder).fail(any());
+    }
+
+    @Test
+    public void testRunTask_whenTransportUnavailable() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport.unavailable());
+        setUpAgent(PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        verify(mListener).onFinished(any());
+        // TODO: Should it be 2 times? (PBT.beginBackup() and PBT.finalizeBackup())
+        verify(mObserver, times(2)).backupFinished(eq(BackupManager.ERROR_TRANSPORT_ABORTED));
+    }
+
+    @Test
+    public void testRunTask_whenTransportRejectsPackage() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        when(transportMock.transport.performBackup(
+                        argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
+        verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+    }
+
+    @Test
+    public void testRunTask_whenTransportRejectsFirstPackageButLastSucceeds() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        IBackupTransport transportBinder = transportMock.transport;
+        setUpAgents(PACKAGE_1, PACKAGE_2);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_OK);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1,
+                        PACKAGE_2);
+
+        runTask(task);
+
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
+        verify(mObserver).onResult(PACKAGE_2, BackupManager.SUCCESS);
+        verify(mObserver).backupFinished(BackupManager.SUCCESS);
+    }
+
+    @Test
+    public void testRunTask_whenTransportRejectsLastPackageButFirstSucceeds() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        IBackupTransport transportBinder = transportMock.transport;
+        setUpAgents(PACKAGE_1, PACKAGE_2);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_OK);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1,
+                        PACKAGE_2);
+
+        runTask(task);
+
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.SUCCESS);
+        verify(mObserver).onResult(PACKAGE_2, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
+        // TODO: Should we return the status of the last?
+        verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+    }
+
+    @Test
+    public void testRunTask_whenTransportReturnsQuotaExceeded() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
+        when(transportMock.transport.performBackup(
+                        argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
+        verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+        verify(agentMock.agent).onQuotaExceeded(anyLong(), anyLong());
+    }
+
+    // TODO: Giving NPE at PerformBackupTask:524 because mCurrentPackage is null (PackageManager
+    // rightfully threw NameNotFoundException). Uncomment @Test when fixed.
+    // @Test
+    public void testRunTask_whenAgentUnknown() throws Exception {
+        // Not calling setUpAgent()
+        TransportMock transportMock = setUpTransport(mTransport);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        verify(transportMock.transport, never()).performBackup(any(), any(), anyInt());
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_PACKAGE_NOT_FOUND);
+        verify(mObserver).backupFinished(BackupManager.SUCCESS);
     }
 
     private void runTask(PerformBackupTask task) {
@@ -241,32 +519,48 @@
         }
     }
 
-    private List<BackupAgent> setUpAgents(String... packageNames) {
+    private TransportMock setUpTransport(TransportData transport) throws Exception {
+        TransportMock transportMock =
+                TransportTestUtils.setUpTransport(mTransportManager, transport);
+        File stateDir = new File(mBaseStateDir, transport.transportDirName);
+        assertThat(stateDir.mkdir()).isTrue();
+        return transportMock;
+    }
+
+    private List<AgentMock> setUpAgents(String... packageNames) {
         return Stream.of(packageNames).map(this::setUpAgent).collect(toList());
     }
 
-    private BackupAgent setUpAgent(String packageName) {
-        PackageInfo packageInfo = new PackageInfo();
-        packageInfo.packageName = packageName;
-        packageInfo.applicationInfo = new ApplicationInfo();
-        packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_ALLOW_BACKUP;
-        packageInfo.applicationInfo.backupAgentName = "BackupAgent" + packageName;
-        packageInfo.applicationInfo.packageName = packageName;
-        mShadowPackageManager.setApplicationEnabledSetting(
-                packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
-        mShadowPackageManager.addPackage(packageInfo);
-        BackupAgent backupAgent = spy(BackupAgent.class);
-        IBackupAgent backupAgentBinder = IBackupAgent.Stub.asInterface(backupAgent.onBind());
-        when(mBackupManagerService.bindToAgentSynchronous(
-                        eq(packageInfo.applicationInfo), anyInt()))
-                .thenReturn(backupAgentBinder);
-        return backupAgent;
+    private AgentMock setUpAgent(String packageName) {
+        try {
+            PackageInfo packageInfo = new PackageInfo();
+            packageInfo.packageName = packageName;
+            packageInfo.applicationInfo = new ApplicationInfo();
+            packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_ALLOW_BACKUP;
+            packageInfo.applicationInfo.backupAgentName = "BackupAgent" + packageName;
+            packageInfo.applicationInfo.packageName = packageName;
+            mShadowPackageManager.setApplicationEnabledSetting(
+                    packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+            mShadowPackageManager.addPackage(packageInfo);
+            BackupAgent backupAgent = spy(BackupAgent.class);
+            IBackupAgent backupAgentBinder =
+                    spy(IBackupAgent.Stub.asInterface(backupAgent.onBind()));
+            // Don't crash our only process (in production code this would crash the app, not us)
+            doNothing().when(backupAgentBinder).fail(any());
+            when(mBackupManagerService.bindToAgentSynchronous(
+                            eq(packageInfo.applicationInfo), anyInt()))
+                    .thenReturn(backupAgentBinder);
+            return new AgentMock(backupAgentBinder, backupAgent);
+        } catch (RemoteException e) {
+            // Never happens, compiler happy
+            throw new AssertionError(e);
+        }
     }
 
     private PerformBackupTask createPerformBackupTask(
+            TransportClient transportClient,
+            String transportDirName,
             List<String> pendingFullBackups,
-            boolean userInitiated,
-            boolean nonIncremental,
             String... packages) {
         ArrayList<BackupRequest> backupRequests =
                 Stream.of(packages).map(BackupRequest::new).collect(toCollection(ArrayList::new));
@@ -274,24 +568,75 @@
         PerformBackupTask task =
                 new PerformBackupTask(
                         mBackupManagerService,
-                        mTransportClient,
-                        mTransport.transportDirName,
+                        transportClient,
+                        transportDirName,
                         backupRequests,
                         mDataChangedJournal,
                         mObserver,
                         mMonitor,
                         mListener,
                         pendingFullBackups,
-                        userInitiated,
-                        nonIncremental);
+                        /* userInitiated */ false,
+                        /* nonIncremental */ true);
         mBackupManager.setUp(mBackupHandler, task);
         return task;
     }
 
-    private ArgumentMatcher<BackupDataOutput> dataOutputWithTransportFlags(int flags) {
+    private static ArgumentMatcher<PackageInfo> packageInfo(String packageName) {
+        // We have to test for packageInfo nulity because of Mockito's own stubbing with argThat().
+        // E.g. if you do:
+        //
+        //   1. when(object.method(argThat(str -> str.equals("foo")))).thenReturn(0)
+        //   2. when(object.method(argThat(str -> str.equals("bar")))).thenReturn(2)
+        //
+        // The second line will throw NPE because it will call lambda 1 with null, since argThat()
+        // returns null. So we guard against that by checking for null.
+        return packageInfo -> packageInfo != null && packageName.equals(packageInfo.packageName);
+    }
+
+    private static ArgumentMatcher<BackupDataOutput> dataOutputWithTransportFlags(int flags) {
         return dataOutput -> dataOutput.getTransportFlags() == flags;
     }
 
+    private static void writeData(BackupDataOutput dataOutput, String key, byte[] data)
+            throws IOException {
+        dataOutput.writeEntityHeader(key, data.length);
+        dataOutput.writeEntityData(data, data.length);
+    }
+
+    private static void agentOnBackupDo(BackupAgent agent, BackupAgentOnBackup function)
+            throws Exception {
+        doAnswer(function).when(agent).onBackup(any(), any(), any());
+    }
+
+    @FunctionalInterface
+    private interface BackupAgentOnBackup extends Answer<Void> {
+        void onBackup(
+                ParcelFileDescriptor oldState,
+                BackupDataOutput dataOutput,
+                ParcelFileDescriptor newState)
+                throws IOException;
+
+        @Override
+        default Void answer(InvocationOnMock invocation) throws Throwable {
+            onBackup(
+                    invocation.getArgument(0),
+                    invocation.getArgument(1),
+                    invocation.getArgument(2));
+            return null;
+        }
+    }
+
+    private static class AgentMock {
+        private final IBackupAgent agentBinder;
+        private final BackupAgent agent;
+
+        private AgentMock(IBackupAgent agentBinder, BackupAgent agent) {
+            this.agentBinder = agentBinder;
+            this.agent = agent;
+        }
+    }
+
     private abstract static class FakeIBackupManager extends IBackupManager.Stub {
         private Handler mBackupHandler;
         private BackupRestoreTask mTask;
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataInput.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataInput.java
index 28489af..8016a8b 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataInput.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataInput.java
@@ -21,41 +21,76 @@
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
+import java.io.EOFException;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.ObjectInputStream;
 
+/**
+ * Shadow for {@link BackupDataInput}. Format read does NOT match implementation. To write data to
+ * be read by this shadow, you should also declare shadow {@link ShadowBackupDataOutput}.
+ */
 @Implements(BackupDataInput.class)
 public class ShadowBackupDataInput {
-    @Implementation
-    public void __constructor__(FileDescriptor fd) {
-    }
+    private ObjectInputStream mInput;
+    private int mSize;
+    private String mKey;
+    private boolean mHeaderReady;
 
     @Implementation
-    protected void finalize() throws Throwable {
+    public void __constructor__(FileDescriptor fd) {
+        try {
+            mInput = new ObjectInputStream(new FileInputStream(fd));
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
     }
 
     @Implementation
     public boolean readNextHeader() throws IOException {
-        return false;
+        mHeaderReady = false;
+        try {
+            mSize = mInput.readInt();
+        } catch (EOFException e) {
+            return false;
+        }
+        mKey = mInput.readUTF();
+        mHeaderReady = true;
+        return true;
     }
 
     @Implementation
     public String getKey() {
-        throw new AssertionError("Can't call because readNextHeader() returned false");
+        checkHeaderReady();
+        return mKey;
     }
 
     @Implementation
     public int getDataSize() {
-        throw new AssertionError("Can't call because readNextHeader() returned false");
+        checkHeaderReady();
+        return mSize;
     }
 
     @Implementation
     public int readEntityData(byte[] data, int offset, int size) throws IOException {
-        throw new AssertionError("Can't call because readNextHeader() returned false");
+        checkHeaderReady();
+        int result = mInput.read(data, offset, size);
+        if (result < 0) {
+            throw new IOException("result=0x" + Integer.toHexString(result));
+        }
+        return result;
     }
 
     @Implementation
     public void skipEntityData() throws IOException {
-        throw new AssertionError("Can't call because readNextHeader() returned false");
+        checkHeaderReady();
+        mInput.read(new byte[mSize], 0, mSize);
+    }
+
+    private void checkHeaderReady() {
+        if (!mHeaderReady) {
+            throw new IllegalStateException("Entity header not read");
+        }
     }
 }
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
index c7deada..e78a4b3 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
@@ -21,16 +21,29 @@
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
+import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.ObjectOutputStream;
 
+/**
+ * Shadow for {@link BackupDataOutput}. Format written does NOT match implementation. To read data
+ * written with this shadow you should also declare shadow {@link ShadowBackupDataInput}.
+ */
 @Implements(BackupDataOutput.class)
 public class ShadowBackupDataOutput {
     private long mQuota;
     private int mTransportFlags;
+    private ObjectOutputStream mOutput;
 
     @Implementation
     public void __constructor__(FileDescriptor fd, long quota, int transportFlags) {
+        try {
+            mOutput = new ObjectOutputStream(new FileOutputStream(fd));
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
         mQuota = quota;
         mTransportFlags = transportFlags;
     }
@@ -47,11 +60,27 @@
 
     @Implementation
     public int writeEntityHeader(String key, int dataSize) throws IOException {
-        return 0;
+        final int size;
+        try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) {
+            writeEntityHeader(new ObjectOutputStream(byteStream), key, dataSize);
+            size = byteStream.size();
+        }
+        writeEntityHeader(mOutput, key, dataSize);
+        return size;
+    }
+
+    private void writeEntityHeader(ObjectOutputStream stream, String key, int dataSize)
+            throws IOException {
+        // Write the int first because readInt() throws EOFException, to know when stream ends
+        stream.writeInt(dataSize);
+        stream.writeUTF(key);
+        stream.flush();
     }
 
     @Implementation
     public int writeEntityData(byte[] data, int size) throws IOException {
-        return 0;
+        mOutput.write(data, 0, size);
+        mOutput.flush();
+        return size;
     }
 }
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-1-no-begin-end.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-1-no-begin-end.pem
new file mode 100644
index 0000000..b5d513c
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-1-no-begin-end.pem
@@ -0,0 +1,49 @@
+MIIJJzCCBQ6gAwIBAgIJAM7fBGeQ1wBkMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV
+BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAxMTEwNjQ5MzNaFw0zODAx
+MDYwNjQ5MzNaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCBCIw
+DQYJKoZIhvcNAQEBBQADggQPADCCBAoCggQBCcFv05M1seLPYIW7oFivh7u5otCt
+Mm7ryq0UjpbTQPcQxJQbYzcUQF7CbPYTdWDid4EuO8Zec03ownsduFhKud6H3yIQ
+4ueGiqCBoG1D6+N8fF9R8awTmAsbNg63VInx6IwcBZnjFlsIIftOFxqIJBYhiKhN
+JhPtF1i9dn+N5HjEKmkJO3pXhYhRXMp7OwL/epxzhBXFYT7aDg9pnaM6C+4hmhQ/
+0q2oyzYtAqFmrEenbtI6G47SzMc+shNTuYLtq21j/Z3uA3RwB9Szfu99F66tlgTX
+v7K7YS573hN3TQY/+nkLfFy/oF2LQRYvKHF+Nv0BHzQLzqDEYBaILcMf3i2Ce/b7
+wZjitLqFAI1swqGzgH/QpB3OrX51M/B7UCF2nB7Pa8knu4kBDGkz2Q41jAL0W/qt
+j43VwJDW0Y98OuqQiCqJrTrGdv7b/phnVVBvFrtIjYMfyK34jy5VLXctV5CSkWj5
+3ul3mvGFHJD+6nneDR4PUkmYN0khT4t/RqnQlwYE0a6Erq1+Rof6/DoWSzeBLBYV
+JaHhRy9mrudR/VcQynLKty6Zst4Lyh6aPMHcpTwGZbG+4mXnWeTaLEnGvivldksT
+XOxipcO/fXJfDss4b0glGzP3GD0+H5EZB9coYzNT47QZd9drxHdrLxtPoi+MeqkG
+gCdyFyBZO8G2k/JuyziT6hy+50VXJnl6Ujxj7MVUYAsISHsHgqETDsukQbbKvTKg
+3gxPVNN/vKWwyh7KLcFIaOEoPOgStkmVsqrXm7YLE6Bvzm8nu4rwJeAF9Yseg9BE
+Y86TRRmAI7fW4eDEPnxgCUUvcYSAh5mcayIyIr0KTuXkevwYbVRHMVmy9DaqzsP8
+YFXIqFvDXRCFSy/gMkoNb9ZoqdkmjZ+VBsjAKI+u/Haf6pgdpGZbVGKEFmaVHCkr
+tPp/gy4kE4qmd/SIaccG8o6Eb9X9fbqTTDZv34kcGgxOvBJVIaNHprTjgvYEnRaD
+KTlmZoCUmBlHzvbf68YWBmIz0K8vYPdx9r98LiUgpbTHtKZIYrJnbgPnbC9icP24
+2ksB4yaTx1QWc14vTNv1lUtv4zJEmaaoynNlETJFf/Tz0QKJxtT+l/BIAz8kEJMA
+cKsfoTx9OTtfuL85pXbCgxbKKmKn6RzxUCzSzgMboC0z6W8Zxy2gLIhqMm8AXAF7
+salwrRirV4lWsM9MOhVEgfjcv/qmQSYr1ARrwwegHRqxPA3qh11kfq5YSFU7W7+f
+JrWH6VuLZ0B1fj2+lsoMNekFA1ULD8DK7aAFIh9Y1y4Jt//xMuOPcD5PWNGFmUk7
+oPewiIUMLjXSWcgrQVYbZEDW/vooMJoo47Vg1fQPehejbONE1nBIaeRVhJcCAwEA
+AaNjMGEwHQYDVR0OBBYEFNd7oYeSi7hSGimRpTZaHLQy6+zRMB8GA1UdIwQYMBaA
+FNd7oYeSi7hSGimRpTZaHLQy6+zRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgGGMA0GCSqGSIb3DQEBDQUAA4IEAgABny011veuPplTcNeyLeKhWRn/y9VM
+QEyhaLlsC1Di35WN8owjj4+gugLlDdtEc/pvzgk+ZkAuplQkrsU907dvwkDPb4rW
+ZB5hjbr9yVyEHK1bHh7RSUkJrB3NRwqH1lyWz/LfaVfbV4CtaaERhThzZCp/MweO
+Tivg2XpSluy5s8lEEbMC/dGuIsBMitX3XLlbYa2ND3aHZLo6X9yQMFfTCjgwYG2n
+eDYupnvcLINlrlJYcrYSrIvoQn9XfsnjU3AXz+jc6xLrO3EtXDhi9e+QTfcnvRsg
+l/Hj9SZr1w1L1PPJo+KjsRavVvzaHXlBAvvUtEojJrkR3j+b5zvQB6dgVrM0zUhM
+Q9zRp5R/xqHeZ/0TTQe9kEa8QuRzuRIkK5Wbh76Eix3S+2uTsbj462nk4E0oPR8p
+iYopS4ZEFEfrKW14HOph9ZscI4l/HfDmTNfgpyFl62UrvzVBnoz+sbhTgbPHPcCX
+OUrhmpz9I5oBkyEAZYunSvzY/9SXUsz6psXHJmVzLQcne/YQTtpWzV/wGD7cjjDl
+bfzsmGCfZ8jqPBoicl5IUVdyZsJgufEZHXxKZQ7wL7R6jKrj/GtCDey1Wr2QT8VX
+5JTk9cJQFjgjDWaAyCBpGEaQvYJcaOxk2D+Wap5ax8nUfW/99vVFA0EJKsSVVzw7
+daRty0UpfZsx2Sfzpg0mymmgB8+NY6t68dL5C/xxAv5mEQ8wGJmP45iQpo5T6LVV
+MrktLf5eIzxlALQIW/AgpSH9JKCqpItdxfisAIIs9e8XHbVJJA0Jde7rtAj+TUY0
+h00xSqyfSSbpcDJ9lIoSZOJvFQdWOxB8c3vZZGGhMuRFm06sUHvcHjo8KwnbqyOx
+DGjeqt6YWty6WcNin0WciR33vGHIzwVNxNnmuY308bNsMvY9jsmd37hdmmwnmQge
+7AIa7TMPjaKm0vV/1ztFSODWCI2K7klmL2MtOJMGfqUeOfjPANbS3lMJBAH9qxLM
+7Kng+nfqVtt+NG9MxcTbP80FkBa/6JxGgjjsiwDmhr2MTCYOK/eD+WZikMOieyvH
+m2vgxYCdWrhaGfc3t6oQ2YO+mXI7e6d3F3a90UUYkBIgje9zu0RLxnBBhuoRyGwv
+uQAlqgMDBZIzTO0Vnwew7KRLdzLhWbiikhi81q6Lg62aWjbdF6Ue6AVXch+dqmr+
+9aVt0Y6ETTS77nrQyglyLKIeNx6cEHDjETXlPYGbCAlrdKAdTA4ngnBZnzGQ/8zg
+tP9zvIJVA6cuOAn8GFEsrb7GN20QSDwyJWrYi6f+m64D9rOK4Jz4t+lEfjcfJeM/
+UcNlhmATcMHXWPCoKkOfll4PBc/Wigv1xYw70RZ4pai07LzJxNHYhvpE3Q==
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-2-empty-block.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-2-empty-block.pem
new file mode 100644
index 0000000..c412709
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-2-empty-block.pem
@@ -0,0 +1,2 @@
+-----BEGIN CERTIFICATE-----
+-----END CERTIFICATE-----
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-3-invalid-key.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-3-invalid-key.pem
new file mode 100644
index 0000000..9137b16
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/invalid-cert-3-invalid-key.pem
@@ -0,0 +1,50 @@
+-----BEGIN CERTIFICATE-----
+BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAxMTEwNjQ5MzNaFw0zODAx
+MDYwNjQ5MzNaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCBCIw
+DQYJKoZIhvcNAQEBBQADggQPADCCBAoCggQBCcFv05M1seLPYIW7oFivh7u5otCt
+Mm7ryq0UjpbTQPcQxJQbYzcUQF7CbPYTdWDid4EuO8Zec03ownsduFhKud6H3yIQ
+4ueGiqCBoG1D6+N8fF9R8awTmAsbNg63VInx6IwcBZnjFlsIIftOFxqIJBYhiKhN
+JhPtF1i9dn+N5HjEKmkJO3pXhYhRXMp7OwL/epxzhBXFYT7aDg9pnaM6C+4hmhQ/
+0q2oyzYtAqFmrEenbtI6G47SzMc+shNTuYLtq21j/Z3uA3RwB9Szfu99F66tlgTX
+v7K7YS573hN3TQY/+nkLfFy/oF2LQRYvKHF+Nv0BHzQLzqDEYBaILcMf3i2Ce/b7
+wZjitLqFAI1swqGzgH/QpB3OrX51M/B7UCF2nB7Pa8knu4kBDGkz2Q41jAL0W/qt
+j43VwJDW0Y98OuqQiCqJrTrGdv7b/phnVVBvFrtIjYMfyK34jy5VLXctV5CSkWj5
+3ul3mvGFHJD+6nneDR4PUkmYN0khT4t/RqnQlwYE0a6Erq1+Rof6/DoWSzeBLBYV
+JaHhRy9mrudR/VcQynLKty6Zst4Lyh6aPMHcpTwGZbG+4mXnWeTaLEnGvivldksT
+XOxipcO/fXJfDss4b0glGzP3GD0+H5EZB9coYzNT47QZd9drxHdrLxtPoi+MeqkG
+gCdyFyBZO8G2k/JuyziT6hy+50VXJnl6Ujxj7MVUYAsISHsHgqETDsukQbbKvTKg
+3gxPVNN/vKWwyh7KLcFIaOEoPOgStkmVsqrXm7YLE6Bvzm8nu4rwJeAF9Yseg9BE
+Y86TRRmAI7fW4eDEPnxgCUUvcYSAh5mcayIyIr0KTuXkevwYbVRHMVmy9DaqzsP8
+YFXIqFvDXRCFSy/gMkoNb9ZoqdkmjZ+VBsjAKI+u/Haf6pgdpGZbVGKEFmaVHCkr
+tPp/gy4kE4qmd/SIaccG8o6Eb9X9fbqTTDZv34kcGgxOvBJVIaNHprTjgvYEnRaD
+KTlmZoCUmBlHzvbf68YWBmIz0K8vYPdx9r98LiUgpbTHtKZIYrJnbgPnbC9icP24
+2ksB4yaTx1QWc14vTNv1lUtv4zJEmaaoynNlETJFf/Tz0QKJxtT+l/BIAz8kEJMA
+cKsfoTx9OTtfuL85pXbCgxbKKmKn6RzxUCzSzgMboC0z6W8Zxy2gLIhqMm8AXAF7
+salwrRirV4lWsM9MOhVEgfjcv/qmQSYr1ARrwwegHRqxPA3qh11kfq5YSFU7W7+f
+JrWH6VuLZ0B1fj2+lsoMNekFA1ULD8DK7aAFIh9Y1y4Jt//xMuOPcD5PWNGFmUk7
+oPewiIUMLjXSWcgrQVYbZEDW/vooMJoo47Vg1fQPehejbONE1nBIaeRVhJcCAwEA
+AaNjMGEwHQYDVR0OBBYEFNd7oYeSi7hSGimRpTZaHLQy6+zRMB8GA1UdIwQYMBaA
+FNd7oYeSi7hSGimRpTZaHLQy6+zRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgGGMA0GCSqGSIb3DQEBDQUAA4IEAgABny011veuPplTcNeyLeKhWRn/y9VM
+QEyhaLlsC1Di35WN8owjj4+gugLlDdtEc/pvzgk+ZkAuplQkrsU907dvwkDPb4rW
+ZB5hjbr9yVyEHK1bHh7RSUkJrB3NRwqH1lyWz/LfaVfbV4CtaaERhThzZCp/MweO
+Tivg2XpSluy5s8lEEbMC/dGuIsBMitX3XLlbYa2ND3aHZLo6X9yQMFfTCjgwYG2n
+eDYupnvcLINlrlJYcrYSrIvoQn9XfsnjU3AXz+jc6xLrO3EtXDhi9e+QTfcnvRsg
+l/Hj9SZr1w1L1PPJo+KjsRavVvzaHXlBAvvUtEojJrkR3j+b5zvQB6dgVrM0zUhM
+Q9zRp5R/xqHeZ/0TTQe9kEa8QuRzuRIkK5Wbh76Eix3S+2uTsbj462nk4E0oPR8p
+iYopS4ZEFEfrKW14HOph9ZscI4l/HfDmTNfgpyFl62UrvzVBnoz+sbhTgbPHPcCX
+OUrhmpz9I5oBkyEAZYunSvzY/9SXUsz6psXHJmVzLQcne/YQTtpWzV/wGD7cjjDl
+bfzsmGCfZ8jqPBoicl5IUVdyZsJgufEZHXxKZQ7wL7R6jKrj/GtCDey1Wr2QT8VX
+5JTk9cJQFjgjDWaAyCBpGEaQvYJcaOxk2D+Wap5ax8nUfW/99vVFA0EJKsSVVzw7
+daRty0UpfZsx2Sfzpg0mymmgB8+NY6t68dL5C/xxAv5mEQ8wGJmP45iQpo5T6LVV
+MrktLf5eIzxlALQIW/AgpSH9JKCqpItdxfisAIIs9e8XHbVJJA0Jde7rtAj+TUY0
+h00xSqyfSSbpcDJ9lIoSZOJvFQdWOxB8c3vZZGGhMuRFm06sUHvcHjo8KwnbqyOx
+DGjeqt6YWty6WcNin0WciR33vGHIzwVNxNnmuY308bNsMvY9jsmd37hdmmwnmQge
+7AIa7TMPjaKm0vV/1ztFSODWCI2K7klmL2MtOJMGfqUeOfjPANbS3lMJBAH9qxLM
+7Kng+nfqVtt+NG9MxcTbP80FkBa/6JxGgjjsiwDmhr2MTCYOK/eD+WZikMOieyvH
+m2vgxYCdWrhaGfc3t6oQ2YO+mXI7e6d3F3a90UUYkBIgje9zu0RLxnBBhuoRyGwv
+uQAlqgMDBZIzTO0Vnwew7KRLdzLhWbiikhi81q6Lg62aWjbdF6Ue6AVXch+dqmr+
+9aVt0Y6ETTS77nrQyglyLKIeNx6cEHDjETXlPYGbCAlrdKAdTA4ngnBZnzGQ/8zg
+tP9zvIJVA6cuOAn8GFEsrb7GN20QSDwyJWrYi6f+m64D9rOK4Jz4t+lEfjcfJeM/
+UcNlhmATcMHXWPCoKkOfll4PBc/Wigv1xYw70RZ4pai07LzJxNHYhvpE3Q==
+-----END CERTIFICATE-----
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert-multiple-blocks.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert-multiple-blocks.pem
new file mode 100644
index 0000000..e3abeaa
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert-multiple-blocks.pem
@@ -0,0 +1,70 @@
+-----BEGIN CERTIFICATE-----
+MIIJJzCCBQ6gAwIBAgIJAM7fBGeQ1wBkMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV
+BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAxMTEwNjQ5MzNaFw0zODAx
+MDYwNjQ5MzNaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCBCIw
+DQYJKoZIhvcNAQEBBQADggQPADCCBAoCggQBCcFv05M1seLPYIW7oFivh7u5otCt
+Mm7ryq0UjpbTQPcQxJQbYzcUQF7CbPYTdWDid4EuO8Zec03ownsduFhKud6H3yIQ
+4ueGiqCBoG1D6+N8fF9R8awTmAsbNg63VInx6IwcBZnjFlsIIftOFxqIJBYhiKhN
+JhPtF1i9dn+N5HjEKmkJO3pXhYhRXMp7OwL/epxzhBXFYT7aDg9pnaM6C+4hmhQ/
+0q2oyzYtAqFmrEenbtI6G47SzMc+shNTuYLtq21j/Z3uA3RwB9Szfu99F66tlgTX
+v7K7YS573hN3TQY/+nkLfFy/oF2LQRYvKHF+Nv0BHzQLzqDEYBaILcMf3i2Ce/b7
+wZjitLqFAI1swqGzgH/QpB3OrX51M/B7UCF2nB7Pa8knu4kBDGkz2Q41jAL0W/qt
+j43VwJDW0Y98OuqQiCqJrTrGdv7b/phnVVBvFrtIjYMfyK34jy5VLXctV5CSkWj5
+3ul3mvGFHJD+6nneDR4PUkmYN0khT4t/RqnQlwYE0a6Erq1+Rof6/DoWSzeBLBYV
+JaHhRy9mrudR/VcQynLKty6Zst4Lyh6aPMHcpTwGZbG+4mXnWeTaLEnGvivldksT
+XOxipcO/fXJfDss4b0glGzP3GD0+H5EZB9coYzNT47QZd9drxHdrLxtPoi+MeqkG
+gCdyFyBZO8G2k/JuyziT6hy+50VXJnl6Ujxj7MVUYAsISHsHgqETDsukQbbKvTKg
+3gxPVNN/vKWwyh7KLcFIaOEoPOgStkmVsqrXm7YLE6Bvzm8nu4rwJeAF9Yseg9BE
+Y86TRRmAI7fW4eDEPnxgCUUvcYSAh5mcayIyIr0KTuXkevwYbVRHMVmy9DaqzsP8
+YFXIqFvDXRCFSy/gMkoNb9ZoqdkmjZ+VBsjAKI+u/Haf6pgdpGZbVGKEFmaVHCkr
+tPp/gy4kE4qmd/SIaccG8o6Eb9X9fbqTTDZv34kcGgxOvBJVIaNHprTjgvYEnRaD
+KTlmZoCUmBlHzvbf68YWBmIz0K8vYPdx9r98LiUgpbTHtKZIYrJnbgPnbC9icP24
+2ksB4yaTx1QWc14vTNv1lUtv4zJEmaaoynNlETJFf/Tz0QKJxtT+l/BIAz8kEJMA
+cKsfoTx9OTtfuL85pXbCgxbKKmKn6RzxUCzSzgMboC0z6W8Zxy2gLIhqMm8AXAF7
+salwrRirV4lWsM9MOhVEgfjcv/qmQSYr1ARrwwegHRqxPA3qh11kfq5YSFU7W7+f
+JrWH6VuLZ0B1fj2+lsoMNekFA1ULD8DK7aAFIh9Y1y4Jt//xMuOPcD5PWNGFmUk7
+oPewiIUMLjXSWcgrQVYbZEDW/vooMJoo47Vg1fQPehejbONE1nBIaeRVhJcCAwEA
+AaNjMGEwHQYDVR0OBBYEFNd7oYeSi7hSGimRpTZaHLQy6+zRMB8GA1UdIwQYMBaA
+FNd7oYeSi7hSGimRpTZaHLQy6+zRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgGGMA0GCSqGSIb3DQEBDQUAA4IEAgABny011veuPplTcNeyLeKhWRn/y9VM
+QEyhaLlsC1Di35WN8owjj4+gugLlDdtEc/pvzgk+ZkAuplQkrsU907dvwkDPb4rW
+ZB5hjbr9yVyEHK1bHh7RSUkJrB3NRwqH1lyWz/LfaVfbV4CtaaERhThzZCp/MweO
+Tivg2XpSluy5s8lEEbMC/dGuIsBMitX3XLlbYa2ND3aHZLo6X9yQMFfTCjgwYG2n
+eDYupnvcLINlrlJYcrYSrIvoQn9XfsnjU3AXz+jc6xLrO3EtXDhi9e+QTfcnvRsg
+l/Hj9SZr1w1L1PPJo+KjsRavVvzaHXlBAvvUtEojJrkR3j+b5zvQB6dgVrM0zUhM
+Q9zRp5R/xqHeZ/0TTQe9kEa8QuRzuRIkK5Wbh76Eix3S+2uTsbj462nk4E0oPR8p
+iYopS4ZEFEfrKW14HOph9ZscI4l/HfDmTNfgpyFl62UrvzVBnoz+sbhTgbPHPcCX
+OUrhmpz9I5oBkyEAZYunSvzY/9SXUsz6psXHJmVzLQcne/YQTtpWzV/wGD7cjjDl
+bfzsmGCfZ8jqPBoicl5IUVdyZsJgufEZHXxKZQ7wL7R6jKrj/GtCDey1Wr2QT8VX
+5JTk9cJQFjgjDWaAyCBpGEaQvYJcaOxk2D+Wap5ax8nUfW/99vVFA0EJKsSVVzw7
+daRty0UpfZsx2Sfzpg0mymmgB8+NY6t68dL5C/xxAv5mEQ8wGJmP45iQpo5T6LVV
+MrktLf5eIzxlALQIW/AgpSH9JKCqpItdxfisAIIs9e8XHbVJJA0Jde7rtAj+TUY0
+h00xSqyfSSbpcDJ9lIoSZOJvFQdWOxB8c3vZZGGhMuRFm06sUHvcHjo8KwnbqyOx
+DGjeqt6YWty6WcNin0WciR33vGHIzwVNxNnmuY308bNsMvY9jsmd37hdmmwnmQge
+7AIa7TMPjaKm0vV/1ztFSODWCI2K7klmL2MtOJMGfqUeOfjPANbS3lMJBAH9qxLM
+7Kng+nfqVtt+NG9MxcTbP80FkBa/6JxGgjjsiwDmhr2MTCYOK/eD+WZikMOieyvH
+m2vgxYCdWrhaGfc3t6oQ2YO+mXI7e6d3F3a90UUYkBIgje9zu0RLxnBBhuoRyGwv
+uQAlqgMDBZIzTO0Vnwew7KRLdzLhWbiikhi81q6Lg62aWjbdF6Ue6AVXch+dqmr+
+9aVt0Y6ETTS77nrQyglyLKIeNx6cEHDjETXlPYGbCAlrdKAdTA4ngnBZnzGQ/8zg
+tP9zvIJVA6cuOAn8GFEsrb7GN20QSDwyJWrYi6f+m64D9rOK4Jz4t+lEfjcfJeM/
+UcNlhmATcMHXWPCoKkOfll4PBc/Wigv1xYw70RZ4pai07LzJxNHYhvpE3Q==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+BuwwuQxvQDF4pmQd
+-----END CERTIFICATE-----
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert.pem b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert.pem
new file mode 100644
index 0000000..5c16a1f
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/pem/valid-cert.pem
@@ -0,0 +1,204 @@
+-----BEGIN CERTIFICATE-----
+MIIJJzCCBQ6gAwIBAgIJAM7fBGeQ1wBkMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV
+BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAxMTEwNjQ5MzNaFw0zODAx
+MDYwNjQ5MzNaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCBCIw
+DQYJKoZIhvcNAQEBBQADggQPADCCBAoCggQBCcFv05M1seLPYIW7oFivh7u5otCt
+Mm7ryq0UjpbTQPcQxJQbYzcUQF7CbPYTdWDid4EuO8Zec03ownsduFhKud6H3yIQ
+4ueGiqCBoG1D6+N8fF9R8awTmAsbNg63VInx6IwcBZnjFlsIIftOFxqIJBYhiKhN
+JhPtF1i9dn+N5HjEKmkJO3pXhYhRXMp7OwL/epxzhBXFYT7aDg9pnaM6C+4hmhQ/
+0q2oyzYtAqFmrEenbtI6G47SzMc+shNTuYLtq21j/Z3uA3RwB9Szfu99F66tlgTX
+v7K7YS573hN3TQY/+nkLfFy/oF2LQRYvKHF+Nv0BHzQLzqDEYBaILcMf3i2Ce/b7
+wZjitLqFAI1swqGzgH/QpB3OrX51M/B7UCF2nB7Pa8knu4kBDGkz2Q41jAL0W/qt
+j43VwJDW0Y98OuqQiCqJrTrGdv7b/phnVVBvFrtIjYMfyK34jy5VLXctV5CSkWj5
+3ul3mvGFHJD+6nneDR4PUkmYN0khT4t/RqnQlwYE0a6Erq1+Rof6/DoWSzeBLBYV
+JaHhRy9mrudR/VcQynLKty6Zst4Lyh6aPMHcpTwGZbG+4mXnWeTaLEnGvivldksT
+XOxipcO/fXJfDss4b0glGzP3GD0+H5EZB9coYzNT47QZd9drxHdrLxtPoi+MeqkG
+gCdyFyBZO8G2k/JuyziT6hy+50VXJnl6Ujxj7MVUYAsISHsHgqETDsukQbbKvTKg
+3gxPVNN/vKWwyh7KLcFIaOEoPOgStkmVsqrXm7YLE6Bvzm8nu4rwJeAF9Yseg9BE
+Y86TRRmAI7fW4eDEPnxgCUUvcYSAh5mcayIyIr0KTuXkevwYbVRHMVmy9DaqzsP8
+YFXIqFvDXRCFSy/gMkoNb9ZoqdkmjZ+VBsjAKI+u/Haf6pgdpGZbVGKEFmaVHCkr
+tPp/gy4kE4qmd/SIaccG8o6Eb9X9fbqTTDZv34kcGgxOvBJVIaNHprTjgvYEnRaD
+KTlmZoCUmBlHzvbf68YWBmIz0K8vYPdx9r98LiUgpbTHtKZIYrJnbgPnbC9icP24
+2ksB4yaTx1QWc14vTNv1lUtv4zJEmaaoynNlETJFf/Tz0QKJxtT+l/BIAz8kEJMA
+cKsfoTx9OTtfuL85pXbCgxbKKmKn6RzxUCzSzgMboC0z6W8Zxy2gLIhqMm8AXAF7
+salwrRirV4lWsM9MOhVEgfjcv/qmQSYr1ARrwwegHRqxPA3qh11kfq5YSFU7W7+f
+JrWH6VuLZ0B1fj2+lsoMNekFA1ULD8DK7aAFIh9Y1y4Jt//xMuOPcD5PWNGFmUk7
+oPewiIUMLjXSWcgrQVYbZEDW/vooMJoo47Vg1fQPehejbONE1nBIaeRVhJcCAwEA
+AaNjMGEwHQYDVR0OBBYEFNd7oYeSi7hSGimRpTZaHLQy6+zRMB8GA1UdIwQYMBaA
+FNd7oYeSi7hSGimRpTZaHLQy6+zRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgGGMA0GCSqGSIb3DQEBDQUAA4IEAgABny011veuPplTcNeyLeKhWRn/y9VM
+QEyhaLlsC1Di35WN8owjj4+gugLlDdtEc/pvzgk+ZkAuplQkrsU907dvwkDPb4rW
+ZB5hjbr9yVyEHK1bHh7RSUkJrB3NRwqH1lyWz/LfaVfbV4CtaaERhThzZCp/MweO
+Tivg2XpSluy5s8lEEbMC/dGuIsBMitX3XLlbYa2ND3aHZLo6X9yQMFfTCjgwYG2n
+eDYupnvcLINlrlJYcrYSrIvoQn9XfsnjU3AXz+jc6xLrO3EtXDhi9e+QTfcnvRsg
+l/Hj9SZr1w1L1PPJo+KjsRavVvzaHXlBAvvUtEojJrkR3j+b5zvQB6dgVrM0zUhM
+Q9zRp5R/xqHeZ/0TTQe9kEa8QuRzuRIkK5Wbh76Eix3S+2uTsbj462nk4E0oPR8p
+iYopS4ZEFEfrKW14HOph9ZscI4l/HfDmTNfgpyFl62UrvzVBnoz+sbhTgbPHPcCX
+OUrhmpz9I5oBkyEAZYunSvzY/9SXUsz6psXHJmVzLQcne/YQTtpWzV/wGD7cjjDl
+bfzsmGCfZ8jqPBoicl5IUVdyZsJgufEZHXxKZQ7wL7R6jKrj/GtCDey1Wr2QT8VX
+5JTk9cJQFjgjDWaAyCBpGEaQvYJcaOxk2D+Wap5ax8nUfW/99vVFA0EJKsSVVzw7
+daRty0UpfZsx2Sfzpg0mymmgB8+NY6t68dL5C/xxAv5mEQ8wGJmP45iQpo5T6LVV
+MrktLf5eIzxlALQIW/AgpSH9JKCqpItdxfisAIIs9e8XHbVJJA0Jde7rtAj+TUY0
+h00xSqyfSSbpcDJ9lIoSZOJvFQdWOxB8c3vZZGGhMuRFm06sUHvcHjo8KwnbqyOx
+DGjeqt6YWty6WcNin0WciR33vGHIzwVNxNnmuY308bNsMvY9jsmd37hdmmwnmQge
+7AIa7TMPjaKm0vV/1ztFSODWCI2K7klmL2MtOJMGfqUeOfjPANbS3lMJBAH9qxLM
+7Kng+nfqVtt+NG9MxcTbP80FkBa/6JxGgjjsiwDmhr2MTCYOK/eD+WZikMOieyvH
+m2vgxYCdWrhaGfc3t6oQ2YO+mXI7e6d3F3a90UUYkBIgje9zu0RLxnBBhuoRyGwv
+uQAlqgMDBZIzTO0Vnwew7KRLdzLhWbiikhi81q6Lg62aWjbdF6Ue6AVXch+dqmr+
+9aVt0Y6ETTS77nrQyglyLKIeNx6cEHDjETXlPYGbCAlrdKAdTA4ngnBZnzGQ/8zg
+tP9zvIJVA6cuOAn8GFEsrb7GN20QSDwyJWrYi6f+m64D9rOK4Jz4t+lEfjcfJeM/
+UcNlhmATcMHXWPCoKkOfll4PBc/Wigv1xYw70RZ4pai07LzJxNHYhvpE3Q==
+-----END CERTIFICATE-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            ce:df:04:67:90:d7:00:64
+    Signature Algorithm: sha512WithRSAEncryption
+        Issuer: CN = Google CryptAuthVault
+        Validity
+            Not Before: Jan 11 06:49:33 2018 GMT
+            Not After : Jan  6 06:49:33 2038 GMT
+        Subject: CN = Google CryptAuthVault
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (8196 bit)
+                Modulus:
+                    09:c1:6f:d3:93:35:b1:e2:cf:60:85:bb:a0:58:af:
+                    87:bb:b9:a2:d0:ad:32:6e:eb:ca:ad:14:8e:96:d3:
+                    40:f7:10:c4:94:1b:63:37:14:40:5e:c2:6c:f6:13:
+                    75:60:e2:77:81:2e:3b:c6:5e:73:4d:e8:c2:7b:1d:
+                    b8:58:4a:b9:de:87:df:22:10:e2:e7:86:8a:a0:81:
+                    a0:6d:43:eb:e3:7c:7c:5f:51:f1:ac:13:98:0b:1b:
+                    36:0e:b7:54:89:f1:e8:8c:1c:05:99:e3:16:5b:08:
+                    21:fb:4e:17:1a:88:24:16:21:88:a8:4d:26:13:ed:
+                    17:58:bd:76:7f:8d:e4:78:c4:2a:69:09:3b:7a:57:
+                    85:88:51:5c:ca:7b:3b:02:ff:7a:9c:73:84:15:c5:
+                    61:3e:da:0e:0f:69:9d:a3:3a:0b:ee:21:9a:14:3f:
+                    d2:ad:a8:cb:36:2d:02:a1:66:ac:47:a7:6e:d2:3a:
+                    1b:8e:d2:cc:c7:3e:b2:13:53:b9:82:ed:ab:6d:63:
+                    fd:9d:ee:03:74:70:07:d4:b3:7e:ef:7d:17:ae:ad:
+                    96:04:d7:bf:b2:bb:61:2e:7b:de:13:77:4d:06:3f:
+                    fa:79:0b:7c:5c:bf:a0:5d:8b:41:16:2f:28:71:7e:
+                    36:fd:01:1f:34:0b:ce:a0:c4:60:16:88:2d:c3:1f:
+                    de:2d:82:7b:f6:fb:c1:98:e2:b4:ba:85:00:8d:6c:
+                    c2:a1:b3:80:7f:d0:a4:1d:ce:ad:7e:75:33:f0:7b:
+                    50:21:76:9c:1e:cf:6b:c9:27:bb:89:01:0c:69:33:
+                    d9:0e:35:8c:02:f4:5b:fa:ad:8f:8d:d5:c0:90:d6:
+                    d1:8f:7c:3a:ea:90:88:2a:89:ad:3a:c6:76:fe:db:
+                    fe:98:67:55:50:6f:16:bb:48:8d:83:1f:c8:ad:f8:
+                    8f:2e:55:2d:77:2d:57:90:92:91:68:f9:de:e9:77:
+                    9a:f1:85:1c:90:fe:ea:79:de:0d:1e:0f:52:49:98:
+                    37:49:21:4f:8b:7f:46:a9:d0:97:06:04:d1:ae:84:
+                    ae:ad:7e:46:87:fa:fc:3a:16:4b:37:81:2c:16:15:
+                    25:a1:e1:47:2f:66:ae:e7:51:fd:57:10:ca:72:ca:
+                    b7:2e:99:b2:de:0b:ca:1e:9a:3c:c1:dc:a5:3c:06:
+                    65:b1:be:e2:65:e7:59:e4:da:2c:49:c6:be:2b:e5:
+                    76:4b:13:5c:ec:62:a5:c3:bf:7d:72:5f:0e:cb:38:
+                    6f:48:25:1b:33:f7:18:3d:3e:1f:91:19:07:d7:28:
+                    63:33:53:e3:b4:19:77:d7:6b:c4:77:6b:2f:1b:4f:
+                    a2:2f:8c:7a:a9:06:80:27:72:17:20:59:3b:c1:b6:
+                    93:f2:6e:cb:38:93:ea:1c:be:e7:45:57:26:79:7a:
+                    52:3c:63:ec:c5:54:60:0b:08:48:7b:07:82:a1:13:
+                    0e:cb:a4:41:b6:ca:bd:32:a0:de:0c:4f:54:d3:7f:
+                    bc:a5:b0:ca:1e:ca:2d:c1:48:68:e1:28:3c:e8:12:
+                    b6:49:95:b2:aa:d7:9b:b6:0b:13:a0:6f:ce:6f:27:
+                    bb:8a:f0:25:e0:05:f5:8b:1e:83:d0:44:63:ce:93:
+                    45:19:80:23:b7:d6:e1:e0:c4:3e:7c:60:09:45:2f:
+                    71:84:80:87:99:9c:6b:22:32:22:bd:0a:4e:e5:e4:
+                    7a:fc:18:6d:54:47:31:59:b2:f4:36:aa:ce:c3:fc:
+                    60:55:c8:a8:5b:c3:5d:10:85:4b:2f:e0:32:4a:0d:
+                    6f:d6:68:a9:d9:26:8d:9f:95:06:c8:c0:28:8f:ae:
+                    fc:76:9f:ea:98:1d:a4:66:5b:54:62:84:16:66:95:
+                    1c:29:2b:b4:fa:7f:83:2e:24:13:8a:a6:77:f4:88:
+                    69:c7:06:f2:8e:84:6f:d5:fd:7d:ba:93:4c:36:6f:
+                    df:89:1c:1a:0c:4e:bc:12:55:21:a3:47:a6:b4:e3:
+                    82:f6:04:9d:16:83:29:39:66:66:80:94:98:19:47:
+                    ce:f6:df:eb:c6:16:06:62:33:d0:af:2f:60:f7:71:
+                    f6:bf:7c:2e:25:20:a5:b4:c7:b4:a6:48:62:b2:67:
+                    6e:03:e7:6c:2f:62:70:fd:b8:da:4b:01:e3:26:93:
+                    c7:54:16:73:5e:2f:4c:db:f5:95:4b:6f:e3:32:44:
+                    99:a6:a8:ca:73:65:11:32:45:7f:f4:f3:d1:02:89:
+                    c6:d4:fe:97:f0:48:03:3f:24:10:93:00:70:ab:1f:
+                    a1:3c:7d:39:3b:5f:b8:bf:39:a5:76:c2:83:16:ca:
+                    2a:62:a7:e9:1c:f1:50:2c:d2:ce:03:1b:a0:2d:33:
+                    e9:6f:19:c7:2d:a0:2c:88:6a:32:6f:00:5c:01:7b:
+                    b1:a9:70:ad:18:ab:57:89:56:b0:cf:4c:3a:15:44:
+                    81:f8:dc:bf:fa:a6:41:26:2b:d4:04:6b:c3:07:a0:
+                    1d:1a:b1:3c:0d:ea:87:5d:64:7e:ae:58:48:55:3b:
+                    5b:bf:9f:26:b5:87:e9:5b:8b:67:40:75:7e:3d:be:
+                    96:ca:0c:35:e9:05:03:55:0b:0f:c0:ca:ed:a0:05:
+                    22:1f:58:d7:2e:09:b7:ff:f1:32:e3:8f:70:3e:4f:
+                    58:d1:85:99:49:3b:a0:f7:b0:88:85:0c:2e:35:d2:
+                    59:c8:2b:41:56:1b:64:40:d6:fe:fa:28:30:9a:28:
+                    e3:b5:60:d5:f4:0f:7a:17:a3:6c:e3:44:d6:70:48:
+                    69:e4:55:84:97
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier:
+                D7:7B:A1:87:92:8B:B8:52:1A:29:91:A5:36:5A:1C:B4:32:EB:EC:D1
+            X509v3 Authority Key Identifier:
+                keyid:D7:7B:A1:87:92:8B:B8:52:1A:29:91:A5:36:5A:1C:B4:32:EB:EC:D1
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Key Usage: critical
+                Digital Signature, Certificate Sign, CRL Sign
+    Signature Algorithm: sha512WithRSAEncryption
+         01:9f:2d:35:d6:f7:ae:3e:99:53:70:d7:b2:2d:e2:a1:59:19:
+         ff:cb:d5:4c:40:4c:a1:68:b9:6c:0b:50:e2:df:95:8d:f2:8c:
+         23:8f:8f:a0:ba:02:e5:0d:db:44:73:fa:6f:ce:09:3e:66:40:
+         2e:a6:54:24:ae:c5:3d:d3:b7:6f:c2:40:cf:6f:8a:d6:64:1e:
+         61:8d:ba:fd:c9:5c:84:1c:ad:5b:1e:1e:d1:49:49:09:ac:1d:
+         cd:47:0a:87:d6:5c:96:cf:f2:df:69:57:db:57:80:ad:69:a1:
+         11:85:38:73:64:2a:7f:33:07:8e:4e:2b:e0:d9:7a:52:96:ec:
+         b9:b3:c9:44:11:b3:02:fd:d1:ae:22:c0:4c:8a:d5:f7:5c:b9:
+         5b:61:ad:8d:0f:76:87:64:ba:3a:5f:dc:90:30:57:d3:0a:38:
+         30:60:6d:a7:78:36:2e:a6:7b:dc:2c:83:65:ae:52:58:72:b6:
+         12:ac:8b:e8:42:7f:57:7e:c9:e3:53:70:17:cf:e8:dc:eb:12:
+         eb:3b:71:2d:5c:38:62:f5:ef:90:4d:f7:27:bd:1b:20:97:f1:
+         e3:f5:26:6b:d7:0d:4b:d4:f3:c9:a3:e2:a3:b1:16:af:56:fc:
+         da:1d:79:41:02:fb:d4:b4:4a:23:26:b9:11:de:3f:9b:e7:3b:
+         d0:07:a7:60:56:b3:34:cd:48:4c:43:dc:d1:a7:94:7f:c6:a1:
+         de:67:fd:13:4d:07:bd:90:46:bc:42:e4:73:b9:12:24:2b:95:
+         9b:87:be:84:8b:1d:d2:fb:6b:93:b1:b8:f8:eb:69:e4:e0:4d:
+         28:3d:1f:29:89:8a:29:4b:86:44:14:47:eb:29:6d:78:1c:ea:
+         61:f5:9b:1c:23:89:7f:1d:f0:e6:4c:d7:e0:a7:21:65:eb:65:
+         2b:bf:35:41:9e:8c:fe:b1:b8:53:81:b3:c7:3d:c0:97:39:4a:
+         e1:9a:9c:fd:23:9a:01:93:21:00:65:8b:a7:4a:fc:d8:ff:d4:
+         97:52:cc:fa:a6:c5:c7:26:65:73:2d:07:27:7b:f6:10:4e:da:
+         56:cd:5f:f0:18:3e:dc:8e:30:e5:6d:fc:ec:98:60:9f:67:c8:
+         ea:3c:1a:22:72:5e:48:51:57:72:66:c2:60:b9:f1:19:1d:7c:
+         4a:65:0e:f0:2f:b4:7a:8c:aa:e3:fc:6b:42:0d:ec:b5:5a:bd:
+         90:4f:c5:57:e4:94:e4:f5:c2:50:16:38:23:0d:66:80:c8:20:
+         69:18:46:90:bd:82:5c:68:ec:64:d8:3f:96:6a:9e:5a:c7:c9:
+         d4:7d:6f:fd:f6:f5:45:03:41:09:2a:c4:95:57:3c:3b:75:a4:
+         6d:cb:45:29:7d:9b:31:d9:27:f3:a6:0d:26:ca:69:a0:07:cf:
+         8d:63:ab:7a:f1:d2:f9:0b:fc:71:02:fe:66:11:0f:30:18:99:
+         8f:e3:98:90:a6:8e:53:e8:b5:55:32:b9:2d:2d:fe:5e:23:3c:
+         65:00:b4:08:5b:f0:20:a5:21:fd:24:a0:aa:a4:8b:5d:c5:f8:
+         ac:00:82:2c:f5:ef:17:1d:b5:49:24:0d:09:75:ee:eb:b4:08:
+         fe:4d:46:34:87:4d:31:4a:ac:9f:49:26:e9:70:32:7d:94:8a:
+         12:64:e2:6f:15:07:56:3b:10:7c:73:7b:d9:64:61:a1:32:e4:
+         45:9b:4e:ac:50:7b:dc:1e:3a:3c:2b:09:db:ab:23:b1:0c:68:
+         de:aa:de:98:5a:dc:ba:59:c3:62:9f:45:9c:89:1d:f7:bc:61:
+         c8:cf:05:4d:c4:d9:e6:b9:8d:f4:f1:b3:6c:32:f6:3d:8e:c9:
+         9d:df:b8:5d:9a:6c:27:99:08:1e:ec:02:1a:ed:33:0f:8d:a2:
+         a6:d2:f5:7f:d7:3b:45:48:e0:d6:08:8d:8a:ee:49:66:2f:63:
+         2d:38:93:06:7e:a5:1e:39:f8:cf:00:d6:d2:de:53:09:04:01:
+         fd:ab:12:cc:ec:a9:e0:fa:77:ea:56:db:7e:34:6f:4c:c5:c4:
+         db:3f:cd:05:90:16:bf:e8:9c:46:82:38:ec:8b:00:e6:86:bd:
+         8c:4c:26:0e:2b:f7:83:f9:66:62:90:c3:a2:7b:2b:c7:9b:6b:
+         e0:c5:80:9d:5a:b8:5a:19:f7:37:b7:aa:10:d9:83:be:99:72:
+         3b:7b:a7:77:17:76:bd:d1:45:18:90:12:20:8d:ef:73:bb:44:
+         4b:c6:70:41:86:ea:11:c8:6c:2f:b9:00:25:aa:03:03:05:92:
+         33:4c:ed:15:9f:07:b0:ec:a4:4b:77:32:e1:59:b8:a2:92:18:
+         bc:d6:ae:8b:83:ad:9a:5a:36:dd:17:a5:1e:e8:05:57:72:1f:
+         9d:aa:6a:fe:f5:a5:6d:d1:8e:84:4d:34:bb:ee:7a:d0:ca:09:
+         72:2c:a2:1e:37:1e:9c:10:70:e3:11:35:e5:3d:81:9b:08:09:
+         6b:74:a0:1d:4c:0e:27:82:70:59:9f:31:90:ff:cc:e0:b4:ff:
+         73:bc:82:55:03:a7:2e:38:09:fc:18:51:2c:ad:be:c6:37:6d:
+         10:48:3c:32:25:6a:d8:8b:a7:fe:9b:ae:03:f6:b3:8a:e0:9c:
+         f8:b7:e9:44:7e:37:1f:25:e3:3f:51:c3:65:86:60:13:70:c1:
+         d7:58:f0:a8:2a:43:9f:96:5e:0f:05:cf:d6:8a:0b:f5:c5:8c:
+         3b:d1:16:78:a5:a8:b4:ec:bc:c9:c4:d1:d8:86:fa:44:dd
\ No newline at end of file
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-endpoint-cert.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-endpoint-cert.xml
new file mode 100644
index 0000000..6519f49
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-endpoint-cert.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<certificates>
+  <metadata>
+    <serial>
+      1000
+    </serial>
+    <creation-time>
+      1515697631
+    </creation-time>
+    <refresh-interval>
+      2592000
+    </refresh-interval>
+    <previous>
+      <serial>
+        0
+      </serial>
+      <hash>
+        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
+      </hash>
+    </previous>
+  </metadata>
+  <endpoints>
+  </endpoints>
+</certificates>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-refresh-interval.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-refresh-interval.xml
new file mode 100644
index 0000000..3da0122
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-refresh-interval.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<certificates>
+  <metadata>
+    <serial>
+      1000
+    </serial>
+    <creation-time>
+      1515697631
+    </creation-time>
+    <previous>
+      <serial>
+        0
+      </serial>
+      <hash>
+        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
+      </hash>
+    </previous>
+  </metadata>
+  <endpoints>
+    <cert>
+      MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+      R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+      NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+      YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+      tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+      4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+      tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+      HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+      GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+      UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+      33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+      7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+      hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+      79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+      M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+      JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+      BuwwuQxvQDF4pmQd
+    </cert>
+  </endpoints>
+</certificates>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-serial.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-serial.xml
new file mode 100644
index 0000000..4370ff0
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-no-serial.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<certificates>
+  <metadata>
+    <creation-time>
+      1515697631
+    </creation-time>
+    <refresh-interval>
+      2592000
+    </refresh-interval>
+    <previous>
+      <serial>
+        0
+      </serial>
+      <hash>
+        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
+      </hash>
+    </previous>
+  </metadata>
+  <endpoints>
+    <cert>
+      MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+      R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+      NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+      YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+      tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+      4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+      tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+      HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+      GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+      UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+      33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+      7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+      hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+      79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+      M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+      JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+      BuwwuQxvQDF4pmQd
+    </cert>
+  </endpoints>
+</certificates>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml
new file mode 100644
index 0000000..0f4e8a3
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-refresh-intervals.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<certificates>
+  <metadata>
+    <serial>
+      1000
+    </serial>
+    <creation-time>
+      1515697631
+    </creation-time>
+    <refresh-interval>
+      2592000
+    </refresh-interval>
+    <refresh-interval>
+      2592000
+    </refresh-interval>
+    <previous>
+      <serial>
+        0
+      </serial>
+      <hash>
+        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
+      </hash>
+    </previous>
+  </metadata>
+  <endpoints>
+    <cert>
+      MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+      R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+      NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+      YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+      tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+      4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+      tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+      HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+      GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+      UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+      33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+      7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+      hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+      79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+      M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+      JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+      BuwwuQxvQDF4pmQd
+    </cert>
+  </endpoints>
+</certificates>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-serials.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-serials.xml
new file mode 100644
index 0000000..a2685aa
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-cert-file-two-serials.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<certificates>
+  <metadata>
+    <serial>
+      1000
+    </serial>
+    <serial>
+      1000
+    </serial>
+    <creation-time>
+      1515697631
+    </creation-time>
+    <refresh-interval>
+      2592000
+    </refresh-interval>
+    <previous>
+      <serial>
+        0
+      </serial>
+      <hash>
+        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
+      </hash>
+    </previous>
+  </metadata>
+  <endpoints>
+    <cert>
+      MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+      R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+      NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+      YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+      tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+      4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+      tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+      HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+      GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+      UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+      33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+      7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+      hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+      79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+      M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+      JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+      BuwwuQxvQDF4pmQd
+    </cert>
+  </endpoints>
+</certificates>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signature.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signature.sig.xml
new file mode 100644
index 0000000..5dc8ffa
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signature.sig.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<signature>
+  <certificate>
+    MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+    R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+    NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+    YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+    tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+    4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+    tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+    HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+    GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+    UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+    33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+    7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+    hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+    79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+    M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+    JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+    BuwwuQxvQDF4pmQd
+  </certificate>
+</signature>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signer-cert.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signer-cert.sig.xml
new file mode 100644
index 0000000..aa81295
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-no-signer-cert.sig.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<signature>
+  <value>
+    VEVTVA==
+  </value>
+</signature>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signatures.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signatures.sig.xml
new file mode 100644
index 0000000..09d0f44
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signatures.sig.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<signature>
+  <certificate>
+    MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+    R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+    NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+    YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+    tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+    4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+    tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+    HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+    GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+    UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+    33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+    7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+    hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+    79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+    M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+    JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+    BuwwuQxvQDF4pmQd
+  </certificate>
+  <value>
+    VEVTVA==
+  </value>
+  <value>
+    VEVTVA==
+  </value>
+</signature>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signer-certs.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signer-certs.sig.xml
new file mode 100644
index 0000000..44e8993
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/invalid-sig-file-two-signer-certs.sig.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<signature>
+  <certificate>
+    signer certificate 1
+  </certificate>
+  <certificate>
+    signer certificate 2
+  </certificate>
+  <value>
+    VEVTVA==
+  </value>
+</signature>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file-no-intermediates.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file-no-intermediates.xml
new file mode 100644
index 0000000..e59bf36
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file-no-intermediates.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<certificates>
+  <metadata>
+    <serial>
+      1000
+    </serial>
+    <creation-time>
+      1515697631
+    </creation-time>
+    <refresh-interval>
+      2592000
+    </refresh-interval>
+    <previous>
+      <serial>
+        0
+      </serial>
+      <hash>
+        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
+      </hash>
+    </previous>
+  </metadata>
+  <endpoints>
+    <cert>
+      MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+      R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+      NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+      YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+      tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+      4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+      tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+      HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+      GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+      UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+      33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+      7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+      hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+      79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+      M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+      JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+      BuwwuQxvQDF4pmQd
+    </cert>
+  </endpoints>
+</certificates>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file.xml
new file mode 100644
index 0000000..be4893f
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-cert-file.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<certificates>
+  <metadata>
+    <serial>
+      1000
+    </serial>
+    <creation-time>
+      1515697631
+    </creation-time>
+    <refresh-interval>
+      2592000
+    </refresh-interval>
+    <previous>
+      <serial>
+        0
+      </serial>
+      <hash>
+        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
+      </hash>
+    </previous>
+  </metadata>
+  <intermediates>
+    <cert>
+      MIIHMDCCAxegAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v
+      Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDExMjAwMjM1N1oXDTI4MDExMDAwMjM1
+      N1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0
+      ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALlhoKYuwxaatY9ERDFp
+      iEygSnjy0xzaiF4uCyiTfAuboSi5QwGon3ohf0ufJF02L9lnTMoeBAg+88m8AMgW
+      KFcEupabqlZfA3F/50mMCmnJvBSLXJ+chUdcAVpwcZAsq6ko22ARBxao1wu2qxNe
+      D8eXiiK8DRpTtKy3wOldZJ222v35v9JGOTjORZRrcv7Z8f6I5/cSsTS+WoVk/aBt
+      QqyFkcdw1zqulnlFE2rxNAVgyLlW71WJikYTDtUDeo79LvkDGjVsLo2MfpNxuK+5
+      MuMqzyN5LmzXJmNCEW1O5IIIUAPhgy5s08G+3G644wCEWsAnv2FBWLBn/HmJu6Uq
+      nSM2AaJN56V0tJG/yL2VgTnPJrJypNTKZW3OTCLCaYcTEbKfarxLwVWxvIWSIgkn
+      0q57GYhf7O+x9vvcOUmZwVxZECorIiK4n5AWG/KD3dWI3UGGGpYsDazRngA/bQPu
+      DSzBP9FBVcQt3/DMBG1s6f2Eko5f6aTFcVW9iV7aWLeIq+pQYlbmG42decj+aHLQ
+      COp5KV+Q77y4kFhZQFAQ1mN4crnhuEc1K5SmjAK24zIqWbwM3ly0KSQFc9jAmONg
+      0xu7kAObP3PZk85En12yLLscNmHCWYfOOEvTHf4KX7tjBl4HHp/ur+2Qwgpt9MFB
+      MGqR2cni5OV6gZcRdHaEerjrAgMBAAGjZjBkMB0GA1UdDgQWBBRE9RxHT7U3EP1v
+      djRzNYMrU7EseDAfBgNVHSMEGDAWgBTXe6GHkou4UhopkaU2Why0Muvs0TASBgNV
+      HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC
+      BAIAAfa7FKkfh4t+G8Sv4n3gUcuEAtmpCsTtHJU67r5eSvR24fDX7sqqSIib9sQ8
+      adA1FtnE3wnC4bEKnIwQLerWTN4i4V9oEKRIT5o5Rr61LyO9R+Prpo6uJVoPujFH
+      GZPdIj/Qs4Xax4a11QD+70+ZmmdL6yfigVDWA4yduFdMg6heHRf3EFCbVBv5qbBS
+      n8+eFKRnBZ/kQdFlYt+G+92Qqyn2uAcER6kZjIfPdnZh44SazLP37W8AkDX30Pmk
+      V0PHVGCDrap44q3maI1m8NAE1jGwwmRzJL953x5XgbVGt0K/3cNoWtKLenwX/G3I
+      akrgvOY5Zl0v3FRDZwGFt9UIBfZDDOGRMXIgIGs/1cvkwWpOT6dyReqDXempiQ1q
+      Yy6J5VsK5WK6gEelUyoACbzgby25V6a79Q1MI7dXmFQfCcX0nAD/AZmM1HkeYgrC
+      uq6fWoPOVMKML2mN90rCzkWxGaLcl5dPfad0O1LrcP48SRE5MXMWyxZZBon+wDIk
+      ascyM/r4fmk4kq64YKdm2wxCDMNArAIcyBkwOaWWfabtSagxJ3qtMtxK0qBUsbLC
+      yMyYpgU1h9c8rEdc4JgeE2LXJzxTKDc3SBOqbuNMlKWjYA+X+SUvVYALrQKAC+5v
+      wdUhLYdAPAksqk/ZoiBjkW35FfvqQMJBY29VnDT1h7/Nxk5gu+goTA9oFIYNrNte
+      +s0my+IUgYhKJBsgh7Mupv+B92GN5b3b440BMHB5QR959Jdq6BAXNUyZLM5fhZQE
+      Jj/rxZFXaqq757kgUhwWBz5TDbYF7GkqTyM4k430xwJKY0AYYEHmv1UYNo5X4G3x
+      SC2LhWC1b9VAykdkHbLs+IA8klxURmLmRiRj1UryhQjjT8h/FvNyPnbT1AKoElix
+      QLnLi8thkJ+tQggO0hISFsIrKNfnn0V6O0VKw9UZsMigsbYG5EbzIXcAyy8Avr9n
+      um7gBBZDt7fWso0+pG1UenJ+PybeuW/azQDLRw1Syz8OwU+ABRLq0JyyAtV7VPY5
+      C9pkKS+bU8nECxr6dMhAbpLBHlKsyb1qtkOt1p7WagEQZFIIc6svc73+L/ET/lWn
+      GBmkVVsCN7Aqyo5aXQWueXP4FUL+6O5+JALqw3qPeQgfnLkh0cUuccNND05QeEiv
+      Zswc/23KJXy1XbdVKT3UP0RAF7DxstbRGQbAT3z+n931e3KhtU28OKjsFtoeq2Dj
+      6STPEXh4rYFWMM8+DrJetAtBqk/i+vBwRA8f7jqIPPep/vEjPqqMOpdSVcoFQ1df
+      JuOZtGfEUjFHnlDr3eGP7KUIEZvhan1zm544dDgPVTXxrY4moi2BhKEY69zRSX6B
+      +a0fa5B3pxc8BN0LsHA0stT/Y2o=
+    </cert>
+    <cert>
+      MIIESTCCAjGgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29v
+      Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTIwMDM4MDNa
+      Fw0yMzAxMTEwMDM4MDNaMDoxODA2BgNVBAMML0dvb2dsZSBDcnlwdEF1dGhWYXVs
+      dCBJbnRlcm1lZGlhdGUgSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOC
+      AQ8AMIIBCgKCAQEA0v3bN3MwKifDAkF1524XzuaxYtk1sQKUlAlNngh+Qv4RjCkX
+      TECi7po8LeNsY+hWxmW3XZ22RBphe/yP4YcOdbqlIjZYNx3b75hCSJCadOkdW+Z9
+      f6+tKsHgeUja6r9r2TThzileImAvjXShe7GZYW8csPv6HaEVRXQlu8fGAZf8skmJ
+      EMfJx84//WeULdVz94beDhi9YAf4gLfmOayQcdWhDcMYI39knJcRny1ffRGgb1Hf
+      lE+3/a3aGFeODaxfkPaGRxEhzhZ/JDBiNgUAH/u7C5nxqa2WOu5e0wq3S0TndIOE
+      hmnwCE2GvxADFQst+rSsOn4EHit70hv4CfrMRQIDAQABo2YwZDAdBgNVHQ4EFgQU
+      0dKv4xTaEmdwHyox3tY8H8XVDGIwHwYDVR0jBBgwFoAURPUcR0+1NxD9b3Y0czWD
+      K1OxLHgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI
+      hvcNAQELBQADggIBAJaArqLlJ2SLQ8JRwanD6LPlqQxucQ+x/LztTQpzPrsFfJds
+      E/sDZr2rXhDpz/bifIdj/DCbQ6/3w+t5JdFjT8GjXLgz1kCa/4W409FgSTgy1ENn
+      AMUU6pFIbOq/Qy/71uOTrrFWYTN5Vk+RBGxx5iDfHjDYraudi4VlcNkal4OyM98n
+      N3qp9cZD0RtWxMhvq6ahgmf9cTbEw6+l8yf/bogGLBYXXYeOoO5Q134AxrrgfthE
+      tvyKwJkT/l3OFKRcaHrebs+V1z5gPs7zWOyO5n2Z1SAmcOGfTfKMZWwp3Hi3OTr2
+      gB3LUYKyQVhC70dka3X+IbnFg5YfzJtX6YGnHlnI1SufOkEpGQDfcc0UQAWg/lgb
+      RkfMFD9tuJomBhyqv1YaxLN8yL4ZTRU0KCvvC5I5+X/zt9kBjnHlBOdYtknZT5jz
+      7+mjqWdpmWoAjeV5+CgIzG2k7JAm6rQuE1ZQNF0wAYxPret4NHPJFqfD5gGhdrYw
+      pEUxkcwHERA/E1CkpyqUy/Hd3kqHvnEDqzFcxBdUdmOgnbpI2nAZdEpfxmA5+M1n
+      UoxQ8ZWAZH+Mdlkw/Hx5hVjGjz8snD4QN25pj/wT+V6AR5OmYb8yfsQb2S8a8yDp
+      HzcIHW+dEWpX2boirOsrdI16kNtxYqtG7c5qWBPJy5Zjkvh9qbnfT/RQx10g
+    </cert>
+  </intermediates>
+  <endpoints>
+    <cert>
+      MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+      R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+      NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+      YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+      tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+      4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+      tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+      HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+      GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+      UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+      33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+      7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+      hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+      79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+      M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+      JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+      BuwwuQxvQDF4pmQd
+    </cert>
+    <cert>
+      MIICrDCCAZSgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwOjE4MDYGA1UEAwwvR29v
+      Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZSBJbnRlcm1lZGlhdGUwHhcN
+      MTgwMTEyMDEwMzA5WhcNMTkwMTEyMDEwMzA5WjArMSkwJwYDVQQDDCBHb29nbGUg
+      Q3J5cHRBdXRoVmF1bHQgSW5zdGFuY2UgMjBZMBMGByqGSM49AgEGCCqGSM49AwEH
+      A0IABGhmBQyWdjsXKJRbkW4iIrvt6iqhX5t2XGt/vZS9CoOl0fs+EvJXo4kgrnx8
+      /8SGxz3pwRkFhY943QYy6a1gv/2jgZUwgZIwCQYDVR0TBAIwADAdBgNVHQ4EFgQU
+      xFmLyxUS2JHKURBtewBKRP6kQBgwVgYDVR0jBE8wTYAU0dKv4xTaEmdwHyox3tY8
+      H8XVDGKhMaQvMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRl
+      cm1lZGlhdGWCAhAAMA4GA1UdDwEB/wQEAwIDCDANBgkqhkiG9w0BAQsFAAOCAQEA
+      EJWpl7HU6LxukLqhw2tVZr7IRrKIucRk+RKaaiMx1Hx2jsTTskiJRiZas/xoPSqX
+      z1K5DVgI486i7HyqnWkGH5xVzCsv+rya5FOSTS3jVtgtoA4HFEqeeAcDowPDqVw3
+      yFTA55ukZnzVaPLpDfPqkhzWiuLQ/4fI6YCmOnWB8KtHTMdyGsDSAkpoxpok++NJ
+      Lu79BoBLe2ucjN383lTlieLxmrmHjF9ryYSQczcm0v6irMOMxEovw5iT4LHiEhbm
+      DfOPW909fe/s+K3TGZ3Q6U77x8g5k9dVovMgA4pFwtREtknFjeK1wXR3/eXGcP3W
+      0bMX1yTWYJQFWCG3DFoC5w==
+    </cert>
+    <cert>
+      MIIDkjCCAXqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29v
+      Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTIwMDU2MjNa
+      Fw0yMDA3MTMwMDU2MjNaMCsxKTAnBgNVBAMMIEdvb2dsZSBDcnlwdEF1dGhWYXVs
+      dCBJbnN0YW5jZSAxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEimGC4KEks4JL
+      83DNAAGCA5sKqqxqUPgV8gxgsijlMPL0TOtyJhJ2vSFIULEa0coVFbu+fAdxt3CV
+      DbzD0vWAmaOBiDCBhTAJBgNVHRMEAjAAMB0GA1UdDgQWBBTVeDueShnq1LCqkCFL
+      MAYtpxkCuDBJBgNVHSMEQjBAgBRE9RxHT7U3EP1vdjRzNYMrU7EseKEkpCIwIDEe
+      MBwGA1UEAwwVR29vZ2xlIENyeXB0QXV0aFZhdWx0ggIQATAOBgNVHQ8BAf8EBAMC
+      AwgwDQYJKoZIhvcNAQELBQADggIBADUZCjfBwBL9SSZDkMwE3n08schTBAgZCCrv
+      XOQVPGrfbFUcMv1mT4e8a5zxE98HsCS6K4HB40RtTXkmt6nuN+NyBrAmZJrBCqvG
+      IYtGsBLLEnojgWuSpQIBQeQy9it3RFdSR/1FIPssrWUB5KrtRvd+07+Mo7tI91jE
+      EunOrocu46g6p/OKSIZ7UmwZzczn2CJsrxuNPgqdlza3ytb+TTm536ZHnqaefSZD
+      rrruNneTXoqjC2OFn/OVLHQ1ee/vrHiX70P8p1V09cccDiwMCIZskNACYgWRdLYU
+      F5aYGueoFajrb4zmMoy8DK/4lh1EsfWMsrsQK6whmPidzgz37nb3rPpiHTdxu1Fc
+      2XM9QV3Jfj2U5FMOZTcDha7W7kb++gSnQEPTM0+Zu6lTJmcZgK4RJ7lmIfK/eVbJ
+      6V/wplOzXSxO3jBb2LNhLbhkUzcg68EIEPxaBpXYVOU2tSo2FMgi7/YLwQLorc6Q
+      h1pUZep8T8SLpvI02GvsB8TroFr2tCvCe5A1VxBQDx9IE7nEd2N30XxqReFk8Y82
+      xZMUOA4DL33NI45KWjhcawm0tzAPFfKjta/zYvnf7rwwE4r2PVuOXdet5eN8zBje
+      yJbEpjCemADujcwtYQ8hScyj/eCT2KNbZ9ibY2yrZEEuRQanq8CLAbpvSZYIHVhg
+      Clar7+38
+    </cert>
+  </endpoints>
+</certificates>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file-no-intermediates.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file-no-intermediates.sig.xml
new file mode 100644
index 0000000..9c0adcd
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file-no-intermediates.sig.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<signature>
+  <certificate>
+    MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi
+    R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1
+    NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW
+    YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu
+    tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl
+    4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21
+    tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu
+    HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr
+    GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb
+    UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe
+    33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5
+    7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ
+    hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa
+    79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4
+    M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf
+    JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp
+    BuwwuQxvQDF4pmQd
+  </certificate>
+  <value>
+    VEVTVA==
+  </value>
+</signature>
diff --git a/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file.sig.xml b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file.sig.xml
new file mode 100644
index 0000000..f94b109
--- /dev/null
+++ b/services/tests/servicestests/assets/KeyStoreRecoveryControllerTest/xml/valid-sig-file.sig.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<signature>
+  <intermediates>
+    <cert>
+      MIIHMDCCAxegAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v
+      Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDExMjAwMjM1N1oXDTI4MDExMDAwMjM1
+      N1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0
+      ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALlhoKYuwxaatY9ERDFp
+      iEygSnjy0xzaiF4uCyiTfAuboSi5QwGon3ohf0ufJF02L9lnTMoeBAg+88m8AMgW
+      KFcEupabqlZfA3F/50mMCmnJvBSLXJ+chUdcAVpwcZAsq6ko22ARBxao1wu2qxNe
+      D8eXiiK8DRpTtKy3wOldZJ222v35v9JGOTjORZRrcv7Z8f6I5/cSsTS+WoVk/aBt
+      QqyFkcdw1zqulnlFE2rxNAVgyLlW71WJikYTDtUDeo79LvkDGjVsLo2MfpNxuK+5
+      MuMqzyN5LmzXJmNCEW1O5IIIUAPhgy5s08G+3G644wCEWsAnv2FBWLBn/HmJu6Uq
+      nSM2AaJN56V0tJG/yL2VgTnPJrJypNTKZW3OTCLCaYcTEbKfarxLwVWxvIWSIgkn
+      0q57GYhf7O+x9vvcOUmZwVxZECorIiK4n5AWG/KD3dWI3UGGGpYsDazRngA/bQPu
+      DSzBP9FBVcQt3/DMBG1s6f2Eko5f6aTFcVW9iV7aWLeIq+pQYlbmG42decj+aHLQ
+      COp5KV+Q77y4kFhZQFAQ1mN4crnhuEc1K5SmjAK24zIqWbwM3ly0KSQFc9jAmONg
+      0xu7kAObP3PZk85En12yLLscNmHCWYfOOEvTHf4KX7tjBl4HHp/ur+2Qwgpt9MFB
+      MGqR2cni5OV6gZcRdHaEerjrAgMBAAGjZjBkMB0GA1UdDgQWBBRE9RxHT7U3EP1v
+      djRzNYMrU7EseDAfBgNVHSMEGDAWgBTXe6GHkou4UhopkaU2Why0Muvs0TASBgNV
+      HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC
+      BAIAAfa7FKkfh4t+G8Sv4n3gUcuEAtmpCsTtHJU67r5eSvR24fDX7sqqSIib9sQ8
+      adA1FtnE3wnC4bEKnIwQLerWTN4i4V9oEKRIT5o5Rr61LyO9R+Prpo6uJVoPujFH
+      GZPdIj/Qs4Xax4a11QD+70+ZmmdL6yfigVDWA4yduFdMg6heHRf3EFCbVBv5qbBS
+      n8+eFKRnBZ/kQdFlYt+G+92Qqyn2uAcER6kZjIfPdnZh44SazLP37W8AkDX30Pmk
+      V0PHVGCDrap44q3maI1m8NAE1jGwwmRzJL953x5XgbVGt0K/3cNoWtKLenwX/G3I
+      akrgvOY5Zl0v3FRDZwGFt9UIBfZDDOGRMXIgIGs/1cvkwWpOT6dyReqDXempiQ1q
+      Yy6J5VsK5WK6gEelUyoACbzgby25V6a79Q1MI7dXmFQfCcX0nAD/AZmM1HkeYgrC
+      uq6fWoPOVMKML2mN90rCzkWxGaLcl5dPfad0O1LrcP48SRE5MXMWyxZZBon+wDIk
+      ascyM/r4fmk4kq64YKdm2wxCDMNArAIcyBkwOaWWfabtSagxJ3qtMtxK0qBUsbLC
+      yMyYpgU1h9c8rEdc4JgeE2LXJzxTKDc3SBOqbuNMlKWjYA+X+SUvVYALrQKAC+5v
+      wdUhLYdAPAksqk/ZoiBjkW35FfvqQMJBY29VnDT1h7/Nxk5gu+goTA9oFIYNrNte
+      +s0my+IUgYhKJBsgh7Mupv+B92GN5b3b440BMHB5QR959Jdq6BAXNUyZLM5fhZQE
+      Jj/rxZFXaqq757kgUhwWBz5TDbYF7GkqTyM4k430xwJKY0AYYEHmv1UYNo5X4G3x
+      SC2LhWC1b9VAykdkHbLs+IA8klxURmLmRiRj1UryhQjjT8h/FvNyPnbT1AKoElix
+      QLnLi8thkJ+tQggO0hISFsIrKNfnn0V6O0VKw9UZsMigsbYG5EbzIXcAyy8Avr9n
+      um7gBBZDt7fWso0+pG1UenJ+PybeuW/azQDLRw1Syz8OwU+ABRLq0JyyAtV7VPY5
+      C9pkKS+bU8nECxr6dMhAbpLBHlKsyb1qtkOt1p7WagEQZFIIc6svc73+L/ET/lWn
+      GBmkVVsCN7Aqyo5aXQWueXP4FUL+6O5+JALqw3qPeQgfnLkh0cUuccNND05QeEiv
+      Zswc/23KJXy1XbdVKT3UP0RAF7DxstbRGQbAT3z+n931e3KhtU28OKjsFtoeq2Dj
+      6STPEXh4rYFWMM8+DrJetAtBqk/i+vBwRA8f7jqIPPep/vEjPqqMOpdSVcoFQ1df
+      JuOZtGfEUjFHnlDr3eGP7KUIEZvhan1zm544dDgPVTXxrY4moi2BhKEY69zRSX6B
+      +a0fa5B3pxc8BN0LsHA0stT/Y2o=
+    </cert>
+  </intermediates>
+  <certificate>
+    MIIESTCCAjGgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29v
+    Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTIwMDM4MDNa
+    Fw0yMzAxMTEwMDM4MDNaMDoxODA2BgNVBAMML0dvb2dsZSBDcnlwdEF1dGhWYXVs
+    dCBJbnRlcm1lZGlhdGUgSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOC
+    AQ8AMIIBCgKCAQEA0v3bN3MwKifDAkF1524XzuaxYtk1sQKUlAlNngh+Qv4RjCkX
+    TECi7po8LeNsY+hWxmW3XZ22RBphe/yP4YcOdbqlIjZYNx3b75hCSJCadOkdW+Z9
+    f6+tKsHgeUja6r9r2TThzileImAvjXShe7GZYW8csPv6HaEVRXQlu8fGAZf8skmJ
+    EMfJx84//WeULdVz94beDhi9YAf4gLfmOayQcdWhDcMYI39knJcRny1ffRGgb1Hf
+    lE+3/a3aGFeODaxfkPaGRxEhzhZ/JDBiNgUAH/u7C5nxqa2WOu5e0wq3S0TndIOE
+    hmnwCE2GvxADFQst+rSsOn4EHit70hv4CfrMRQIDAQABo2YwZDAdBgNVHQ4EFgQU
+    0dKv4xTaEmdwHyox3tY8H8XVDGIwHwYDVR0jBBgwFoAURPUcR0+1NxD9b3Y0czWD
+    K1OxLHgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI
+    hvcNAQELBQADggIBAJaArqLlJ2SLQ8JRwanD6LPlqQxucQ+x/LztTQpzPrsFfJds
+    E/sDZr2rXhDpz/bifIdj/DCbQ6/3w+t5JdFjT8GjXLgz1kCa/4W409FgSTgy1ENn
+    AMUU6pFIbOq/Qy/71uOTrrFWYTN5Vk+RBGxx5iDfHjDYraudi4VlcNkal4OyM98n
+    N3qp9cZD0RtWxMhvq6ahgmf9cTbEw6+l8yf/bogGLBYXXYeOoO5Q134AxrrgfthE
+    tvyKwJkT/l3OFKRcaHrebs+V1z5gPs7zWOyO5n2Z1SAmcOGfTfKMZWwp3Hi3OTr2
+    gB3LUYKyQVhC70dka3X+IbnFg5YfzJtX6YGnHlnI1SufOkEpGQDfcc0UQAWg/lgb
+    RkfMFD9tuJomBhyqv1YaxLN8yL4ZTRU0KCvvC5I5+X/zt9kBjnHlBOdYtknZT5jz
+    7+mjqWdpmWoAjeV5+CgIzG2k7JAm6rQuE1ZQNF0wAYxPret4NHPJFqfD5gGhdrYw
+    pEUxkcwHERA/E1CkpyqUy/Hd3kqHvnEDqzFcxBdUdmOgnbpI2nAZdEpfxmA5+M1n
+    UoxQ8ZWAZH+Mdlkw/Hx5hVjGjz8snD4QN25pj/wT+V6AR5OmYb8yfsQb2S8a8yDp
+    HzcIHW+dEWpX2boirOsrdI16kNtxYqtG7c5qWBPJy5Zjkvh9qbnfT/RQx10g
+  </certificate>
+  <value>
+    zELcMKbEb82mjWdhaV62Po4Tn/fEnHg7TMQzlz3cpDP3uzGKXg4fvCa+yDYrEYqm17uywOfFQpJs
+    pVjoUMINdnYogO44mul+E+m/klzSQN3GbmvYDtKpFsSGqsymyFSg8Bv2LeDLx2Pisc3sLUhxwKN4
+    8B6MwfZ3qUnRa5/ySk0bzEYYiRWsYR5oY7vK0kAI5c4Oi77E0W440FaEhnT7WxucFUnAhZbOSwXA
+    apE39BXu6ZbAPpTSc4f+uMErF7cRGbIODcAQJko6yjliBmvnCxj0ct7qzwUpgJojy/G5DLaVx3MF
+    Xnee9peYCrKFWpB+Z/7io0/Fqs/fDF7U25BsXA==
+  </value>
+</signature>
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
similarity index 92%
rename from services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
rename to services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
index 2c50f22..90db2a3 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
@@ -15,7 +15,7 @@
  */
 package com.android.server;
 
-import static com.android.server.ForceAppStandbyTracker.TARGET_OP;
+import static com.android.server.AppStateTracker.TARGET_OP;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -33,6 +33,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OpEntry;
 import android.app.AppOpsManager.PackageOps;
@@ -63,7 +64,7 @@
 
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
-import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.server.AppStateTracker.Listener;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -82,17 +83,17 @@
 import java.util.function.Consumer;
 
 /**
- * Tests for {@link ForceAppStandbyTracker}
+ * Tests for {@link AppStateTracker}
  *
  * Run with:
- atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class ForceAppStandbyTrackerTest {
+public class AppStateTrackerTest {
 
-    private class ForceAppStandbyTrackerTestable extends ForceAppStandbyTracker {
-        ForceAppStandbyTrackerTestable() {
+    private class AppStateTrackerTestable extends AppStateTracker {
+        AppStateTrackerTestable() {
             super(mMockContext, Looper.getMainLooper());
         }
 
@@ -112,6 +113,11 @@
         }
 
         @Override
+        ActivityManagerInternal injectActivityManagerInternal() {
+            return mMockIActivityManagerInternal;
+        }
+
+        @Override
         PowerManagerInternal injectPowerManagerInternal() {
             return mMockPowerManagerInternal;
         }
@@ -152,6 +158,9 @@
     private IActivityManager mMockIActivityManager;
 
     @Mock
+    private ActivityManagerInternal mMockIActivityManagerInternal;
+
+    @Mock
     private AppOpsManager mMockAppOpsManager;
 
     @Mock
@@ -195,7 +204,7 @@
         return new PowerSaveState.Builder().setBatterySaverEnabled(mPowerSaveMode).build();
     }
 
-    private ForceAppStandbyTrackerTestable newInstance() throws Exception {
+    private AppStateTrackerTestable newInstance() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         when(mMockIAppOpsService.checkOperation(eq(TARGET_OP), anyInt(), anyString()))
@@ -205,12 +214,12 @@
                             AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED;
                 });
 
-        final ForceAppStandbyTrackerTestable instance = new ForceAppStandbyTrackerTestable();
+        final AppStateTrackerTestable instance = new AppStateTrackerTestable();
 
         return instance;
     }
 
-    private void callStart(ForceAppStandbyTrackerTestable instance) throws RemoteException {
+    private void callStart(AppStateTrackerTestable instance) throws RemoteException {
 
         // Set up functions that start() calls.
         when(mMockPowerManagerInternal.getLowPowerState(eq(ServiceType.FORCE_ALL_APPS_STANDBY)))
@@ -223,7 +232,7 @@
         when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
 
         // Call start.
-        instance.start();
+        instance.onSystemServicesReady();
 
         // Capture the listeners.
         ArgumentCaptor<IUidObserver> uidObserverArgumentCaptor =
@@ -287,7 +296,7 @@
     private static final int JOBS_ONLY = 1 << 1;
     private static final int JOBS_AND_ALARMS = ALARMS_ONLY | JOBS_ONLY;
 
-    private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName,
+    private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName,
             int restrictionTypes, boolean exemptFromBatterySaver) {
         assertEquals(((restrictionTypes & JOBS_ONLY) != 0),
                 instance.areJobsRestricted(uid, packageName, exemptFromBatterySaver));
@@ -295,13 +304,13 @@
                 instance.areAlarmsRestricted(uid, packageName, exemptFromBatterySaver));
     }
 
-    private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName,
+    private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName,
             int restrictionTypes) {
         areRestricted(instance, uid, packageName, restrictionTypes,
                 /*exemptFromBatterySaver=*/ false);
     }
 
-    private void areRestrictedWithExemption(ForceAppStandbyTrackerTestable instance,
+    private void areRestrictedWithExemption(AppStateTrackerTestable instance,
             int uid, String packageName, int restrictionTypes) {
         areRestricted(instance, uid, packageName, restrictionTypes,
                 /*exemptFromBatterySaver=*/ true);
@@ -309,7 +318,7 @@
 
     @Test
     public void testAll() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
         assertFalse(instance.isForceAllAppsStandbyEnabled());
@@ -343,6 +352,7 @@
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
 
         mIUidObserver.onUidActive(UID_1);
+        waitUntilMainHandlerDrain();
         areRestricted(instance, UID_1, PACKAGE_1, NONE);
         areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
@@ -350,6 +360,7 @@
         assertFalse(instance.isUidActive(UID_2));
 
         mIUidObserver.onUidGone(UID_1, /*disable=*/ false);
+        waitUntilMainHandlerDrain();
         areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
         areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
@@ -357,11 +368,13 @@
         assertFalse(instance.isUidActive(UID_2));
 
         mIUidObserver.onUidActive(UID_1);
+        waitUntilMainHandlerDrain();
         areRestricted(instance, UID_1, PACKAGE_1, NONE);
         areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
 
         mIUidObserver.onUidIdle(UID_1, /*disable=*/ false);
+        waitUntilMainHandlerDrain();
         areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
         areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
@@ -462,15 +475,20 @@
 
     @Test
     public void testUidStateForeground() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
         mIUidObserver.onUidActive(UID_1);
 
+        waitUntilMainHandlerDrain();
         assertTrue(instance.isUidActive(UID_1));
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
 
+        assertTrue(instance.isUidActiveSynced(UID_1));
+        assertFalse(instance.isUidActiveSynced(UID_2));
+        assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
         assertFalse(instance.isUidInForeground(UID_1));
         assertFalse(instance.isUidInForeground(UID_2));
         assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
@@ -479,10 +497,15 @@
         mIUidObserver.onUidStateChanged(UID_2,
                 ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE, 0);
 
+        waitUntilMainHandlerDrain();
         assertTrue(instance.isUidActive(UID_1));
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
 
+        assertTrue(instance.isUidActiveSynced(UID_1));
+        assertFalse(instance.isUidActiveSynced(UID_2));
+        assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
         assertFalse(instance.isUidInForeground(UID_1));
         assertTrue(instance.isUidInForeground(UID_2));
         assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
@@ -491,6 +514,7 @@
         mIUidObserver.onUidStateChanged(UID_1,
                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
 
+        waitUntilMainHandlerDrain();
         assertTrue(instance.isUidActive(UID_1));
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -501,6 +525,7 @@
 
         mIUidObserver.onUidGone(UID_1, true);
 
+        waitUntilMainHandlerDrain();
         assertFalse(instance.isUidActive(UID_1));
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -511,6 +536,7 @@
 
         mIUidObserver.onUidIdle(UID_2, true);
 
+        waitUntilMainHandlerDrain();
         assertFalse(instance.isUidActive(UID_1));
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -522,6 +548,7 @@
         mIUidObserver.onUidStateChanged(UID_1,
                 ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0);
 
+        waitUntilMainHandlerDrain();
         assertFalse(instance.isUidActive(UID_1));
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -533,18 +560,39 @@
         mIUidObserver.onUidStateChanged(UID_1,
                 ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0);
 
+        waitUntilMainHandlerDrain();
         assertFalse(instance.isUidActive(UID_1));
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
 
+        assertFalse(instance.isUidActiveSynced(UID_1));
+        assertFalse(instance.isUidActiveSynced(UID_2));
+        assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
         assertFalse(instance.isUidInForeground(UID_1));
         assertFalse(instance.isUidInForeground(UID_2));
         assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+        // The result from AMI.isUidActive() only affects isUidActiveSynced().
+        when(mMockIActivityManagerInternal.isUidActive(anyInt())).thenReturn(true);
+
+        assertFalse(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+        assertTrue(instance.isUidActiveSynced(UID_1));
+        assertTrue(instance.isUidActiveSynced(UID_2));
+        assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
+        assertFalse(instance.isUidInForeground(UID_1));
+        assertFalse(instance.isUidInForeground(UID_2));
+        assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
     }
 
     @Test
     public void testExempt() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
         assertFalse(instance.isForceAllAppsStandbyEnabled());
@@ -610,7 +658,7 @@
     }
 
     public void loadPersistedAppOps() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
 
         final List<PackageOps> ops = new ArrayList<>();
 
@@ -620,7 +668,7 @@
                 AppOpsManager.OP_ACCESS_NOTIFICATIONS,
                 AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
         entries.add(new AppOpsManager.OpEntry(
-                ForceAppStandbyTracker.TARGET_OP,
+                AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
 
         ops.add(new PackageOps(PACKAGE_1, UID_1, entries));
@@ -628,7 +676,7 @@
         //--------------------------------------------------
         entries = new ArrayList<>();
         entries.add(new AppOpsManager.OpEntry(
-                ForceAppStandbyTracker.TARGET_OP,
+                AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
 
         ops.add(new PackageOps(PACKAGE_2, UID_2, entries));
@@ -636,7 +684,7 @@
         //--------------------------------------------------
         entries = new ArrayList<>();
         entries.add(new AppOpsManager.OpEntry(
-                ForceAppStandbyTracker.TARGET_OP,
+                AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_ALLOWED, 0, 0, 0, 0, null));
 
         ops.add(new PackageOps(PACKAGE_1, UID_10_1, entries));
@@ -644,7 +692,7 @@
         //--------------------------------------------------
         entries = new ArrayList<>();
         entries.add(new AppOpsManager.OpEntry(
-                ForceAppStandbyTracker.TARGET_OP,
+                AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
         entries.add(new AppOpsManager.OpEntry(
                 AppOpsManager.OP_ACCESS_NOTIFICATIONS,
@@ -677,10 +725,10 @@
 
     @Test
     public void testPowerSaveListener() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
-        ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class);
+        AppStateTracker.Listener l = mock(AppStateTracker.Listener.class);
         instance.addListener(l);
 
         // Power save on.
@@ -720,10 +768,10 @@
 
     @Test
     public void testAllListeners() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
-        ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class);
+        AppStateTracker.Listener l = mock(AppStateTracker.Listener.class);
         instance.addListener(l);
 
         // -------------------------------------------------------------------------
@@ -1031,12 +1079,14 @@
 
     @Test
     public void testUserRemoved() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
         mIUidObserver.onUidActive(UID_1);
         mIUidObserver.onUidActive(UID_10_1);
 
+        waitUntilMainHandlerDrain();
+
         setAppOps(UID_2, PACKAGE_2, true);
         setAppOps(UID_10_2, PACKAGE_2, true);
 
@@ -1064,7 +1114,7 @@
         // This is a small battery device
         mIsSmallBatteryDevice = true;
 
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
         assertFalse(instance.isForceAllAppsStandbyEnabled());
 
@@ -1090,7 +1140,7 @@
         // Not a small battery device, so plugged in status should not affect forced app standby
         mIsSmallBatteryDevice = false;
 
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
         assertFalse(instance.isForceAllAppsStandbyEnabled());
 
@@ -1139,7 +1189,7 @@
 
     private void checkAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray, boolean expected) {
         assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
-                expected, ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(prevArray, newArray));
+                expected, AppStateTracker.isAnyAppIdUnwhitelisted(prevArray, newArray));
 
         // Also test isAnyAppIdUnwhitelistedSlow.
         assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
@@ -1171,7 +1221,7 @@
             final int[] array2 = makeRandomArray();
 
             final boolean expected = isAnyAppIdUnwhitelistedSlow(array1, array2);
-            final boolean actual = ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(array1, array2);
+            final boolean actual = AppStateTracker.isAnyAppIdUnwhitelisted(array1, array2);
 
             assertEquals("Input: " + Arrays.toString(array1) + " " + Arrays.toString(array2),
                     expected, actual);
diff --git a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
new file mode 100644
index 0000000..6e76b67
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.runner.AndroidJUnit4;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Unit tests for {@link WatchdogDiagnostics}
+ */
+@RunWith(AndroidJUnit4.class)
+public class WatchdogDiagnosticsTest {
+
+    private static class TestThread1 extends Thread {
+        Object lock1;
+        Object lock2;
+        volatile boolean inB = false;
+
+        public TestThread1(Object lock1, Object lock2) {
+            super("TestThread1");
+            this.lock1 = lock1;
+            this.lock2 = lock2;
+        }
+
+        @Override
+        public void run() {
+            a();
+        }
+
+        private void a() {
+            synchronized(lock1) {
+                b();
+            }
+        }
+
+        private void b() {
+            inB = true;
+            synchronized(lock2) {
+                // Nothing.
+            }
+        }
+    }
+
+    private static class TestThread2 extends Thread {
+        Object lock1;
+        Object lock2;
+        volatile boolean inY = false;
+
+        public TestThread2(Object lock1, Object lock2) {
+            super("TestThread2");
+            this.lock1 = lock1;
+            this.lock2 = lock2;
+        }
+
+        @Override
+        public void run() {
+            x();
+        }
+
+        private void x() {
+            synchronized(lock1) {
+                y();
+            }
+        }
+
+        private void y() {
+            synchronized(lock2) {
+                inY = true;
+                try {
+                    lock2.wait();
+                } catch (Exception exc) {
+                    throw new RuntimeException(exc);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void printAnnotatedStack() throws Exception {
+        // Preparation.
+
+        Object heldLock1 = new Object();
+        Object heldLock2 = 0;
+        Object waitLock = "123";
+
+        TestThread1 thread1 = new TestThread1(heldLock1, heldLock2);
+        TestThread2 thread2 = new TestThread2(heldLock2, waitLock);
+
+        // Start the second thread, ensure it grabs heldLock2.
+        thread2.start();
+        while(!thread2.inY) {
+            Thread.yield();
+        }
+
+        // Start the first thread, ensure it made progress.
+        thread1.start();
+        while(!thread1.inB) {
+            Thread.yield();
+        }
+
+        // Now wait till both are no longer in runnable state.
+        while (thread1.getState() == Thread.State.RUNNABLE) {
+            Thread.yield();
+        }
+        while (thread2.getState() == Thread.State.RUNNABLE) {
+            Thread.yield();
+        }
+
+        // Now do the test.
+        StringWriter stringBuffer = new StringWriter();
+        PrintWriter print = new PrintWriter(stringBuffer, true);
+
+        {
+            WatchdogDiagnostics.printAnnotatedStack(thread1, print);
+
+            String output = stringBuffer.toString();
+            String expected =
+                    "TestThread1 annotated stack trace:\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread1.b(" +
+                            "WatchdogDiagnosticsTest.java:59)\n" +
+                    "    - waiting to lock <HASH> (a java.lang.Integer)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread1.a(" +
+                            "WatchdogDiagnosticsTest.java:53)\n" +
+                    "    - locked <HASH> (a java.lang.Object)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread1.run(" +
+                            "WatchdogDiagnosticsTest.java:48)\n";
+            assertEquals(expected, filterHashes(output));
+        }
+
+        stringBuffer.getBuffer().setLength(0);
+
+        {
+            WatchdogDiagnostics.printAnnotatedStack(thread2, print);
+
+            String output = stringBuffer.toString();
+            String expected =
+                    "TestThread2 annotated stack trace:\n" +
+                    "    at java.lang.Object.wait(Native Method)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread2.y(" +
+                            "WatchdogDiagnosticsTest.java:91)\n" +
+                    "    - locked <HASH> (a java.lang.String)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread2.x(" +
+                            "WatchdogDiagnosticsTest.java:83)\n" +
+                    "    - locked <HASH> (a java.lang.Integer)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread2.run(" +
+                            "WatchdogDiagnosticsTest.java:78)\n";
+            assertEquals(expected, filterHashes(output));
+        }
+
+        // Let the threads finish.
+        synchronized (waitLock) {
+            waitLock.notifyAll();
+        }
+
+        thread1.join();
+        thread2.join();
+    }
+
+    /**
+     * A filter function that removes hash codes (which will change between tests and cannot be
+     * controlled.)
+     * <p>
+     * Note: leaves "<HASH>" to indicate that something was replaced.
+     */
+    private static String filterHashes(String t) {
+        return t.replaceAll("<0x[0-9a-f]{8}>", "<HASH>");
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index fc17da8..2378e6d 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -25,6 +27,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
 
+import android.app.ActivityManager;
+import android.app.WaitResult;
 import android.content.ComponentName;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
@@ -45,7 +49,7 @@
  * Tests for the {@link ActivityStackSupervisor} class.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests
+ *  atest FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests
  */
 @MediumTest
 @Presubmit
@@ -146,4 +150,34 @@
 
         assertFalse(mSupervisor.mStoppingActivities.contains(firstActivity));
     }
+
+    /**
+     * Ensures that waiting results are notified of launches.
+     */
+    @Test
+    public void testReportWaitingActivityLaunchedIfNeeded() throws Exception {
+        final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
+                .setStack(mFullscreenStack).build();
+
+        // #notifyAll will be called on the ActivityManagerService. we must hold the object lock
+        // when this happens.
+        synchronized (mSupervisor.mService) {
+            final WaitResult taskToFrontWait = new WaitResult();
+            mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait);
+            mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT);
+
+            assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty());
+            assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT);
+            assertEquals(taskToFrontWait.who, null);
+
+            final WaitResult deliverToTopWait = new WaitResult();
+            mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait);
+            mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity,
+                    START_DELIVERED_TO_TOP);
+
+            assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty());
+            assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP);
+            assertEquals(deliverToTopWait.who, firstActivity.realActivity);
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
new file mode 100644
index 0000000..a7e3810
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static com.android.server.am.MemoryStatUtil.parseMemoryStat;
+import static com.android.server.am.MemoryStatUtil.MemoryStat;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MemoryStatUtilTest {
+  private String MEMORY_STAT_CONTENTS = String.join(
+      "\n",
+      "cache 96", // keep different from total_cache to catch reading wrong value
+      "rss 97", // keep different from total_rss to catch reading wrong value
+      "rss_huge 0",
+      "mapped_file 524288",
+      "writeback 0",
+      "swap 95", // keep different from total_rss to catch reading wrong value
+      "pgpgin 16717",
+      "pgpgout 5037",
+      "pgfault 99", // keep different from total_pgfault to catch reading wrong value
+      "pgmajfault 98", // keep different from total_pgmajfault to catch reading wrong value
+      "inactive_anon 503808",
+      "active_anon 46309376",
+      "inactive_file 876544",
+      "active_file 81920",
+      "unevictable 0",
+      "hierarchical_memory_limit 18446744073709551615",
+      "hierarchical_memsw_limit 18446744073709551615",
+      "total_cache 4",
+      "total_rss 3",
+      "total_rss_huge 0",
+      "total_mapped_file 524288",
+      "total_writeback 0",
+      "total_swap 5",
+      "total_pgpgin 16717",
+      "total_pgpgout 5037",
+      "total_pgfault 1",
+      "total_pgmajfault 2",
+      "total_inactive_anon 503808",
+      "total_active_anon 46309376",
+      "total_inactive_file 876544",
+      "total_active_file 81920",
+      "total_unevictable 0");
+
+
+  @Test
+  public void testParseMemoryStat_parsesCorrectValues() throws Exception {
+    MemoryStat stat = parseMemoryStat(MEMORY_STAT_CONTENTS);
+    assertEquals(stat.pgfault, 1);
+    assertEquals(stat.pgmajfault, 2);
+    assertEquals(stat.rssInBytes, 3);
+    assertEquals(stat.cacheInBytes, 4);
+    assertEquals(stat.swapInBytes, 5);
+  }
+
+  @Test
+  public void testParseMemoryStat_emptyMemoryStatContents() throws Exception {
+    MemoryStat stat = parseMemoryStat("");
+    assertEquals(stat.pgfault, 0);
+    assertEquals(stat.pgmajfault, 0);
+    assertEquals(stat.rssInBytes, 0);
+    assertEquals(stat.cacheInBytes, 0);
+    assertEquals(stat.swapInBytes, 0);
+
+    stat = parseMemoryStat(null);
+    assertEquals(stat.pgfault, 0);
+    assertEquals(stat.pgmajfault, 0);
+    assertEquals(stat.rssInBytes, 0);
+    assertEquals(stat.cacheInBytes, 0);
+    assertEquals(stat.swapInBytes, 0);
+  }
+}
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 00e27c9..ab0bfefb 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -447,5 +447,8 @@
             return new TransferOwnershipMetadataManager(
                     new TransferOwnershipMetadataManagerTest.MockInjector());
         }
+
+        @Override
+        public void runCryptoSelfTest() {}
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index ce5ee13..e40e3a4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -275,7 +275,7 @@
     }
 
     @Test
-    public void run_sendsEncryptedKeysIfAvailableToSync() throws Exception {
+    public void run_sendsEncryptedKeysIfAvailableToSync_withRawPublicKey() throws Exception {
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
 
@@ -323,6 +323,26 @@
     }
 
     @Test
+    public void run_sendsEncryptedKeysIfAvailableToSync_withCertPath() throws Exception {
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TestData.CERT_PATH_1);
+        mRecoverableKeyStoreDb.setServerParams(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
+        when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
+        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+
+        mKeySyncTask.run();
+
+        KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
+        List<WrappedApplicationKey> applicationKeys = keyChainSnapshot.getWrappedApplicationKeys();
+        assertThat(applicationKeys).hasSize(1);
+        assertThat(keyChainSnapshot.getTrustedHardwarePublicKey())
+                .isEqualTo(SecureBox.encodePublicKey(
+                        TestData.CERT_PATH_1.getCertificates().get(0).getPublicKey()));
+    }
+
+    @Test
     public void run_setsCorrectSnapshotVersion() throws Exception {
         mRecoverableKeyStoreDb.setRecoveryServicePublicKey(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, mKeyPair.getPublic());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index f9ffccd..0f0e3f3 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -255,6 +255,9 @@
         when(mKeyStoreProxy
                 .containsAlias("com.android.server.locksettings.recoverablekeystore/"
                         + "platform/42/1/decrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/encrypt")).thenReturn(true);
 
         mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
 
@@ -264,6 +267,56 @@
     }
 
     @Test
+    public void getDecryptKey_generatesNewKeyIfOldDecryptKeyWasRemoved() throws Exception {
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/encrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/decrypt")).thenReturn(false); // was removed
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/encrypt")).thenReturn(true); // new version is available
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/decrypt")).thenReturn(true);
+
+        mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
+
+        verify(mKeyStoreProxy).containsAlias(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"));
+        // Attempt to get regenerated key.
+        verify(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+                any());
+    }
+
+    @Test
+    public void getDecryptKey_generatesNewKeyIfOldEncryptKeyWasRemoved() throws Exception {
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/encrypt")).thenReturn(false); // was removed
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/decrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/encrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/decrypt")).thenReturn(true);
+
+        mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
+
+        verify(mKeyStoreProxy).containsAlias(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"));
+        // Attempt to get regenerated key.
+        verify(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+                any());
+    }
+
+    @Test
     public void getEncryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception {
         doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
                 eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"),
@@ -274,7 +327,13 @@
                         + "platform/42/1/encrypt")).thenReturn(true);
         when(mKeyStoreProxy
                 .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/decrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
                         + "platform/42/2/encrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/decrypt")).thenReturn(true);
 
         mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
 
@@ -295,11 +354,16 @@
 
         when(mKeyStoreProxy
                 .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/decrypt")).thenReturn(false); // was removed.
-
+                        + "platform/42/1/encrypt")).thenReturn(true);
         when(mKeyStoreProxy
                 .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/2/decrypt")).thenReturn(true); // new version is available
+                        + "platform/42/1/decrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/encrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/decrypt")).thenReturn(true);
 
         mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
 
@@ -312,14 +376,45 @@
     }
 
     @Test
-    public void getEncryptKey_generatesNewKeyIfOldWasRemoved() throws Exception {
+    public void getEncryptKey_generatesNewKeyIfDecryptKeyIsUnrecoverable() throws Exception {
+        doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                any());
         when(mKeyStoreProxy
                 .containsAlias("com.android.server.locksettings.recoverablekeystore/"
-                        + "platform/42/1/encrypt")).thenReturn(false); // was removed.
-
+                        + "platform/42/1/encrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/decrypt")).thenReturn(false); // was removed
         when(mKeyStoreProxy
                 .containsAlias("com.android.server.locksettings.recoverablekeystore/"
                         + "platform/42/2/encrypt")).thenReturn(true); // new version is available
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/decrypt")).thenReturn(true);
+
+        mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
+
+        // Attempt to get regenerated key.
+        verify(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"),
+                any());
+    }
+
+    @Test
+    public void getEncryptKey_generatesNewKeyIfOldDecryptKeyWasRemoved() throws Exception {
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/encrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/decrypt")).thenReturn(false); // was removed
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/encrypt")).thenReturn(true); // new version is available
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/decrypt")).thenReturn(true);
 
         mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
 
@@ -332,10 +427,38 @@
     }
 
     @Test
-    public void getEncryptKey_getsEndryptKeyWithCorrectAlias() throws Exception {
+    public void getEncryptKey_generatesNewKeyIfOldEncryptKeyWasRemoved() throws Exception {
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/encrypt")).thenReturn(false); // was removed
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/decrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/encrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/2/decrypt")).thenReturn(true);
+
+        mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
+
+        verify(mKeyStoreProxy).containsAlias(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"));
+        // Attempt to get regenerated key.
+        verify(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"),
+                any());
+    }
+
+    @Test
+    public void getEncryptKey_getsEncryptKeyWithCorrectAlias() throws Exception {
         when(mKeyStoreProxy
                 .containsAlias("com.android.server.locksettings.recoverablekeystore/"
                         + "platform/42/1/encrypt")).thenReturn(true);
+        when(mKeyStoreProxy
+                .containsAlias("com.android.server.locksettings.recoverablekeystore/"
+                        + "platform/42/1/decrypt")).thenReturn(true);
 
         mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 473a813..a523b86 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -125,6 +125,7 @@
     private static final byte[] RECOVERY_RESPONSE_HEADER =
             "V1 reencrypted_recovery_key".getBytes(StandardCharsets.UTF_8);
     private static final String TEST_ALIAS = "nick";
+    private static final String TEST_ALIAS2 = "bob";
     private static final int RECOVERABLE_KEY_SIZE_BYTES = 32;
     private static final int GENERATION_ID = 1;
     private static final byte[] NONCE = getUtf8Bytes("nonce");
@@ -237,15 +238,81 @@
     }
 
     @Test
-    public void initRecoveryService_updatesShouldCreateSnapshot() throws Exception {
+    public void initRecoveryService_succeeds() throws Exception {
         int uid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
-        // Sync is not needed.
+        long certSerial = 1000L;
+        mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial));
+
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
+                TestData.CERT_PATH_1);
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isEqualTo(
+                certSerial);
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull();
+    }
+
+    @Test
+    public void initRecoveryService_updatesWithLargerSerial() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        long certSerial = 1000L;
+
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial));
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial + 1));
+
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid))
+                .isEqualTo(certSerial + 1);
+    }
+
+    @Test
+    public void initRecoveryService_ignoresSmallerSerial() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        long certSerial = 1000L;
+
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial));
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial - 1));
+
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid))
+                .isEqualTo(certSerial);
+    }
+
+    @Test
+    public void initRecoveryService_ignoresTheSameSerial() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        long certSerial = 1000L;
+
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial));
+        mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
+        mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS,
+                TestData.getCertXmlWithSerial(certSerial));
+
+        // If the second update succeeds, getShouldCreateSnapshot() will return true.
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isFalse();
+    }
+
+    @Test
+    public void initRecoveryService_succeedsWithRawPublicKey() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
         mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
 
         mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, TEST_PUBLIC_KEY);
 
         assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isNull();
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isNull();
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNotNull();
     }
 
     @Test
@@ -343,26 +410,6 @@
     }
 
     @Test
-    public void startRecoverySession_throwsIfBadKey() throws Exception {
-        try {
-            mRecoverableKeyStoreManager.startRecoverySession(
-                    TEST_SESSION_ID,
-                    getUtf8Bytes("0"),
-                    TEST_VAULT_PARAMS,
-                    TEST_VAULT_CHALLENGE,
-                    ImmutableList.of(
-                            new KeyChainProtectionParams(
-                                    TYPE_LOCKSCREEN,
-                                    UI_FORMAT_PASSWORD,
-                                    KeyDerivationParams.createSha256Params(TEST_SALT),
-                                    TEST_SECRET)));
-            fail("should have thrown");
-        } catch (ServiceSpecificException e) {
-            assertEquals("Not a valid X509 key", e.getMessage());
-        }
-    }
-
-    @Test
     public void startRecoverySession_throwsIfPublicKeysMismatch() throws Exception {
         byte[] vaultParams = TEST_VAULT_PARAMS.clone();
         vaultParams[1] ^= (byte) 1;  // Flip 1 bit
@@ -424,7 +471,7 @@
     }
 
     @Test
-    public void recoverKeys_throwsIfFailedToDecryptAnApplicationKey() throws Exception {
+    public void recoverKeys_throwsIfFailedToDecryptAllApplicationKeys() throws Exception {
         mRecoverableKeyStoreManager.startRecoverySession(
                 TEST_SESSION_ID,
                 TEST_PUBLIC_KEY,
@@ -442,7 +489,7 @@
                 keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey);
         WrappedApplicationKey badApplicationKey = new WrappedApplicationKey(
                 TEST_ALIAS,
-                randomBytes(32));
+                encryptedApplicationKey(randomRecoveryKey(), randomBytes(32)));
 
         try {
             mRecoverableKeyStoreManager.recoverKeys(
@@ -451,7 +498,7 @@
                     /*applicationKeys=*/ ImmutableList.of(badApplicationKey));
             fail("should have thrown");
         } catch (ServiceSpecificException e) {
-            assertThat(e.getMessage()).startsWith("Failed to recover key with alias 'nick'");
+            assertThat(e.getMessage()).startsWith("Failed to recover any of the application keys");
         }
     }
 
@@ -487,6 +534,44 @@
     }
 
     @Test
+    public void recoverKeys_worksOnOtherApplicationKeysIfOneDecryptionFails() throws Exception {
+        mRecoverableKeyStoreManager.startRecoverySession(
+                TEST_SESSION_ID,
+                TEST_PUBLIC_KEY,
+                TEST_VAULT_PARAMS,
+                TEST_VAULT_CHALLENGE,
+                ImmutableList.of(new KeyChainProtectionParams(
+                        TYPE_LOCKSCREEN,
+                        UI_FORMAT_PASSWORD,
+                        KeyDerivationParams.createSha256Params(TEST_SALT),
+                        TEST_SECRET)));
+        byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID)
+                .getKeyClaimant();
+        SecretKey recoveryKey = randomRecoveryKey();
+        byte[] encryptedClaimResponse = encryptClaimResponse(
+                keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey);
+
+        byte[] applicationKeyBytes1 = randomBytes(32);
+        byte[] applicationKeyBytes2 = randomBytes(32);
+
+        WrappedApplicationKey applicationKey1 = new WrappedApplicationKey(
+                TEST_ALIAS,
+                // Use a different recovery key here, so the decryption will fail
+                encryptedApplicationKey(randomRecoveryKey(), applicationKeyBytes1));
+        WrappedApplicationKey applicationKey2 = new WrappedApplicationKey(
+                TEST_ALIAS2,
+                encryptedApplicationKey(recoveryKey, applicationKeyBytes2));
+
+        Map<String, byte[]> recoveredKeys = mRecoverableKeyStoreManager.recoverKeys(
+                TEST_SESSION_ID,
+                encryptedClaimResponse,
+                ImmutableList.of(applicationKey1, applicationKey2));
+
+        assertThat(recoveredKeys).hasSize(1);
+        assertThat(recoveredKeys.get(TEST_ALIAS2)).isEqualTo(applicationKeyBytes2);
+    }
+
+    @Test
     public void setSnapshotCreatedPendingIntent() throws Exception {
         int uid = Binder.getCallingUid();
         PendingIntent intent = PendingIntent.getBroadcast(
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
new file mode 100644
index 0000000..0e4f91b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
@@ -0,0 +1,202 @@
+package com.android.server.locksettings.recoverablekeystore;
+
+import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateFactory;
+
+public final class TestData {
+
+    private static final String CERT_PATH_ENCODING = "PkiPath";
+
+    private static final String CERT_PATH_1_BASE64 = ""
+            + "MIIIPzCCBS8wggMXoAMCAQICAhAAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMM"
+            + "FUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDMwMDQyMDNaFw0yODAyMDEw"
+            + "MDQyMDNaMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRlcm1l"
+            + "ZGlhdGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDckHib0X6rQyDq"
+            + "k4519b5du0OrCPk30XXKwz+Hz5y4cGZaWKGcHOHWS2X9YApRzO00/EbvFkWVUTVG"
+            + "27wJ54V+C3HHSOAUWHhEgfFWvvHwfn9HTDx1BEk79aQqJ7DuJ06Sn/WOiMtKVAT5"
+            + "6Mi8mekBxpMOrdZqwlcLrUVsZxEHsw5/ceZu4cSWzc7SzlnbNK1cCgyRDGqWf6Gp"
+            + "3hGE86kUOtM1i95RgUIpw+w/z0wxpF6kIyQTjK+KjiYH/RBOJIEcm6sSWZlMotKL"
+            + "Sn2lhf+XL8yUxExIHTosfeb077QWW4w2BB2NZM4wPAO3w4aw33FNigDQc2SQYmnU"
+            + "EYmIcD8kx77+JWCgCxBJc2zTHXtBxWuXAQ+iegt8RO+QD97pd6XKM9xPsAOkcWLp"
+            + "79o+AJol4P5fwvgYM69mM4lwH12v86RI4aptPQOag0KDIHXyKbjaQyAgv30l4KkD"
+            + "pf2uWODhOOTwNbVPYUm3sYUlhBcbyhTk8YqN9sPU4QAao5sKTAYZgB/mlheQypTU"
+            + "wyvqz6bRzGehVB3ltP9gCyKdI04VXEUuUBWk3STyV2REQen5/LKAns6v11Cz22Zr"
+            + "EdCvNLgetnyV7CJsOa/wD/GiUWL2Ta7pzshi9ahJqrrcNPRbAzOLcNKZkFexhzPp"
+            + "onuo/pNrcaRda1frepXxVkmbsgOULwIDAQABo2YwZDAdBgNVHQ4EFgQUd6md2hCP"
+            + "lmf3VkEX5FfDxKBLbaAwHwYDVR0jBBgwFoAUm2X66jmB+eBCaZHSjGYzHM/x6fgw"
+            + "EgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL"
+            + "BQADggIBAFgShhuW+WVTowN080PLf0TWPlHACHHUPghf7rFGxgUjJypCloE84Beg"
+            + "3ROpP5l19CDqZ9OyPzA1z6VAzeGXyFhZvby7G2tZDBRP/v0u8pnSAdC5F8l8Vh2Y"
+            + "GdgE3sZD25vpdBi7P0Ef6LYQetOJXn86PqgmgW1F6lzxDjKCsi9kpeU0AWwDdOVg"
+            + "748wku50o8UEzsVwxzFd9toGlge/nn3FH5J7EuGzAlFwToHqpwTVEegaAd0l9mr5"
+            + "+rS7Urd3X80BHDqCBcXE7Uqbtzw5Y+lmowMCnW0kFN02dC9dLt2c9IxC+9sPIA5e"
+            + "TkrZBkrkTVRGLj2r29j7nC9m5VaKcBqcLZDWy8pRna8yaZprgNdE8d/WTY9nVsic"
+            + "09N8zNF5Q0bhhWa3QonlB9XW5ZqDguiclvn+5TtREzSAtSOyxM+gfG3l0wjOywIk"
+            + "1aFa52RaqAWPL67KOM6G3vKNpMnW5hrmHrijuKxiarGIoZfkZMR5ijK0uFgv3/p6"
+            + "NHL/YQBaHJJhkKet5ThiPxwW9+1k/ZcXVeY26Xh+22Gp/8to7ZW8guPPiN1hfpD+"
+            + "7f1IdSmHDrsZQQ7bfzV0bppsyNNB7e2Ecyw+GQny27nytBLJDGdRBurbwQvzppQO"
+            + "6Qmlk0rfCszh7bGCoCQNxXmuDsQ5BC+pQUqJplTqds1smyi29xs3MIIDCDCB8aAD"
+            + "AgECAgYBYVkuU0cwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29vZ2xlIENy"
+            + "eXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAyMDIwMTAxMDNaFw0yMDAy"
+            + "MDMwMTAxMDNaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnN0"
+            + "YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfButJT+htocB40B"
+            + "tDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl4b0hRH54Uvow"
+            + "DQYJKoZIhvcNAQELBQADggIBAJ3PM4GNTNYzMr8E/IGsWZkLx9ARAALqBXz7As59"
+            + "F8y5UcLMqkXD/ewOfBZgF5VzjlAePyE/wSw0wc3xzvrDVVDiZaMBW1DVtSlbn25q"
+            + "00m00mmcUeyyMc7vuRkPoDshIMQTc8+U3yyYsVScSV+B4TvSx6wPZ9FpwnSPjVPD"
+            + "2GkqeMTWszuxNVEWq0wmm0K5lMaX0hfiak+4/IZxOPPGIg2py1KLA/H2gdyeqyJR"
+            + "cAsyEkfwLlushR5T9abSiPsIRcYoX8Ck8Lt+gQ7RCMefnm8CoOBKIfcjuV4PGOoe"
+            + "Xrq57VR5SsOeT07bL+D7B+mohYFI1v2G3WClAE8XgM3q8NoFFvaYmoi0+UcTduil"
+            + "47qvozjdNmjRAgu5j6vMKXEdG5Rqsja8hy0LG1hwfnR0gNiwcZ5Le3GyFnwH1Igq"
+            + "vsGOUM0ohnDUAU0zJY7nG0QYrDYe5/QPRNhWDpYkwHDiqcG28wIQCOTPAZHU2EoS"
+            + "KjSqEG2l0S5JPcor2BEde9ikSkcmK8foxlOHIdFn+n7RNF3bSEfKn1IOuXoqPidm"
+            + "eBQLevqG8KTy/C9CHqlaCNlpbIA9h+WVfsjm2s6JXBu0YbcfoIbJAmSuZVeqB/+Z"
+            + "Vvpfiad/jQWzY49fRnsSmV7VveTFPGtJxC89EadbMAinMZo+72u59319RqN5wsP2"
+            + "Zus8";
+    private static String CERT_PATH_2_BASE64 = ""
+            + "MIIFMzCCBS8wggMXoAMCAQICAhAAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMM"
+            + "FUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDMwMDQyMDNaFw0yODAyMDEw"
+            + "MDQyMDNaMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRlcm1l"
+            + "ZGlhdGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDckHib0X6rQyDq"
+            + "k4519b5du0OrCPk30XXKwz+Hz5y4cGZaWKGcHOHWS2X9YApRzO00/EbvFkWVUTVG"
+            + "27wJ54V+C3HHSOAUWHhEgfFWvvHwfn9HTDx1BEk79aQqJ7DuJ06Sn/WOiMtKVAT5"
+            + "6Mi8mekBxpMOrdZqwlcLrUVsZxEHsw5/ceZu4cSWzc7SzlnbNK1cCgyRDGqWf6Gp"
+            + "3hGE86kUOtM1i95RgUIpw+w/z0wxpF6kIyQTjK+KjiYH/RBOJIEcm6sSWZlMotKL"
+            + "Sn2lhf+XL8yUxExIHTosfeb077QWW4w2BB2NZM4wPAO3w4aw33FNigDQc2SQYmnU"
+            + "EYmIcD8kx77+JWCgCxBJc2zTHXtBxWuXAQ+iegt8RO+QD97pd6XKM9xPsAOkcWLp"
+            + "79o+AJol4P5fwvgYM69mM4lwH12v86RI4aptPQOag0KDIHXyKbjaQyAgv30l4KkD"
+            + "pf2uWODhOOTwNbVPYUm3sYUlhBcbyhTk8YqN9sPU4QAao5sKTAYZgB/mlheQypTU"
+            + "wyvqz6bRzGehVB3ltP9gCyKdI04VXEUuUBWk3STyV2REQen5/LKAns6v11Cz22Zr"
+            + "EdCvNLgetnyV7CJsOa/wD/GiUWL2Ta7pzshi9ahJqrrcNPRbAzOLcNKZkFexhzPp"
+            + "onuo/pNrcaRda1frepXxVkmbsgOULwIDAQABo2YwZDAdBgNVHQ4EFgQUd6md2hCP"
+            + "lmf3VkEX5FfDxKBLbaAwHwYDVR0jBBgwFoAUm2X66jmB+eBCaZHSjGYzHM/x6fgw"
+            + "EgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL"
+            + "BQADggIBAFgShhuW+WVTowN080PLf0TWPlHACHHUPghf7rFGxgUjJypCloE84Beg"
+            + "3ROpP5l19CDqZ9OyPzA1z6VAzeGXyFhZvby7G2tZDBRP/v0u8pnSAdC5F8l8Vh2Y"
+            + "GdgE3sZD25vpdBi7P0Ef6LYQetOJXn86PqgmgW1F6lzxDjKCsi9kpeU0AWwDdOVg"
+            + "748wku50o8UEzsVwxzFd9toGlge/nn3FH5J7EuGzAlFwToHqpwTVEegaAd0l9mr5"
+            + "+rS7Urd3X80BHDqCBcXE7Uqbtzw5Y+lmowMCnW0kFN02dC9dLt2c9IxC+9sPIA5e"
+            + "TkrZBkrkTVRGLj2r29j7nC9m5VaKcBqcLZDWy8pRna8yaZprgNdE8d/WTY9nVsic"
+            + "09N8zNF5Q0bhhWa3QonlB9XW5ZqDguiclvn+5TtREzSAtSOyxM+gfG3l0wjOywIk"
+            + "1aFa52RaqAWPL67KOM6G3vKNpMnW5hrmHrijuKxiarGIoZfkZMR5ijK0uFgv3/p6"
+            + "NHL/YQBaHJJhkKet5ThiPxwW9+1k/ZcXVeY26Xh+22Gp/8to7ZW8guPPiN1hfpD+"
+            + "7f1IdSmHDrsZQQ7bfzV0bppsyNNB7e2Ecyw+GQny27nytBLJDGdRBurbwQvzppQO"
+            + "6Qmlk0rfCszh7bGCoCQNxXmuDsQ5BC+pQUqJplTqds1smyi29xs3";
+
+    private static final String THM_CERT_XML_BEFORE_SERIAL = ""
+            + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+            + "<certificates>\n"
+            + "  <metadata>\n"
+            + "    <serial>\n";
+    private static final String THM_CERT_XML_AFTER_SERIAL = ""
+            + "    </serial>\n"
+            + "    <creation-time>\n"
+            + "      1515697631\n"
+            + "    </creation-time>\n"
+            + "    <refresh-interval>\n"
+            + "      2592000\n"
+            + "    </refresh-interval>\n"
+            + "    <previous>\n"
+            + "      <serial>\n"
+            + "        0\n"
+            + "      </serial>\n"
+            + "      <hash>\n"
+            + "        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\n"
+            + "      </hash>\n"
+            + "    </previous>\n"
+            + "  </metadata>\n"
+            + "  <intermediates>\n"
+            + "    <cert>\n"
+            + "      MIIFLzCCAxegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v\n"
+            + "      Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDIwMzAwNDIwM1oXDTI4MDIwMTAwNDIw\n"
+            + "      M1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0\n"
+            + "      ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANyQeJvRfqtDIOqTjnX1\n"
+            + "      vl27Q6sI+TfRdcrDP4fPnLhwZlpYoZwc4dZLZf1gClHM7TT8Ru8WRZVRNUbbvAnn\n"
+            + "      hX4LccdI4BRYeESB8Va+8fB+f0dMPHUESTv1pConsO4nTpKf9Y6Iy0pUBPnoyLyZ\n"
+            + "      6QHGkw6t1mrCVwutRWxnEQezDn9x5m7hxJbNztLOWds0rVwKDJEMapZ/oaneEYTz\n"
+            + "      qRQ60zWL3lGBQinD7D/PTDGkXqQjJBOMr4qOJgf9EE4kgRybqxJZmUyi0otKfaWF\n"
+            + "      /5cvzJTETEgdOix95vTvtBZbjDYEHY1kzjA8A7fDhrDfcU2KANBzZJBiadQRiYhw\n"
+            + "      PyTHvv4lYKALEElzbNMde0HFa5cBD6J6C3xE75AP3ul3pcoz3E+wA6RxYunv2j4A\n"
+            + "      miXg/l/C+Bgzr2YziXAfXa/zpEjhqm09A5qDQoMgdfIpuNpDICC/fSXgqQOl/a5Y\n"
+            + "      4OE45PA1tU9hSbexhSWEFxvKFOTxio32w9ThABqjmwpMBhmAH+aWF5DKlNTDK+rP\n"
+            + "      ptHMZ6FUHeW0/2ALIp0jThVcRS5QFaTdJPJXZERB6fn8soCezq/XULPbZmsR0K80\n"
+            + "      uB62fJXsImw5r/AP8aJRYvZNrunOyGL1qEmqutw09FsDM4tw0pmQV7GHM+mie6j+\n"
+            + "      k2txpF1rV+t6lfFWSZuyA5QvAgMBAAGjZjBkMB0GA1UdDgQWBBR3qZ3aEI+WZ/dW\n"
+            + "      QRfkV8PEoEttoDAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DASBgNV\n"
+            + "      HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\n"
+            + "      AgEAWBKGG5b5ZVOjA3TzQ8t/RNY+UcAIcdQ+CF/usUbGBSMnKkKWgTzgF6DdE6k/\n"
+            + "      mXX0IOpn07I/MDXPpUDN4ZfIWFm9vLsba1kMFE/+/S7ymdIB0LkXyXxWHZgZ2ATe\n"
+            + "      xkPbm+l0GLs/QR/othB604lefzo+qCaBbUXqXPEOMoKyL2Sl5TQBbAN05WDvjzCS\n"
+            + "      7nSjxQTOxXDHMV322gaWB7+efcUfknsS4bMCUXBOgeqnBNUR6BoB3SX2avn6tLtS\n"
+            + "      t3dfzQEcOoIFxcTtSpu3PDlj6WajAwKdbSQU3TZ0L10u3Zz0jEL72w8gDl5OStkG\n"
+            + "      SuRNVEYuPavb2PucL2blVopwGpwtkNbLylGdrzJpmmuA10Tx39ZNj2dWyJzT03zM\n"
+            + "      0XlDRuGFZrdCieUH1dblmoOC6JyW+f7lO1ETNIC1I7LEz6B8beXTCM7LAiTVoVrn\n"
+            + "      ZFqoBY8vrso4zobe8o2kydbmGuYeuKO4rGJqsYihl+RkxHmKMrS4WC/f+no0cv9h\n"
+            + "      AFockmGQp63lOGI/HBb37WT9lxdV5jbpeH7bYan/y2jtlbyC48+I3WF+kP7t/Uh1\n"
+            + "      KYcOuxlBDtt/NXRummzI00Ht7YRzLD4ZCfLbufK0EskMZ1EG6tvBC/OmlA7pCaWT\n"
+            + "      St8KzOHtsYKgJA3Fea4OxDkEL6lBSommVOp2zWybKLb3Gzc=\n"
+            + "    </cert>\n"
+            + "  </intermediates>\n"
+            + "  <endpoints>\n"
+            + "    <cert>\n"
+            + "      MIIDCDCB8aADAgECAgYBYVkuU0cwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi\n"
+            + "      R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAyMDIwMTAx\n"
+            + "      MDNaFw0yMDAyMDMwMTAxMDNaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW\n"
+            + "      YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu\n"
+            + "      tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl\n"
+            + "      4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBAJ3PM4GNTNYzMr8E/IGsWZkLx9AR\n"
+            + "      AALqBXz7As59F8y5UcLMqkXD/ewOfBZgF5VzjlAePyE/wSw0wc3xzvrDVVDiZaMB\n"
+            + "      W1DVtSlbn25q00m00mmcUeyyMc7vuRkPoDshIMQTc8+U3yyYsVScSV+B4TvSx6wP\n"
+            + "      Z9FpwnSPjVPD2GkqeMTWszuxNVEWq0wmm0K5lMaX0hfiak+4/IZxOPPGIg2py1KL\n"
+            + "      A/H2gdyeqyJRcAsyEkfwLlushR5T9abSiPsIRcYoX8Ck8Lt+gQ7RCMefnm8CoOBK\n"
+            + "      IfcjuV4PGOoeXrq57VR5SsOeT07bL+D7B+mohYFI1v2G3WClAE8XgM3q8NoFFvaY\n"
+            + "      moi0+UcTduil47qvozjdNmjRAgu5j6vMKXEdG5Rqsja8hy0LG1hwfnR0gNiwcZ5L\n"
+            + "      e3GyFnwH1IgqvsGOUM0ohnDUAU0zJY7nG0QYrDYe5/QPRNhWDpYkwHDiqcG28wIQ\n"
+            + "      COTPAZHU2EoSKjSqEG2l0S5JPcor2BEde9ikSkcmK8foxlOHIdFn+n7RNF3bSEfK\n"
+            + "      n1IOuXoqPidmeBQLevqG8KTy/C9CHqlaCNlpbIA9h+WVfsjm2s6JXBu0YbcfoIbJ\n"
+            + "      AmSuZVeqB/+ZVvpfiad/jQWzY49fRnsSmV7VveTFPGtJxC89EadbMAinMZo+72u5\n"
+            + "      9319RqN5wsP2Zus8\n"
+            + "    </cert>\n"
+            + "  </endpoints>\n"
+            + "</certificates>\n";
+
+    public static byte[] getCertPath1Bytes() {
+        try {
+            return CertUtils.decodeBase64(CERT_PATH_1_BASE64);
+        } catch (Exception e){
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static byte[] getCertPath2Bytes() {
+        try {
+            return CertUtils.decodeBase64(CERT_PATH_2_BASE64);
+        } catch (Exception e){
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static final CertPath CERT_PATH_1;
+    public static final CertPath CERT_PATH_2;
+
+    static {
+        try {
+            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            CERT_PATH_1 = certFactory.generateCertPath(
+                    new ByteArrayInputStream(getCertPath1Bytes()), CERT_PATH_ENCODING);
+            CERT_PATH_2 = certFactory.generateCertPath(
+                    new ByteArrayInputStream(getCertPath2Bytes()), CERT_PATH_ENCODING);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static byte[] getCertXmlWithSerial(long serial) {
+        String xml = THM_CERT_XML_BEFORE_SERIAL + serial + THM_CERT_XML_AFTER_SERIAL;
+        return xml.getBytes(StandardCharsets.UTF_8);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java
new file mode 100644
index 0000000..d08dab4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.expectThrows;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.io.InputStream;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.X509Certificate;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.w3c.dom.Element;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class CertUtilsTest {
+
+    private static final String XML_STR = ""
+            + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+            + "<!-- comment 1 -->"
+            + "<root>\n\n\n\r\r\r"
+            + "  <node1>\r\n\r\n"
+            + "    node1-1</node1>"
+            + "  <!-- comment 2 -->"
+            + "  <node1>node1-2"
+            + "    \n\r\n\r</node1>"
+            + "  <node2>"
+            + "    <node1>   node2-node1-1</node1>"
+            + "    <node1>node2-node1-2   </node1>"
+            + "    <!-- comment 3 -->"
+            + "    <node1>   node2-node1-3   </node1>"
+            + "  </node2>"
+            + "</root>";
+
+    private static final String SIGNED_STR = "abcdefg\n";
+    private static final String SIGNATURE_BASE64 = ""
+            + "KxBt9B3pwL3/59SrjTJTpuhc9JRxLOUNwNr3J4EEdXj5BqkYOUeXIOjyBGp8XaOnmuW8WmBxhko3"
+            + "yTR3/M9x0/pJuKDgqQSSFG+I56O/IAri7DmMBfY8QqcgiF8RaR86G7mWXUIdu8ixEtpKa//T4bN7"
+            + "c8Txvt96ApAcW0wJDihfCqDEXyi56pFCp+qEZuL4fS8iZtZTUkvxim1tb2/IsZ9OyDd9BWxp+JTs"
+            + "zihzH6xqnUCa1aELSUZnU8OzWGeuKpVDQDbDMtQpcxJ9o+6L6wO5vmQutZAulgw5gRPGhYWVs8+0"
+            + "ATdNEbv8TSomkXkZ3/lMYnmPXKmaHxcP4330DA==";
+    private static final PublicKey SIGNER_PUBLIC_KEY = TestData.INTERMEDIATE_CA_2.getPublicKey();
+
+    @Test
+    public void decodeCert_readPemFile_succeeds_singleBlock() throws Exception {
+        InputStream f = TestData.openTestFile("pem/valid-cert.pem");
+        X509Certificate cert = CertUtils.decodeCert(f);
+        assertThat(cert).isEqualTo(TestData.ROOT_CA_TRUSTED);
+    }
+
+    @Test
+    public void decodeCert_readPemFile_succeeds_multipleBlocks() throws Exception {
+        InputStream in = TestData.openTestFile("pem/valid-cert-multiple-blocks.pem");
+        X509Certificate cert = CertUtils.decodeCert(in);
+        assertThat(cert).isEqualTo(TestData.ROOT_CA_TRUSTED);
+    }
+
+    @Test
+    public void decodeCert_readPemFile_throwsIfNoBeginEndLines() throws Exception {
+        InputStream in = TestData.openTestFile("pem/invalid-cert-1-no-begin-end.pem");
+        assertThrows(CertParsingException.class, () -> CertUtils.decodeCert(in));
+    }
+
+    @Test
+    public void decodeCert_readPemFile_throwsIfEmptyBlock() throws Exception {
+        InputStream in = TestData.openTestFile("pem/invalid-cert-2-empty-block.pem");
+        assertThrows(CertParsingException.class, () -> CertUtils.decodeCert(in));
+    }
+
+    @Test
+    public void decodeCert_readPemFile_throwsIfInvalidCert() throws Exception {
+        InputStream in = TestData.openTestFile("pem/invalid-cert-3-invalid-key.pem");
+        assertThrows(CertParsingException.class, () -> CertUtils.decodeCert(in));
+    }
+
+    @Test
+    public void decodeCert_readBytes_succeeds() throws Exception {
+        X509Certificate cert = CertUtils.decodeCert(TestData.INTERMEDIATE_CA_2.getEncoded());
+        assertThat(cert.getIssuerX500Principal().getName())
+                .isEqualTo("CN=Google CryptAuthVault Intermediate");
+    }
+
+    @Test
+    public void decodeCert_readBytes_throwsIfInvalidCert() throws Exception {
+        byte[] modifiedCertBytes = TestData.INTERMEDIATE_CA_1.getEncoded();
+        modifiedCertBytes[0] ^= (byte) 1;
+        assertThrows(CertParsingException.class, () -> CertUtils.decodeCert(modifiedCertBytes));
+    }
+
+    @Test
+    public void decodeBase64_succeeds() throws Exception {
+        assertThat(CertUtils.decodeBase64("VEVTVA==")).isEqualTo("TEST".getBytes(UTF_8));
+    }
+
+    @Test
+    public void decodeBase64_succeedsIfEmptyInput() throws Exception {
+        assertThat(CertUtils.decodeBase64("")).hasLength(0);
+    }
+
+    @Test
+    public void decodeBase64_throwsIfInvalidInput() throws Exception {
+        assertThrows(CertParsingException.class, () -> CertUtils.decodeBase64("EVTVA=="));
+    }
+
+    @Test
+    public void getXmlRootNode_succeeds() throws Exception {
+        Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8));
+        assertThat(root.getTagName()).isEqualTo("root");
+    }
+
+    @Test
+    public void getXmlRootNode_throwsIfEmptyInput() throws Exception {
+        assertThrows(CertParsingException.class, () -> CertUtils.getXmlRootNode(new byte[0]));
+    }
+
+    @Test
+    public void getXmlNodeContents_singleLevel_succeeds() throws Exception {
+        Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8));
+        assertThat(CertUtils.getXmlNodeContents(CertUtils.MUST_EXIST_UNENFORCED, root, "node1"))
+                .containsExactly("node1-1", "node1-2");
+    }
+
+    @Test
+    public void getXmlNodeContents_multipleLevels_succeeds() throws Exception {
+        Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8));
+        assertThat(CertUtils.getXmlNodeContents(CertUtils.MUST_EXIST_UNENFORCED, root, "node2", "node1"))
+                .containsExactly("node2-node1-1", "node2-node1-2", "node2-node1-3");
+    }
+
+    @Test
+    public void getXmlNodeContents_mustExistFalse_succeedsIfNotExist() throws Exception {
+        Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8));
+        assertThat(
+                CertUtils.getXmlNodeContents(
+                        CertUtils.MUST_EXIST_UNENFORCED, root, "node2", "node-not-exist"))
+                .isEmpty();
+    }
+
+    @Test
+    public void getXmlNodeContents_mustExistAtLeastOne_throwsIfNotExist() throws Exception {
+        Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8));
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                CertUtils.getXmlNodeContents(
+                                        CertUtils.MUST_EXIST_AT_LEAST_ONE, root, "node2",
+                                        "node-not-exist"));
+        assertThat(expected.getMessage()).contains("must contain at least one");
+    }
+
+    @Test
+    public void getXmlNodeContents_mustExistExactlyOne_throwsIfNotExist() throws Exception {
+        Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8));
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                CertUtils.getXmlNodeContents(
+                                        CertUtils.MUST_EXIST_EXACTLY_ONE, root, "node-not-exist",
+                                        "node1"));
+        assertThat(expected.getMessage()).contains("must contain exactly one");
+    }
+
+    @Test
+    public void getXmlNodeContents_mustExistExactlyOne_throwsIfMultipleExist() throws Exception {
+        Element root = CertUtils.getXmlRootNode(XML_STR.getBytes(UTF_8));
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                CertUtils.getXmlNodeContents(
+                                        CertUtils.MUST_EXIST_EXACTLY_ONE, root, "node2", "node1"));
+        assertThat(expected.getMessage()).contains("must contain exactly one");
+    }
+
+    @Test
+    public void verifyRsaSha256Signature_succeeds() throws Exception {
+        CertUtils.verifyRsaSha256Signature(
+                SIGNER_PUBLIC_KEY,
+                Base64.getDecoder().decode(SIGNATURE_BASE64),
+                SIGNED_STR.getBytes(UTF_8));
+    }
+
+    @Test
+    public void verifyRsaSha256Signature_throwsIfMismatchSignature() throws Exception {
+        byte[] modifiedBytes = SIGNED_STR.getBytes(UTF_8);
+        modifiedBytes[0] ^= (byte) 1;
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        CertUtils.verifyRsaSha256Signature(
+                                SIGNER_PUBLIC_KEY, Base64.getDecoder().decode(SIGNATURE_BASE64),
+                                modifiedBytes));
+    }
+
+    @Test
+    public void verifyRsaSha256Signature_throwsIfWrongKeyType() throws Exception {
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
+        keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1"));
+        PublicKey publicKey = keyPairGenerator.generateKeyPair().getPublic();
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        CertUtils.verifyRsaSha256Signature(
+                                publicKey,
+                                Base64.getDecoder().decode(SIGNATURE_BASE64),
+                                SIGNED_STR.getBytes(UTF_8)));
+    }
+
+    @Test
+    public void buildCertPath_succeedsWithoutIntermediates() throws Exception {
+        X509Certificate rootCert = TestData.ROOT_CA_TRUSTED;
+        X509Certificate leafCert = TestData.INTERMEDIATE_CA_1;
+        CertPath certPath = CertUtils.buildCertPath(
+                CertUtils.buildPkixParams(
+                        TestData.DATE_ALL_CERTS_VALID, rootCert, Collections.emptyList(),
+                        leafCert));
+        assertThat(certPath.getCertificates()).containsExactly(
+                TestData.INTERMEDIATE_CA_1).inOrder();
+    }
+
+    @Test
+    public void buildCertPath_succeedsWithIntermediates() throws Exception {
+        X509Certificate rootCert = TestData.ROOT_CA_TRUSTED;
+        List<X509Certificate> intermediateCerts =
+                Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2);
+        X509Certificate leafCert = TestData.LEAF_CERT_2;
+        CertPath certPath =
+                CertUtils.buildCertPath(
+                        CertUtils.buildPkixParams(
+                                TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts,
+                                leafCert));
+        assertThat(certPath.getCertificates())
+                .containsExactly(
+                        TestData.LEAF_CERT_2, TestData.INTERMEDIATE_CA_2,
+                        TestData.INTERMEDIATE_CA_1)
+                .inOrder();
+    }
+
+    @Test
+    public void buildCertPath_succeedsWithIntermediates_ignoreUnrelatedIntermedateCert()
+            throws Exception {
+        X509Certificate rootCert = TestData.ROOT_CA_TRUSTED;
+        List<X509Certificate> intermediateCerts =
+                Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2);
+        X509Certificate leafCert = TestData.LEAF_CERT_1;
+        CertPath certPath =
+                CertUtils.buildCertPath(
+                        CertUtils.buildPkixParams(
+                                TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts,
+                                leafCert));
+        assertThat(certPath.getCertificates())
+                .containsExactly(TestData.LEAF_CERT_1, TestData.INTERMEDIATE_CA_1)
+                .inOrder();
+    }
+
+    @Test
+    public void buildCertPath_throwsIfWrongRootCommonName() throws Exception {
+        X509Certificate rootCert = TestData.ROOT_CA_DIFFERENT_COMMON_NAME;
+        List<X509Certificate> intermediateCerts =
+                Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2);
+        X509Certificate leafCert = TestData.LEAF_CERT_1;
+
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        CertUtils.buildCertPath(
+                                CertUtils.buildPkixParams(
+                                        TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts,
+                                        leafCert)));
+    }
+
+    @Test
+    public void buildCertPath_throwsIfMissingIntermediateCert() throws Exception {
+        X509Certificate rootCert = TestData.ROOT_CA_DIFFERENT_COMMON_NAME;
+        List<X509Certificate> intermediateCerts = Collections.emptyList();
+        X509Certificate leafCert = TestData.LEAF_CERT_1;
+
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        CertUtils.buildCertPath(
+                                CertUtils.buildPkixParams(
+                                        TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts,
+                                        leafCert)));
+    }
+
+    @Test
+    public void validateCert_succeeds() throws Exception {
+        X509Certificate rootCert = TestData.ROOT_CA_TRUSTED;
+        List<X509Certificate> intermediateCerts =
+                Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2);
+        X509Certificate leafCert = TestData.LEAF_CERT_2;
+        CertUtils.validateCert(TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts,
+                leafCert);
+    }
+
+    @Test
+    public void validateCert_throwsIfExpired() throws Exception {
+        X509Certificate rootCert = TestData.ROOT_CA_TRUSTED;
+        List<X509Certificate> intermediateCerts =
+                Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2);
+        X509Certificate leafCert = TestData.LEAF_CERT_2;
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        CertUtils.validateCert(
+                                TestData.DATE_LEAF_CERT_2_EXPIRED, rootCert, intermediateCerts,
+                                leafCert));
+    }
+
+    @Test
+    public void validateCert_throwsIfWrongRootWithTheSameCommonName() throws Exception {
+        X509Certificate rootCert = TestData.ROOT_CA_DIFFERENT_KEY;
+        List<X509Certificate> intermediateCerts =
+                Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2);
+        X509Certificate leafCert = TestData.LEAF_CERT_2;
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        CertUtils.validateCert(
+                                TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts,
+                                leafCert));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java
new file mode 100644
index 0000000..52269d9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertXmlTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.expectThrows;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.security.cert.CertPath;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class CertXmlTest {
+
+    private byte[] certXmlBytes;
+
+    @Before
+    public void setUp() throws Exception {
+        certXmlBytes = TestData.readTestFile("xml/valid-cert-file.xml");
+    }
+
+    @Test
+    public void parse_succeeds() throws Exception {
+        CertXml certXml = CertXml.parse(certXmlBytes);
+        assertThat(certXml.getSerial()).isEqualTo(1000L);
+        assertThat(certXml.getRefreshInterval()).isEqualTo(2592000L);
+    }
+
+    @Test
+    public void parse_succeedsIfNoIntermediateCerts() throws Exception {
+        CertXml certXml =
+                CertXml.parse(TestData.readTestFile("xml/valid-cert-file-no-intermediates.xml"));
+        assertThat(certXml.getAllIntermediateCerts()).isEmpty();
+    }
+
+    @Test
+    public void parse_checkIntermediateCerts() throws Exception {
+        CertXml certXml = CertXml.parse(certXmlBytes);
+        List<X509Certificate> intermediateCerts = certXml.getAllIntermediateCerts();
+        assertThat(intermediateCerts)
+                .containsExactly(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2)
+                .inOrder();
+    }
+
+    @Test
+    public void parse_checkEndpointCerts() throws Exception {
+        CertXml certXml = CertXml.parse(certXmlBytes);
+        List<X509Certificate> endpointCerts = certXml.getAllEndpointCerts();
+        assertThat(endpointCerts).hasSize(3);
+        assertThat(endpointCerts).containsAllOf(TestData.LEAF_CERT_1, TestData.LEAF_CERT_2);
+    }
+
+    @Test
+    public void parse_throwsIfNoEndpointCert() throws Exception {
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                CertXml.parse(
+                                        TestData.readTestFile(
+                                                "xml/invalid-cert-file-no-endpoint-cert.xml")));
+        assertThat(expected.getMessage()).contains("at least one");
+    }
+
+    @Test
+    public void parse_throwsIfNoRefreshInterval() throws Exception {
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                CertXml.parse(
+                                        TestData.readTestFile(
+                                                "xml/invalid-cert-file-no-refresh-interval.xml")));
+        assertThat(expected.getMessage()).contains("exactly one");
+    }
+
+    @Test
+    public void parse_throwsIfNoSerial() throws Exception {
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                CertXml.parse(
+                                        TestData.readTestFile(
+                                                "xml/invalid-cert-file-no-serial.xml")));
+        assertThat(expected.getMessage()).contains("exactly one");
+    }
+
+    @Test
+    public void parse_throwsIfTwoRefreshIntervals() throws Exception {
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                CertXml.parse(
+                                        TestData.readTestFile(
+                                                "xml/invalid-cert-file-two-refresh-intervals"
+                                                        + ".xml")));
+        assertThat(expected.getMessage()).contains("exactly one");
+    }
+
+    @Test
+    public void parse_throwsIfTwoSerials() throws Exception {
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                CertXml.parse(
+                                        TestData.readTestFile(
+                                                "xml/invalid-cert-file-two-serials.xml")));
+        assertThat(expected.getMessage()).contains("exactly one node");
+    }
+
+    @Test
+    public void parseAndValidateAllCerts_succeeds() throws Exception {
+        CertXml certXml = CertXml.parse(certXmlBytes);
+        for (int index = 0; index < certXml.getAllEndpointCerts().size(); index++) {
+            assertThat(
+                    certXml.getEndpointCert(
+                            index, TestData.DATE_ALL_CERTS_VALID, TestData.ROOT_CA_TRUSTED))
+                    .isNotNull();
+        }
+    }
+
+    @Test
+    public void parseAndValidate_returnsExpectedCertPath() throws Exception {
+        CertXml certXml = CertXml.parse(certXmlBytes);
+        CertPath certPath =
+                certXml.getEndpointCert(
+                        /*index=*/ 1, // TestData.LEAF_CERT_2
+                        TestData.DATE_ALL_CERTS_VALID,
+                        TestData.ROOT_CA_TRUSTED);
+        assertThat(certPath.getCertificates())
+                .containsExactly(
+                        TestData.LEAF_CERT_2, TestData.INTERMEDIATE_CA_2,
+                        TestData.INTERMEDIATE_CA_1)
+                .inOrder();
+    }
+
+    @Test
+    public void validateCert_throwsIfRootCertWithDifferentCommonName() throws Exception {
+        CertXml certXml = CertXml.parse(certXmlBytes);
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        certXml.getEndpointCert(
+                                /*index=*/ 0, // TestData.LEAF_CERT_1
+                                TestData.DATE_ALL_CERTS_VALID,
+                                TestData.ROOT_CA_DIFFERENT_COMMON_NAME));
+    }
+
+    @Test
+    public void validateCert_throwsIfRootCertWithDifferentPublicKey() throws Exception {
+        CertXml certXml = CertXml.parse(certXmlBytes);
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        certXml.getEndpointCert(
+                                /*index=*/ 0, // TestData.LEAF_CERT_1
+                                TestData.DATE_ALL_CERTS_VALID,
+                                TestData.ROOT_CA_DIFFERENT_KEY));
+    }
+
+    @Test
+    public void validateCert_throwsIfExpired() throws Exception {
+        CertXml certXml = CertXml.parse(certXmlBytes);
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        certXml.getEndpointCert(
+                                /*index=*/ 1, // TestData.LEAF_CERT_2
+                                TestData.DATE_LEAF_CERT_2_EXPIRED,
+                                TestData.ROOT_CA_TRUSTED));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/SigXmlTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/SigXmlTest.java
new file mode 100644
index 0000000..4d87006
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/SigXmlTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.expectThrows;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class SigXmlTest {
+
+    private byte[] certXmlBytes;
+    private byte[] sigXmlBytes;
+
+    @Before
+    public void setUp() throws Exception {
+        certXmlBytes = TestData.readTestFile("xml/valid-cert-file.xml");
+        sigXmlBytes = TestData.readTestFile("xml/valid-sig-file.sig.xml");
+    }
+
+    @Test
+    public void parseAndVerifyFileSignature_succeeds() throws Exception {
+        SigXml sigXml = SigXml.parse(sigXmlBytes);
+        sigXml.verifyFileSignature(
+                TestData.ROOT_CA_TRUSTED, certXmlBytes, TestData.DATE_ALL_CERTS_VALID);
+    }
+
+    @Test
+    public void parseAndVerifyFileSignature_throwsIfExpiredCert() throws Exception {
+        SigXml sigXml = SigXml.parse(sigXmlBytes);
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        sigXml.verifyFileSignature(
+                                TestData.ROOT_CA_TRUSTED, certXmlBytes,
+                                TestData.DATE_INTERMEDIATE_CA_2_EXPIRED));
+    }
+
+    @Test
+    public void parseAndVerifyFileSignature_throwsIfInvalidSignature() throws Exception {
+        SigXml sigXml = SigXml.parse(sigXmlBytes);
+        byte[] modifiedBytes = sigXmlBytes.clone();
+        modifiedBytes[0] ^= (byte) 1; // Flip one bit
+        CertValidationException expected =
+                expectThrows(
+                        CertValidationException.class,
+                        () ->
+                                sigXml.verifyFileSignature(
+                                        TestData.ROOT_CA_TRUSTED, modifiedBytes,
+                                        TestData.DATE_ALL_CERTS_VALID));
+        assertThat(expected.getMessage()).contains("signature is invalid");
+    }
+
+    @Test
+    public void parseAndVerifyFileSignature_throwsIfRootCertWithWrongCommonName() throws Exception {
+        SigXml sigXml = SigXml.parse(sigXmlBytes);
+        assertThrows(
+                CertValidationException.class,
+                () ->
+                        sigXml.verifyFileSignature(
+                                TestData.ROOT_CA_DIFFERENT_COMMON_NAME,
+                                certXmlBytes,
+                                TestData.DATE_ALL_CERTS_VALID));
+    }
+
+    @Test
+    public void parse_succeedsWithoutIntermediateCerts() throws Exception {
+        SigXml.parse(TestData.readTestFile("xml/valid-sig-file-no-intermediates.sig.xml"));
+    }
+
+    @Test
+    public void parse_throwsIfNoSignerCert() throws Exception {
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                SigXml.parse(
+                                        TestData.readTestFile(
+                                                "xml/invalid-sig-file-no-signer-cert.sig.xml")));
+        assertThat(expected.getMessage()).contains("exactly one");
+    }
+
+    @Test
+    public void parse_throwsIfTwoSignerCerts() throws Exception {
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                SigXml.parse(
+                                        TestData.readTestFile(
+                                                "xml/invalid-sig-file-two-signer-certs.sig.xml")));
+        assertThat(expected.getMessage()).contains("exactly one");
+    }
+
+    @Test
+    public void parse_throwsIfNoSignatureValue() throws Exception {
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                SigXml.parse(
+                                        TestData.readTestFile(
+                                                "xml/invalid-sig-file-no-signature.sig.xml")));
+        assertThat(expected.getMessage()).contains("exactly one");
+    }
+
+    @Test
+    public void parse_throwsIfTwoSignatureValues() throws Exception {
+        CertParsingException expected =
+                expectThrows(
+                        CertParsingException.class,
+                        () ->
+                                SigXml.parse(
+                                        TestData.readTestFile(
+                                                "xml/invalid-sig-file-two-signatures.sig.xml")));
+        assertThat(expected.getMessage()).contains("exactly one");
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/TestData.java
new file mode 100644
index 0000000..5eb4166
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/TestData.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.certificate;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+
+import com.google.common.io.ByteStreams;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+import java.util.Date;
+
+/** Constants used by the tests in the folder. */
+public final class TestData {
+
+    private static final String TEST_FILE_FOLDER_NAME = "KeyStoreRecoveryControllerTest";
+
+    private TestData() {}
+
+    // Some test data that is generated by using OpenSSL command line tools.
+    private static final String ROOT_CA_TRUSTED_BASE64 = ""
+            + "MIIJJzCCBQ6gAwIBAgIJAM7fBGeQ1wBkMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV"
+            + "BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAxMTEwNjQ5MzNaFw0zODAx"
+            + "MDYwNjQ5MzNaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCBCIw"
+            + "DQYJKoZIhvcNAQEBBQADggQPADCCBAoCggQBCcFv05M1seLPYIW7oFivh7u5otCt"
+            + "Mm7ryq0UjpbTQPcQxJQbYzcUQF7CbPYTdWDid4EuO8Zec03ownsduFhKud6H3yIQ"
+            + "4ueGiqCBoG1D6+N8fF9R8awTmAsbNg63VInx6IwcBZnjFlsIIftOFxqIJBYhiKhN"
+            + "JhPtF1i9dn+N5HjEKmkJO3pXhYhRXMp7OwL/epxzhBXFYT7aDg9pnaM6C+4hmhQ/"
+            + "0q2oyzYtAqFmrEenbtI6G47SzMc+shNTuYLtq21j/Z3uA3RwB9Szfu99F66tlgTX"
+            + "v7K7YS573hN3TQY/+nkLfFy/oF2LQRYvKHF+Nv0BHzQLzqDEYBaILcMf3i2Ce/b7"
+            + "wZjitLqFAI1swqGzgH/QpB3OrX51M/B7UCF2nB7Pa8knu4kBDGkz2Q41jAL0W/qt"
+            + "j43VwJDW0Y98OuqQiCqJrTrGdv7b/phnVVBvFrtIjYMfyK34jy5VLXctV5CSkWj5"
+            + "3ul3mvGFHJD+6nneDR4PUkmYN0khT4t/RqnQlwYE0a6Erq1+Rof6/DoWSzeBLBYV"
+            + "JaHhRy9mrudR/VcQynLKty6Zst4Lyh6aPMHcpTwGZbG+4mXnWeTaLEnGvivldksT"
+            + "XOxipcO/fXJfDss4b0glGzP3GD0+H5EZB9coYzNT47QZd9drxHdrLxtPoi+MeqkG"
+            + "gCdyFyBZO8G2k/JuyziT6hy+50VXJnl6Ujxj7MVUYAsISHsHgqETDsukQbbKvTKg"
+            + "3gxPVNN/vKWwyh7KLcFIaOEoPOgStkmVsqrXm7YLE6Bvzm8nu4rwJeAF9Yseg9BE"
+            + "Y86TRRmAI7fW4eDEPnxgCUUvcYSAh5mcayIyIr0KTuXkevwYbVRHMVmy9DaqzsP8"
+            + "YFXIqFvDXRCFSy/gMkoNb9ZoqdkmjZ+VBsjAKI+u/Haf6pgdpGZbVGKEFmaVHCkr"
+            + "tPp/gy4kE4qmd/SIaccG8o6Eb9X9fbqTTDZv34kcGgxOvBJVIaNHprTjgvYEnRaD"
+            + "KTlmZoCUmBlHzvbf68YWBmIz0K8vYPdx9r98LiUgpbTHtKZIYrJnbgPnbC9icP24"
+            + "2ksB4yaTx1QWc14vTNv1lUtv4zJEmaaoynNlETJFf/Tz0QKJxtT+l/BIAz8kEJMA"
+            + "cKsfoTx9OTtfuL85pXbCgxbKKmKn6RzxUCzSzgMboC0z6W8Zxy2gLIhqMm8AXAF7"
+            + "salwrRirV4lWsM9MOhVEgfjcv/qmQSYr1ARrwwegHRqxPA3qh11kfq5YSFU7W7+f"
+            + "JrWH6VuLZ0B1fj2+lsoMNekFA1ULD8DK7aAFIh9Y1y4Jt//xMuOPcD5PWNGFmUk7"
+            + "oPewiIUMLjXSWcgrQVYbZEDW/vooMJoo47Vg1fQPehejbONE1nBIaeRVhJcCAwEA"
+            + "AaNjMGEwHQYDVR0OBBYEFNd7oYeSi7hSGimRpTZaHLQy6+zRMB8GA1UdIwQYMBaA"
+            + "FNd7oYeSi7hSGimRpTZaHLQy6+zRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/"
+            + "BAQDAgGGMA0GCSqGSIb3DQEBDQUAA4IEAgABny011veuPplTcNeyLeKhWRn/y9VM"
+            + "QEyhaLlsC1Di35WN8owjj4+gugLlDdtEc/pvzgk+ZkAuplQkrsU907dvwkDPb4rW"
+            + "ZB5hjbr9yVyEHK1bHh7RSUkJrB3NRwqH1lyWz/LfaVfbV4CtaaERhThzZCp/MweO"
+            + "Tivg2XpSluy5s8lEEbMC/dGuIsBMitX3XLlbYa2ND3aHZLo6X9yQMFfTCjgwYG2n"
+            + "eDYupnvcLINlrlJYcrYSrIvoQn9XfsnjU3AXz+jc6xLrO3EtXDhi9e+QTfcnvRsg"
+            + "l/Hj9SZr1w1L1PPJo+KjsRavVvzaHXlBAvvUtEojJrkR3j+b5zvQB6dgVrM0zUhM"
+            + "Q9zRp5R/xqHeZ/0TTQe9kEa8QuRzuRIkK5Wbh76Eix3S+2uTsbj462nk4E0oPR8p"
+            + "iYopS4ZEFEfrKW14HOph9ZscI4l/HfDmTNfgpyFl62UrvzVBnoz+sbhTgbPHPcCX"
+            + "OUrhmpz9I5oBkyEAZYunSvzY/9SXUsz6psXHJmVzLQcne/YQTtpWzV/wGD7cjjDl"
+            + "bfzsmGCfZ8jqPBoicl5IUVdyZsJgufEZHXxKZQ7wL7R6jKrj/GtCDey1Wr2QT8VX"
+            + "5JTk9cJQFjgjDWaAyCBpGEaQvYJcaOxk2D+Wap5ax8nUfW/99vVFA0EJKsSVVzw7"
+            + "daRty0UpfZsx2Sfzpg0mymmgB8+NY6t68dL5C/xxAv5mEQ8wGJmP45iQpo5T6LVV"
+            + "MrktLf5eIzxlALQIW/AgpSH9JKCqpItdxfisAIIs9e8XHbVJJA0Jde7rtAj+TUY0"
+            + "h00xSqyfSSbpcDJ9lIoSZOJvFQdWOxB8c3vZZGGhMuRFm06sUHvcHjo8KwnbqyOx"
+            + "DGjeqt6YWty6WcNin0WciR33vGHIzwVNxNnmuY308bNsMvY9jsmd37hdmmwnmQge"
+            + "7AIa7TMPjaKm0vV/1ztFSODWCI2K7klmL2MtOJMGfqUeOfjPANbS3lMJBAH9qxLM"
+            + "7Kng+nfqVtt+NG9MxcTbP80FkBa/6JxGgjjsiwDmhr2MTCYOK/eD+WZikMOieyvH"
+            + "m2vgxYCdWrhaGfc3t6oQ2YO+mXI7e6d3F3a90UUYkBIgje9zu0RLxnBBhuoRyGwv"
+            + "uQAlqgMDBZIzTO0Vnwew7KRLdzLhWbiikhi81q6Lg62aWjbdF6Ue6AVXch+dqmr+"
+            + "9aVt0Y6ETTS77nrQyglyLKIeNx6cEHDjETXlPYGbCAlrdKAdTA4ngnBZnzGQ/8zg"
+            + "tP9zvIJVA6cuOAn8GFEsrb7GN20QSDwyJWrYi6f+m64D9rOK4Jz4t+lEfjcfJeM/"
+            + "UcNlhmATcMHXWPCoKkOfll4PBc/Wigv1xYw70RZ4pai07LzJxNHYhvpE3Q==";
+    private static final String ROOT_CA_DIFFERENT_KEY_BASE64 = ""
+            + "MIIFJjCCAw6gAwIBAgIJANpazyIWdcb/MA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNV"
+            + "BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAxMjEwMzI0MjVaFw0zODAx"
+            + "MTYwMzI0MjVaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCAiIw"
+            + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKkAUqkRxdVy9UpI9BjQnylGVPRW"
+            + "aQsCwT2iWJ7fuCnQQon1U9nOyw2R5GYKcA8Zy+4Co++6nzRblYYXJG3Fzsj+kxei"
+            + "pZGmU11djRJDOhHPPe5jSW37Y0czWaj8jx4xvMim18dGYR7fg6SsOOYXA2y5tlvZ"
+            + "xLjvw5qpL62J5bVoAAxjng/Oc2Osu+vpv6M50pUZr0OEiFi59WlwrCCZpf1/80bT"
+            + "j2ebCKKAtTYa6+Q+oMGGxb3imSRpmQPtFcvhUPmAaocUjYM/FeIGNRv14oED/aXz"
+            + "khuPb+QNkXgk9yiokE10IeAk6oNUNDyuiMNIFy67lUrwc45lv9y0s/8fHj9pvKse"
+            + "n3+UOKAuV9atUXLdFKQwnQPt4SOmHPkXoj+5tv32RSvVeYhb0ZOpQPkRhxv4wgs7"
+            + "NldNbKhzVDM9K4M5Q2TrPK1yJKrc5/z0bDzmPOcH4AAXPvSt5PZOs0NlXUJ99BcA"
+            + "KE1sWArUhipz5mx0hxPTNEM9/8bMb//HkbZtx2log1/fc207W/AFd2FICOpRY+Sb"
+            + "CJs9WjstpisppotONvgXxZbZiypGKxpeZOb4s6y3iXtZ0FWXUZrc65b8S06fDVCa"
+            + "ZomNFDWhspHFKyueBgU6cR9K97cDo85Juy6RhnouXxi+XpXPdGFwPqVm1glFYos8"
+            + "5+Scbwwx69RihN1nAgMBAAGjYzBhMB0GA1UdDgQWBBRoosUAVtfHHeMl8/5x1m2m"
+            + "arEOoTAfBgNVHSMEGDAWgBRoosUAVtfHHeMl8/5x1m2marEOoTAPBgNVHRMBAf8E"
+            + "BTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAYbLVQlsi"
+            + "KdzCPsaybSrUtMrmkad8Gy+/QR3J16adxy/2WpxsZ1Su0YA4tFzOSWqt74C0mnUi"
+            + "i+3prW7nyEOwezs+NH0SreF4B7tO1FSj157LoHxR2WmCCwul8FfsMi0x6MvEf40v"
+            + "bMeLrRAA4ysRITua1INb05fzJpczoaW/Q1lBPXConvolnIMvYsLbCZX4/OhQQCLa"
+            + "mJx8mGrt1wcNp7Kvh+3JfuOXw+WGeCuB5sSWBsOUvhfN+8sgyk1Dtq5c7rVKKtqz"
+            + "gqHfCNZ+lYa6Vkii7plIcWYJXXa7DMmozX07mrDqdJZEocv6XCoZAKDlJorB8pQT"
+            + "im47RF60X/FCHSCK2cHbG5M+kF84xwj5fTLztLM1+RlJSJiGk6jhxJRQ+hl0Vkhp"
+            + "+u7UbUDwkUF/CJB3d1Gtfm+QtzFVKe27ClU5YFSKCXRV/K4KnkZqpyG8Py+PUtUf"
+            + "WRahp4hkWFkIoLeTnJwgAFRvp/KCtSW0/trI/vfInzqBk/qWIVhxYB8Qv9DXtKBX"
+            + "3AZ36HM2dxmjef/rpYRphuEN0ZwYdynsGy9dF0SihbR8curSg67sbtYfyw0xURhU"
+            + "Nk99YMy7T0EUYnaki/PIPK/gnJjZTX1FLCyHUR38fDJIWkGB4xr8pSrwmRoPSvNF"
+            + "dFr3YlFWwHWd1gXlwJtzeMSuVgoKVtZGmmk=";
+    private static final String ROOT_CA_DIFFERENT_COMMON_NAME_BASE64 = ""
+            + "MIIJFzCCBP6gAwIBAgIJAMobGgw5LXwqMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV"
+            + "BAMMDVdyb25nIFJvb3QgQ0EwHhcNMTgwMTE2MTgzNDA5WhcNMzgwMTExMTgzNDA5"
+            + "WjAYMRYwFAYDVQQDDA1Xcm9uZyBSb290IENBMIIEIjANBgkqhkiG9w0BAQEFAAOC"
+            + "BA8AMIIECgKCBAEJwW/TkzWx4s9ghbugWK+Hu7mi0K0ybuvKrRSOltNA9xDElBtj"
+            + "NxRAXsJs9hN1YOJ3gS47xl5zTejCex24WEq53offIhDi54aKoIGgbUPr43x8X1Hx"
+            + "rBOYCxs2DrdUifHojBwFmeMWWwgh+04XGogkFiGIqE0mE+0XWL12f43keMQqaQk7"
+            + "eleFiFFcyns7Av96nHOEFcVhPtoOD2mdozoL7iGaFD/SrajLNi0CoWasR6du0job"
+            + "jtLMxz6yE1O5gu2rbWP9ne4DdHAH1LN+730Xrq2WBNe/srthLnveE3dNBj/6eQt8"
+            + "XL+gXYtBFi8ocX42/QEfNAvOoMRgFogtwx/eLYJ79vvBmOK0uoUAjWzCobOAf9Ck"
+            + "Hc6tfnUz8HtQIXacHs9rySe7iQEMaTPZDjWMAvRb+q2PjdXAkNbRj3w66pCIKomt"
+            + "OsZ2/tv+mGdVUG8Wu0iNgx/IrfiPLlUtdy1XkJKRaPne6Xea8YUckP7qed4NHg9S"
+            + "SZg3SSFPi39GqdCXBgTRroSurX5Gh/r8OhZLN4EsFhUloeFHL2au51H9VxDKcsq3"
+            + "Lpmy3gvKHpo8wdylPAZlsb7iZedZ5NosSca+K+V2SxNc7GKlw799cl8OyzhvSCUb"
+            + "M/cYPT4fkRkH1yhjM1PjtBl312vEd2svG0+iL4x6qQaAJ3IXIFk7wbaT8m7LOJPq"
+            + "HL7nRVcmeXpSPGPsxVRgCwhIeweCoRMOy6RBtsq9MqDeDE9U03+8pbDKHsotwUho"
+            + "4Sg86BK2SZWyqtebtgsToG/Obye7ivAl4AX1ix6D0ERjzpNFGYAjt9bh4MQ+fGAJ"
+            + "RS9xhICHmZxrIjIivQpO5eR6/BhtVEcxWbL0NqrOw/xgVcioW8NdEIVLL+AySg1v"
+            + "1mip2SaNn5UGyMAoj678dp/qmB2kZltUYoQWZpUcKSu0+n+DLiQTiqZ39Ihpxwby"
+            + "joRv1f19upNMNm/fiRwaDE68ElUho0emtOOC9gSdFoMpOWZmgJSYGUfO9t/rxhYG"
+            + "YjPQry9g93H2v3wuJSCltMe0pkhismduA+dsL2Jw/bjaSwHjJpPHVBZzXi9M2/WV"
+            + "S2/jMkSZpqjKc2URMkV/9PPRAonG1P6X8EgDPyQQkwBwqx+hPH05O1+4vzmldsKD"
+            + "FsoqYqfpHPFQLNLOAxugLTPpbxnHLaAsiGoybwBcAXuxqXCtGKtXiVawz0w6FUSB"
+            + "+Ny/+qZBJivUBGvDB6AdGrE8DeqHXWR+rlhIVTtbv58mtYfpW4tnQHV+Pb6Wygw1"
+            + "6QUDVQsPwMrtoAUiH1jXLgm3//Ey449wPk9Y0YWZSTug97CIhQwuNdJZyCtBVhtk"
+            + "QNb++igwmijjtWDV9A96F6Ns40TWcEhp5FWElwIDAQABo2MwYTAdBgNVHQ4EFgQU"
+            + "13uhh5KLuFIaKZGlNloctDLr7NEwHwYDVR0jBBgwFoAU13uhh5KLuFIaKZGlNloc"
+            + "tDLr7NEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcN"
+            + "AQELBQADggQCAAWZS0RIH4FdQhlUkdJW06cUYYIJ7p8rRI+6XgMkfj7vupjVnfDN"
+            + "3Z3s0yf+dGaGGJbv68W952j33z94FuubsacCixNSaS4bIwLXvcL9kQtI9Qf09Pd6"
+            + "GB102Q6nz/daLVF/5urQPbp4UFkyhcP/d2mg9CmxwBL3Djrf/dKf4EoiV5xmQpUB"
+            + "a6BNBMntnK1VZ3y8YxDF3XnhbjUZAOTLLYe4+isqvXPb9osdmdaZQU3iHQQwGYJN"
+            + "6rTYvHmsdfU5eLYLdWxOOm/5Sz5rWXxa1XqSfQgOIaFYQ1w69Z+3BfNbaBnYck3l"
+            + "xtxGHromigt+2iimXFFML7EHiSznVhHl3SOX0RBLeUvP8oNwwSsaHXuXbceYWvb+"
+            + "ic7FyTN4f3+wRGjN01U3be93dj+qZlvTmCzpOrJeUcym3F94d0tWQvk3kkBp/Egi"
+            + "Dd85vYWCdEeCfODW6sReVdj/IuT5xv1T8kKaNaEjJjAjeX6xjPskw3I2LuPeEyz+"
+            + "26LiOs1hPRHC4CL3JS6LNmRmIYKuy7K0DHwxS6wplDYXXH+a0VuLvQrbsw5zTh3f"
+            + "Xwq0CLGwPPRyMnFk13+PYBa0bmJ1dNu5hUc9biziCJlvcg0c+FzzUYG4poN0R73R"
+            + "XPyFHmpULAHit05dw3QaPZqX1GCeiVxrCl6N6G4/9PsVOvi/WEUasHDkk+R4/r9b"
+            + "RwvQw0PVdDvGndouRcSzHvPEdW9y2TxSDhltvtC2xvp3mGaT0j2+cCRDINLFB6rK"
+            + "v18oLzpzu3HaZ2ptmm4OpeRnCTLa4qheV1rlSWi3mvPoh77glgHEyTHvhiFrlq+6"
+            + "f6oMpkcbp4KtOT/npvB3yY4RZWn+J1cDcOW34ssSN2PDVSx1IsianxtSCXKReYrv"
+            + "kjS4sTQWw0LYG6146g2rz1OKzuT+6YSIPlpw/4/DK0Sz/Q1AY0cuOHhgMSW0cSaE"
+            + "6PQ275hFjJ4zYYEYNOp56nhsvgbLAu1V5rwQpwi2RNo4teFzP/AKyZzNbApfl8Q5"
+            + "PKHHE8+Uk3/oLZ8h12JzceKL5ivXU4i8r9sw+o7b/UReVsbrFDXTuO3sRFyA5kI0"
+            + "aBpYrAyb8xVubbi7gCWhDfJsSKc7CR2N+EUtBrT08TD0AtuxpRLr6Sz2RrTabZNV"
+            + "lQlgWmKalWT/i7gyA/MNxbBK0hyr7Pvl5f7Ud2+muKOfhEXiCzp8yzXU9I8cTz2p"
+            + "K85LYJfRNIO2kPrNLdomPL+J2S298GvX2j08CZR8qBXLOs6XJOvZ1KC8BrJ9M7kG"
+            + "2MHGXeL+9/11khM09dbC+Q0NUKTKOpSU7M7RaON1Dp4RyzdIcdwZ/dFvvxcYbtOP"
+            + "6OAzRvlk6CZWG3obkt3yaB1NhBEw8hiYvX9F";
+    private static final String INTERMEDIATE_CA_1_BASE64 = ""
+            + "MIIHMDCCAxegAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v"
+            + "Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDExMjAwMjM1N1oXDTI4MDExMDAwMjM1"
+            + "N1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0"
+            + "ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALlhoKYuwxaatY9ERDFp"
+            + "iEygSnjy0xzaiF4uCyiTfAuboSi5QwGon3ohf0ufJF02L9lnTMoeBAg+88m8AMgW"
+            + "KFcEupabqlZfA3F/50mMCmnJvBSLXJ+chUdcAVpwcZAsq6ko22ARBxao1wu2qxNe"
+            + "D8eXiiK8DRpTtKy3wOldZJ222v35v9JGOTjORZRrcv7Z8f6I5/cSsTS+WoVk/aBt"
+            + "QqyFkcdw1zqulnlFE2rxNAVgyLlW71WJikYTDtUDeo79LvkDGjVsLo2MfpNxuK+5"
+            + "MuMqzyN5LmzXJmNCEW1O5IIIUAPhgy5s08G+3G644wCEWsAnv2FBWLBn/HmJu6Uq"
+            + "nSM2AaJN56V0tJG/yL2VgTnPJrJypNTKZW3OTCLCaYcTEbKfarxLwVWxvIWSIgkn"
+            + "0q57GYhf7O+x9vvcOUmZwVxZECorIiK4n5AWG/KD3dWI3UGGGpYsDazRngA/bQPu"
+            + "DSzBP9FBVcQt3/DMBG1s6f2Eko5f6aTFcVW9iV7aWLeIq+pQYlbmG42decj+aHLQ"
+            + "COp5KV+Q77y4kFhZQFAQ1mN4crnhuEc1K5SmjAK24zIqWbwM3ly0KSQFc9jAmONg"
+            + "0xu7kAObP3PZk85En12yLLscNmHCWYfOOEvTHf4KX7tjBl4HHp/ur+2Qwgpt9MFB"
+            + "MGqR2cni5OV6gZcRdHaEerjrAgMBAAGjZjBkMB0GA1UdDgQWBBRE9RxHT7U3EP1v"
+            + "djRzNYMrU7EseDAfBgNVHSMEGDAWgBTXe6GHkou4UhopkaU2Why0Muvs0TASBgNV"
+            + "HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC"
+            + "BAIAAfa7FKkfh4t+G8Sv4n3gUcuEAtmpCsTtHJU67r5eSvR24fDX7sqqSIib9sQ8"
+            + "adA1FtnE3wnC4bEKnIwQLerWTN4i4V9oEKRIT5o5Rr61LyO9R+Prpo6uJVoPujFH"
+            + "GZPdIj/Qs4Xax4a11QD+70+ZmmdL6yfigVDWA4yduFdMg6heHRf3EFCbVBv5qbBS"
+            + "n8+eFKRnBZ/kQdFlYt+G+92Qqyn2uAcER6kZjIfPdnZh44SazLP37W8AkDX30Pmk"
+            + "V0PHVGCDrap44q3maI1m8NAE1jGwwmRzJL953x5XgbVGt0K/3cNoWtKLenwX/G3I"
+            + "akrgvOY5Zl0v3FRDZwGFt9UIBfZDDOGRMXIgIGs/1cvkwWpOT6dyReqDXempiQ1q"
+            + "Yy6J5VsK5WK6gEelUyoACbzgby25V6a79Q1MI7dXmFQfCcX0nAD/AZmM1HkeYgrC"
+            + "uq6fWoPOVMKML2mN90rCzkWxGaLcl5dPfad0O1LrcP48SRE5MXMWyxZZBon+wDIk"
+            + "ascyM/r4fmk4kq64YKdm2wxCDMNArAIcyBkwOaWWfabtSagxJ3qtMtxK0qBUsbLC"
+            + "yMyYpgU1h9c8rEdc4JgeE2LXJzxTKDc3SBOqbuNMlKWjYA+X+SUvVYALrQKAC+5v"
+            + "wdUhLYdAPAksqk/ZoiBjkW35FfvqQMJBY29VnDT1h7/Nxk5gu+goTA9oFIYNrNte"
+            + "+s0my+IUgYhKJBsgh7Mupv+B92GN5b3b440BMHB5QR959Jdq6BAXNUyZLM5fhZQE"
+            + "Jj/rxZFXaqq757kgUhwWBz5TDbYF7GkqTyM4k430xwJKY0AYYEHmv1UYNo5X4G3x"
+            + "SC2LhWC1b9VAykdkHbLs+IA8klxURmLmRiRj1UryhQjjT8h/FvNyPnbT1AKoElix"
+            + "QLnLi8thkJ+tQggO0hISFsIrKNfnn0V6O0VKw9UZsMigsbYG5EbzIXcAyy8Avr9n"
+            + "um7gBBZDt7fWso0+pG1UenJ+PybeuW/azQDLRw1Syz8OwU+ABRLq0JyyAtV7VPY5"
+            + "C9pkKS+bU8nECxr6dMhAbpLBHlKsyb1qtkOt1p7WagEQZFIIc6svc73+L/ET/lWn"
+            + "GBmkVVsCN7Aqyo5aXQWueXP4FUL+6O5+JALqw3qPeQgfnLkh0cUuccNND05QeEiv"
+            + "Zswc/23KJXy1XbdVKT3UP0RAF7DxstbRGQbAT3z+n931e3KhtU28OKjsFtoeq2Dj"
+            + "6STPEXh4rYFWMM8+DrJetAtBqk/i+vBwRA8f7jqIPPep/vEjPqqMOpdSVcoFQ1df"
+            + "JuOZtGfEUjFHnlDr3eGP7KUIEZvhan1zm544dDgPVTXxrY4moi2BhKEY69zRSX6B"
+            + "+a0fa5B3pxc8BN0LsHA0stT/Y2o=";
+    private static final String INTERMEDIATE_CA_2_BASE64 = ""
+            + "MIIESTCCAjGgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29v"
+            + "Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTIwMDM4MDNa"
+            + "Fw0yMzAxMTEwMDM4MDNaMDoxODA2BgNVBAMML0dvb2dsZSBDcnlwdEF1dGhWYXVs"
+            + "dCBJbnRlcm1lZGlhdGUgSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOC"
+            + "AQ8AMIIBCgKCAQEA0v3bN3MwKifDAkF1524XzuaxYtk1sQKUlAlNngh+Qv4RjCkX"
+            + "TECi7po8LeNsY+hWxmW3XZ22RBphe/yP4YcOdbqlIjZYNx3b75hCSJCadOkdW+Z9"
+            + "f6+tKsHgeUja6r9r2TThzileImAvjXShe7GZYW8csPv6HaEVRXQlu8fGAZf8skmJ"
+            + "EMfJx84//WeULdVz94beDhi9YAf4gLfmOayQcdWhDcMYI39knJcRny1ffRGgb1Hf"
+            + "lE+3/a3aGFeODaxfkPaGRxEhzhZ/JDBiNgUAH/u7C5nxqa2WOu5e0wq3S0TndIOE"
+            + "hmnwCE2GvxADFQst+rSsOn4EHit70hv4CfrMRQIDAQABo2YwZDAdBgNVHQ4EFgQU"
+            + "0dKv4xTaEmdwHyox3tY8H8XVDGIwHwYDVR0jBBgwFoAURPUcR0+1NxD9b3Y0czWD"
+            + "K1OxLHgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI"
+            + "hvcNAQELBQADggIBAJaArqLlJ2SLQ8JRwanD6LPlqQxucQ+x/LztTQpzPrsFfJds"
+            + "E/sDZr2rXhDpz/bifIdj/DCbQ6/3w+t5JdFjT8GjXLgz1kCa/4W409FgSTgy1ENn"
+            + "AMUU6pFIbOq/Qy/71uOTrrFWYTN5Vk+RBGxx5iDfHjDYraudi4VlcNkal4OyM98n"
+            + "N3qp9cZD0RtWxMhvq6ahgmf9cTbEw6+l8yf/bogGLBYXXYeOoO5Q134AxrrgfthE"
+            + "tvyKwJkT/l3OFKRcaHrebs+V1z5gPs7zWOyO5n2Z1SAmcOGfTfKMZWwp3Hi3OTr2"
+            + "gB3LUYKyQVhC70dka3X+IbnFg5YfzJtX6YGnHlnI1SufOkEpGQDfcc0UQAWg/lgb"
+            + "RkfMFD9tuJomBhyqv1YaxLN8yL4ZTRU0KCvvC5I5+X/zt9kBjnHlBOdYtknZT5jz"
+            + "7+mjqWdpmWoAjeV5+CgIzG2k7JAm6rQuE1ZQNF0wAYxPret4NHPJFqfD5gGhdrYw"
+            + "pEUxkcwHERA/E1CkpyqUy/Hd3kqHvnEDqzFcxBdUdmOgnbpI2nAZdEpfxmA5+M1n"
+            + "UoxQ8ZWAZH+Mdlkw/Hx5hVjGjz8snD4QN25pj/wT+V6AR5OmYb8yfsQb2S8a8yDp"
+            + "HzcIHW+dEWpX2boirOsrdI16kNtxYqtG7c5qWBPJy5Zjkvh9qbnfT/RQx10g";
+    private static final String LEAF_CERT_1_BASE64 = ""
+            + "MIIDCDCB8aADAgECAgYBYOlweDswDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi"
+            + "R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAxMTEwODE1"
+            + "NTBaFw0yMDAxMTIwODE1NTBaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW"
+            + "YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu"
+            + "tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl"
+            + "4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBABZALhC9j3hpZ0AgN0tsqAP2Ix21"
+            + "tNOcvo/aFJuSFanOM4DZbycZEYAo5rorvuFu7eXETBKDGnI5xreNAoQsaj/dyCHu"
+            + "HKIn5P7yCmKvG2sV2TQ5go+0xV2x8BhTrtUWLeHvUbM3fXipa3NrordbA8MgzXwr"
+            + "GR1Y1FuMOn5n4kiuHJ2sQTbDdzSQSK5VpH+6rjARlfOCyLUX0u8UKRRH81qhIQWb"
+            + "UFMp9q1CVfiLP2O3CdDdpZXCysdflIb62TWnma+I8jqMryyxrMVs9kpfa8zkX9qe"
+            + "33Vxp+QaQTqQ07/7KYVw869MeFn+bXeHnjUhqGY6S8M71vrTMG3M5p8Sq9LmV8Y5"
+            + "7YB5uqKap2Inf0FOuJS7h7nVVzU/kOFkepaQVHyScwTPuuXNgpQg8XZnN/AWfRwJ"
+            + "hf5zE6vXXTHMzQA1mY2eEhxGfpryv7LH8pvfcyTakdBlw8aMJjKdre8xLLGZeVCa"
+            + "79plkfYD0rMrxtRHCGyTKGzUcx/B9kYJK5qBgJiDJLKF3XwGbAs/F8CyEPihjvj4"
+            + "M2EoeyhmHWKLYsps6+uTksJ+PxZU14M7672K2y8BdulyfkZIhili118XnRykKkMf"
+            + "JLQJKMqZx5O0B9bF8yQdcGKEGEwMQt5ENdH8HeiwLm4QS3VzFXYetgUPCM5lPDIp"
+            + "BuwwuQxvQDF4pmQd";
+    private static final String LEAF_CERT_2_BASE64 = ""
+            + "MIICrDCCAZSgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwOjE4MDYGA1UEAwwvR29v"
+            + "Z2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZSBJbnRlcm1lZGlhdGUwHhcN"
+            + "MTgwMTEyMDEwMzA5WhcNMTkwMTEyMDEwMzA5WjArMSkwJwYDVQQDDCBHb29nbGUg"
+            + "Q3J5cHRBdXRoVmF1bHQgSW5zdGFuY2UgMjBZMBMGByqGSM49AgEGCCqGSM49AwEH"
+            + "A0IABGhmBQyWdjsXKJRbkW4iIrvt6iqhX5t2XGt/vZS9CoOl0fs+EvJXo4kgrnx8"
+            + "/8SGxz3pwRkFhY943QYy6a1gv/2jgZUwgZIwCQYDVR0TBAIwADAdBgNVHQ4EFgQU"
+            + "xFmLyxUS2JHKURBtewBKRP6kQBgwVgYDVR0jBE8wTYAU0dKv4xTaEmdwHyox3tY8"
+            + "H8XVDGKhMaQvMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRl"
+            + "cm1lZGlhdGWCAhAAMA4GA1UdDwEB/wQEAwIDCDANBgkqhkiG9w0BAQsFAAOCAQEA"
+            + "EJWpl7HU6LxukLqhw2tVZr7IRrKIucRk+RKaaiMx1Hx2jsTTskiJRiZas/xoPSqX"
+            + "z1K5DVgI486i7HyqnWkGH5xVzCsv+rya5FOSTS3jVtgtoA4HFEqeeAcDowPDqVw3"
+            + "yFTA55ukZnzVaPLpDfPqkhzWiuLQ/4fI6YCmOnWB8KtHTMdyGsDSAkpoxpok++NJ"
+            + "Lu79BoBLe2ucjN383lTlieLxmrmHjF9ryYSQczcm0v6irMOMxEovw5iT4LHiEhbm"
+            + "DfOPW909fe/s+K3TGZ3Q6U77x8g5k9dVovMgA4pFwtREtknFjeK1wXR3/eXGcP3W"
+            + "0bMX1yTWYJQFWCG3DFoC5w==";
+
+    /** The cert of the root CA. */
+    static final X509Certificate ROOT_CA_TRUSTED = decodeBase64Cert(ROOT_CA_TRUSTED_BASE64);
+    /** This root CA cert has a different Common Name than ROOT_CA_TRUSTED. */
+    static final X509Certificate ROOT_CA_DIFFERENT_COMMON_NAME =
+            decodeBase64Cert(ROOT_CA_DIFFERENT_COMMON_NAME_BASE64);
+    /** This root CA cert has the same CN as ROOT_CA_TRUSTED, but a different public key. */
+    static final X509Certificate ROOT_CA_DIFFERENT_KEY =
+            decodeBase64Cert(ROOT_CA_DIFFERENT_KEY_BASE64);
+    /** This intermediate CA cert is signed by the corresponding private key of ROOT_CA_TRUSTED. */
+    static final X509Certificate INTERMEDIATE_CA_1 = decodeBase64Cert(INTERMEDIATE_CA_1_BASE64);
+    /** This intermediate CA cert is signed by the private key of INTERMEDIATE_CA_1. */
+    static final X509Certificate INTERMEDIATE_CA_2 = decodeBase64Cert(INTERMEDIATE_CA_2_BASE64);
+    /** This leaf cert is signed by the corresponding private key of INTERMEDIATE_CA_1. */
+    static final X509Certificate LEAF_CERT_1 = decodeBase64Cert(LEAF_CERT_1_BASE64);
+    /** This leaf cert is signed by the corresponding private key of INTERMEDIATE_CA_2. */
+    static final X509Certificate LEAF_CERT_2 = decodeBase64Cert(LEAF_CERT_2_BASE64);
+
+    private static X509Certificate decodeBase64Cert(String str) {
+        try {
+            byte[] bytes = Base64.getDecoder().decode(str);
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes));
+        } catch (Exception e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    static final Date DATE_ALL_CERTS_VALID = new Date(1516406400000L); // Jan 20, 2018
+    static final Date DATE_LEAF_CERT_2_EXPIRED = new Date(1547254989001L); // Jan 12, 2019
+    static final Date DATE_INTERMEDIATE_CA_2_EXPIRED = new Date(1673397483001L); // Jan 11, 2023
+
+    static InputStream openTestFile(String relativePath) throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+        return context.getResources().getAssets().open(TEST_FILE_FOLDER_NAME + "/" + relativePath);
+    }
+
+    static byte[] readTestFile(String relativePath) throws Exception {
+        InputStream in = openTestFile(relativePath);
+        return ByteStreams.toByteArray(in);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
new file mode 100644
index 0000000..37482a3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings.recoverablekeystore.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.KeysEntry;
+import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.RecoveryServiceMetadataEntry;
+import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDbContract.UserMetadataEntry;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecoverableKeyStoreDbHelperTest {
+
+    private static final long TEST_USER_ID = 10L;
+    private static final long TEST_UID = 60001L;
+    private static final String TEST_ALIAS = "test-alias";
+    private static final byte[] TEST_NONCE = "test-nonce".getBytes(UTF_8);
+    private static final byte[] TEST_WRAPPED_KEY = "test-wrapped-key".getBytes(UTF_8);
+    private static final long TEST_GENERATION_ID = 13L;
+    private static final long TEST_LAST_SYNCED_AT = 1517990732000L;
+    private static final int TEST_RECOVERY_STATUS = 3;
+    private static final int TEST_PLATFORM_KEY_GENERATION_ID = 11;
+    private static final int TEST_SNAPSHOT_VERSION = 31;
+    private static final int TEST_SHOULD_CREATE_SNAPSHOT = 1;
+    private static final byte[] TEST_PUBLIC_KEY = "test-public-key".getBytes(UTF_8);
+    private static final String TEST_SECRET_TYPES = "test-secret-types";
+    private static final long TEST_COUNTER_ID = -3981205205038476415L;
+    private static final byte[] TEST_SERVER_PARAMS = "test-server-params".getBytes(UTF_8);
+    private static final byte[] TEST_CERT_PATH = "test-cert-path".getBytes(UTF_8);
+    private static final long TEST_CERT_SERIAL = 1000L;
+
+    private static final String SQL_CREATE_V2_TABLE_KEYS =
+            "CREATE TABLE " + KeysEntry.TABLE_NAME + "( "
+                    + KeysEntry._ID + " INTEGER PRIMARY KEY,"
+                    + KeysEntry.COLUMN_NAME_USER_ID + " INTEGER,"
+                    + KeysEntry.COLUMN_NAME_UID + " INTEGER,"
+                    + KeysEntry.COLUMN_NAME_ALIAS + " TEXT,"
+                    + KeysEntry.COLUMN_NAME_NONCE + " BLOB,"
+                    + KeysEntry.COLUMN_NAME_WRAPPED_KEY + " BLOB,"
+                    + KeysEntry.COLUMN_NAME_GENERATION_ID + " INTEGER,"
+                    + KeysEntry.COLUMN_NAME_LAST_SYNCED_AT + " INTEGER,"
+                    + KeysEntry.COLUMN_NAME_RECOVERY_STATUS + " INTEGER,"
+                    + "UNIQUE(" + KeysEntry.COLUMN_NAME_UID + ","
+                    + KeysEntry.COLUMN_NAME_ALIAS + "))";
+
+    private static final String SQL_CREATE_V2_TABLE_USER_METADATA =
+            "CREATE TABLE " + UserMetadataEntry.TABLE_NAME + "( "
+                    + UserMetadataEntry._ID + " INTEGER PRIMARY KEY,"
+                    + UserMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER UNIQUE,"
+                    + UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID + " INTEGER)";
+
+    private static final String SQL_CREATE_V2_TABLE_RECOVERY_SERVICE_METADATA =
+            "CREATE TABLE " + RecoveryServiceMetadataEntry.TABLE_NAME + " ("
+                    + RecoveryServiceMetadataEntry._ID + " INTEGER PRIMARY KEY,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID + " INTEGER,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + " INTEGER,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION + " INTEGER,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT + " INTEGER,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY + " BLOB,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES + " TEXT,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID + " INTEGER,"
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS + " BLOB,"
+                    + "UNIQUE("
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID  + ","
+                    + RecoveryServiceMetadataEntry.COLUMN_NAME_UID + "))";
+
+    private SQLiteDatabase mDatabase;
+    private RecoverableKeyStoreDbHelper mDatabaseHelper;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getTargetContext();
+        mDatabaseHelper = new RecoverableKeyStoreDbHelper(context);
+        mDatabase = SQLiteDatabase.create(null);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mDatabase.close();
+    }
+
+    private void createV2Tables() throws Exception {
+        mDatabase.execSQL(SQL_CREATE_V2_TABLE_KEYS);
+        mDatabase.execSQL(SQL_CREATE_V2_TABLE_USER_METADATA);
+        mDatabase.execSQL(SQL_CREATE_V2_TABLE_RECOVERY_SERVICE_METADATA);
+    }
+
+    @Test
+    public void onCreate() throws Exception {
+        mDatabaseHelper.onCreate(mDatabase);
+        checkAllColumns();
+    }
+
+    @Test
+    public void onUpgrade_beforeV2() throws Exception {
+        mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 1,
+                RecoverableKeyStoreDbHelper.DATABASE_VERSION);
+        checkAllColumns();
+    }
+
+    @Test
+    public void onUpgrade_fromV2() throws Exception {
+        createV2Tables();
+        mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 2,
+                RecoverableKeyStoreDbHelper.DATABASE_VERSION);
+        checkAllColumns();
+    }
+
+    private void checkAllColumns() throws Exception {
+        // Check the table containing encrypted application keys
+        ContentValues values = new ContentValues();
+        values.put(KeysEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
+        values.put(KeysEntry.COLUMN_NAME_UID, TEST_UID);
+        values.put(KeysEntry.COLUMN_NAME_ALIAS, TEST_ALIAS);
+        values.put(KeysEntry.COLUMN_NAME_NONCE, TEST_NONCE);
+        values.put(KeysEntry.COLUMN_NAME_WRAPPED_KEY, TEST_WRAPPED_KEY);
+        values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, TEST_GENERATION_ID);
+        values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, TEST_LAST_SYNCED_AT);
+        values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, TEST_RECOVERY_STATUS);
+        assertThat(mDatabase.insert(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
+                .isGreaterThan(-1L);
+
+        // Check the table about user metadata
+        values = new ContentValues();
+        values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
+        values.put(UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID,
+                TEST_PLATFORM_KEY_GENERATION_ID);
+        assertThat(mDatabase.insert(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
+                .isGreaterThan(-1L);
+
+        // Check the table about recovery service metadata
+        values = new ContentValues();
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_UID, TEST_UID);
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SNAPSHOT_VERSION,
+                TEST_SNAPSHOT_VERSION);
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SHOULD_CREATE_SNAPSHOT,
+                TEST_SHOULD_CREATE_SNAPSHOT);
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_PUBLIC_KEY, TEST_PUBLIC_KEY);
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SECRET_TYPES, TEST_SECRET_TYPES);
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_COUNTER_ID, TEST_COUNTER_ID);
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_SERVER_PARAMS, TEST_SERVER_PARAMS);
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH, TEST_CERT_PATH);
+        values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, TEST_CERT_SERIAL);
+        assertThat(
+                mDatabase.insert(RecoveryServiceMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null,
+                        values))
+                .isGreaterThan(-1L);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index 097d214..1c5bcd4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -32,6 +32,8 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.locksettings.recoverablekeystore.TestData;
 import com.android.server.locksettings.recoverablekeystore.WrappedKey;
 
 import java.io.File;
@@ -370,6 +372,57 @@
                 pubkey);
     }
 
+    public void setRecoveryServiceCertPath_replaceOldValue() throws Exception {
+        int userId = 12;
+        int uid = 10009;
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TestData.CERT_PATH_1);
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TestData.CERT_PATH_2);
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
+                TestData.CERT_PATH_2);
+    }
+
+    @Test
+    public void getRecoveryServiceCertPath_returnsNullIfNoValue() throws Exception {
+        int userId = 12;
+        int uid = 10009;
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isNull();
+    }
+
+    @Test
+    public void getRecoveryServiceCertPath_returnsInsertedValue() throws Exception {
+        int userId = 12;
+        int uid = 10009;
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(userId, uid, TestData.CERT_PATH_1);
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo(
+                TestData.CERT_PATH_1);
+    }
+
+    @Test
+    public void setRecoveryServiceCertSerial_replaceOldValue() throws Exception {
+        int userId = 12;
+        int uid = 10009;
+
+        mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, 1L);
+        mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, 3L);
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isEqualTo(3L);
+    }
+
+    @Test
+    public void getRecoveryServiceCertSerial_returnsNullIfNoValue() throws Exception {
+        int userId = 12;
+        int uid = 10009;
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isNull();
+    }
+
+    @Test
+    public void getRecoveryServiceCertSerial_returnsInsertedValue() throws Exception {
+        int userId = 12;
+        int uid = 10009;
+        mRecoverableKeyStoreDb.setRecoveryServiceCertSerial(userId, uid, 1234L);
+        assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertSerial(userId, uid)).isEqualTo(
+                1234L);
+    }
+
     @Test
     public void getRecoveryAgents_returnsUidIfSet() throws Exception {
         int userId = 12;
@@ -493,17 +546,6 @@
     }
 
     @Test
-    public void getRecoveryServicePublicKey_returnsFirstKey() throws Exception {
-        int userId = 68;
-        int uid = 12904;
-        PublicKey publicKey = genRandomPublicKey();
-
-        mRecoverableKeyStoreDb.setRecoveryServicePublicKey(userId, uid, publicKey);
-
-        assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId)).isEqualTo(publicKey);
-    }
-
-    @Test
     public void setServerParams_replaceOldValue() throws Exception {
         int userId = 12;
         int uid = 10009;
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index 376db5b..6e1808b 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -117,7 +117,8 @@
     }
 
     @AfterClass
-    public static void tearDownOnce() {
+    public static void tearDownOnce() throws Exception {
+        batteryReset();
         if (mAppIdleConstsUpdated) {
             Settings.Global.putString(mContext.getContentResolver(),
                     Settings.Global.APP_IDLE_CONSTANTS, mOriginalAppIdleConsts);
@@ -213,12 +214,12 @@
     @Test
     public void testStartActivity_appStandby() throws Exception {
         try{
-            turnBatteryOff();
+            turnBatteryOn();
             setAppIdle(true);
             turnScreenOn();
             startActivityAndCheckNetworkAccess();
         } finally {
-            turnBatteryOn();
+            turnBatteryOff();
             finishActivity();
             setAppIdle(false);
         }
@@ -251,11 +252,11 @@
     // create a static library which can be used by both servicestests and cts.
     private void setBatterySaverMode(boolean enabled) throws Exception {
         if (enabled) {
-            turnBatteryOff();
+            turnBatteryOn();
             executeCommand("settings put global low_power 1");
         } else {
             executeCommand("settings put global low_power 0");
-            turnBatteryOn();
+            turnBatteryOff();
         }
         final String result = executeCommand("settings get global low_power");
         assertEquals(enabled ? "1" : "0", result);
@@ -271,12 +272,12 @@
 
     private void setDozeMode(boolean enabled) throws Exception {
         if (enabled) {
-            turnBatteryOff();
+            turnBatteryOn();
             turnScreenOff();
             executeCommand("dumpsys deviceidle force-idle deep");
         } else {
             turnScreenOn();
-            turnBatteryOn();
+            turnBatteryOff();
             executeCommand("dumpsys deviceidle unforce");
         }
         assertDelayedCommandResult("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE",
@@ -320,12 +321,12 @@
                 + ". Full list: " + uids);
     }
 
-    private void turnBatteryOff() throws Exception {
+    private void turnBatteryOn() throws Exception {
         executeCommand("cmd battery unplug");
-        assertBatteryOff();
+        assertBatteryOn();
     }
 
-    private void assertBatteryOff() throws Exception {
+    private void assertBatteryOn() throws Exception {
         final long endTime = SystemClock.uptimeMillis() + BATTERY_OFF_TIMEOUT_MS;
         while (mBatteryManager.isCharging() && SystemClock.uptimeMillis() < endTime) {
             SystemClock.sleep(BATTERY_OFF_CHECK_INTERVAL_MS);
@@ -333,7 +334,11 @@
         assertFalse("Power should be disconnected", mBatteryManager.isCharging());
     }
 
-    private void turnBatteryOn() throws Exception {
+    private void turnBatteryOff() throws Exception {
+        executeCommand("cmd battery set ac " + BatteryManager.BATTERY_PLUGGED_AC);
+    }
+
+    private static void batteryReset() throws Exception {
         executeCommand("cmd battery reset");
     }
 
@@ -348,7 +353,7 @@
         SystemClock.sleep(SCREEN_ON_DELAY_MS);
     }
 
-    private String executeCommand(String cmd) throws IOException {
+    private static String executeCommand(String cmd) throws IOException {
         final String result = executeSilentCommand(cmd);
         Log.d(TAG, String.format("Result for '%s': %s", cmd, result));
         return result;
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
index 070de5b..a38b353 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
@@ -16,18 +16,43 @@
 
 package com.android.server.net.watchlist;
 
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doAnswer;
+
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.FileUtils;
+import android.os.Looper;
+import android.os.UserManager;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.test.InstrumentationRegistry;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+
+import java.io.File;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 
 /**
  * runtest frameworks-services -c com.android.server.net.watchlist.WatchlistLoggingHandlerTests
@@ -36,18 +61,126 @@
 @SmallTest
 public class WatchlistLoggingHandlerTests {
 
+    private static final String APK_A = "A.apk";
+    private static final String APK_B = "B.apk";
+    private static final String APK_A_CONTENT = "AAA";
+    private static final String APK_B_CONTENT = "BBB";
+    // Sha256 of "AAA"
+    private static final String APK_A_CONTENT_HASH =
+            "CB1AD2119D8FAFB69566510EE712661F9F14B83385006EF92AEC47F523A38358";
+    // Sha256 of "BBB"
+    private static final String APK_B_CONTENT_HASH =
+            "DCDB704109A454784B81229D2B05F368692E758BFA33CB61D04C1B93791B0273";
+
+    private Context mServiceContext;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        final Context context = InstrumentationRegistry.getContext();
+        final UserManager mockUserManager = mock(UserManager.class);
+        final PackageManager mockPackageManager = mock(PackageManager.class);
+
+        // Context that will be used by WatchlistLoggingHandler
+        mServiceContext = new ContextWrapper(context) {
+            @Override
+            public PackageManager getPackageManager() {
+                return mockPackageManager;
+            }
+
+            @Override
+            public Object getSystemService(String name) {
+                switch (name) {
+                    case Context.USER_SERVICE:
+                        return mockUserManager;
+                    default:
+                        return super.getSystemService(name);
+                }
+            }
+        };
+
+        // Returns 2 users, user 0 and user 10
+        doAnswer((InvocationOnMock invocation) -> {
+            final ArrayList<UserInfo> info = new ArrayList<>();
+            info.add(new UserInfo(0, "user1", 0));
+            info.add(new UserInfo(10, "user2", 0));
+            return info;
+        }).when(mockUserManager).getUsers();
+
+        // Returns 2 apps, with uid 1 and uid 2
+        doAnswer((InvocationOnMock invocation) -> {
+            final List<ApplicationInfo> result = new ArrayList<>();
+            ApplicationInfo info1 = new ApplicationInfo();
+            info1.uid = 1;
+            result.add(info1);
+            ApplicationInfo info2 = new ApplicationInfo();
+            info2.uid = 2;
+            result.add(info2);
+            return result;
+        }).when(mockPackageManager).getInstalledApplications(anyInt());
+
+        // Uid 1 app with is installed in primary user and package name is "A"
+        // Uid 2 app is installed in secondary user and package name is "B"
+        doAnswer((InvocationOnMock invocation) -> {
+            int uid = (int) invocation.getArguments()[0];
+            if (uid == 1) {
+                return new String[]{"A"};
+            } else if (uid == 1000001) {
+                return null;
+            } else if (uid == 2) {
+                return null;
+            } else if (uid == 1000002) {
+                return new String[]{"B"};
+            }
+            return null;
+        }).when(mockPackageManager).getPackagesForUid(anyInt());
+
+        String fileDir = InstrumentationRegistry.getContext().getFilesDir().getAbsolutePath();
+        // Simulate app's apk file path
+        doAnswer((InvocationOnMock invocation) -> {
+            String pkg = (String) invocation.getArguments()[0];
+            PackageInfo result = new PackageInfo();
+            result.applicationInfo = new ApplicationInfo();
+            result.applicationInfo.publicSourceDir = fileDir + "/" + pkg + ".apk";
+            return result;
+        }).when(mockPackageManager).getPackageInfoAsUser(anyString(), anyInt(), anyInt());
+
+        FileUtils.bytesToFile(fileDir + "/" + APK_A, APK_A_CONTENT.getBytes());
+        FileUtils.bytesToFile(fileDir + "/" + APK_B, APK_B_CONTENT.getBytes());
+    }
+
+    @After
+    public void tearDown() {
+        String fileDir = InstrumentationRegistry.getContext().getFilesDir().getAbsolutePath();
+        new File(fileDir, APK_A).delete();
+        new File(fileDir, APK_B).delete();
+    }
+
+    @Test
+    public void testWatchlistLoggingHandler_getAllDigestsForReportWithMultiUsers()
+            throws Exception {
+        List<String> result = new WatchlistLoggingHandler(mServiceContext,
+                Looper.getMainLooper()).getAllDigestsForReport(
+                new WatchlistReportDbHelper.AggregatedResult(new HashSet<String>(), null,
+                        new HashMap<String, String>()));
+        assertEquals(2, result.size());
+        assertEquals(APK_A_CONTENT_HASH, result.get(0));
+        assertEquals(APK_B_CONTENT_HASH, result.get(1));
+    }
+
     @Test
     public void testWatchlistLoggingHandler_getAllSubDomains() throws Exception {
         String[] subDomains = WatchlistLoggingHandler.getAllSubDomains("abc.def.gh.i.jkl.mm");
-        assertTrue(Arrays.equals(subDomains, new String[] {"abc.def.gh.i.jkl.mm",
+        assertTrue(Arrays.equals(subDomains, new String[]{"abc.def.gh.i.jkl.mm",
                 "def.gh.i.jkl.mm", "gh.i.jkl.mm", "i.jkl.mm", "jkl.mm", "mm"}));
         subDomains = WatchlistLoggingHandler.getAllSubDomains(null);
         assertNull(subDomains);
         subDomains = WatchlistLoggingHandler.getAllSubDomains("jkl.mm");
-        assertTrue(Arrays.equals(subDomains, new String[] {"jkl.mm", "mm"}));
+        assertTrue(Arrays.equals(subDomains, new String[]{"jkl.mm", "mm"}));
         subDomains = WatchlistLoggingHandler.getAllSubDomains("abc");
-        assertTrue(Arrays.equals(subDomains, new String[] {"abc"}));
+        assertTrue(Arrays.equals(subDomains, new String[]{"abc"}));
         subDomains = WatchlistLoggingHandler.getAllSubDomains("jkl.mm.");
-        assertTrue(Arrays.equals(subDomains, new String[] {"jkl.mm.", "mm."}));
+        assertTrue(Arrays.equals(subDomains, new String[]{"jkl.mm.", "mm."}));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 0abb48f..98483a8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -294,7 +294,7 @@
                 null /*disabledPkg*/,
                 null /*sharedUser*/,
                 UPDATED_CODE_PATH /*codePath*/,
-                null /*resourcePath*/,
+                UPDATED_CODE_PATH /*resourcePath*/,
                 null /*legacyNativeLibraryPath*/,
                 "arm64-v8a" /*primaryCpuAbi*/,
                 "armeabi" /*secondaryCpuAbi*/,
@@ -328,7 +328,7 @@
                 null /*disabledPkg*/,
                 null /*sharedUser*/,
                 UPDATED_CODE_PATH /*codePath*/,
-                null /*resourcePath*/,
+                UPDATED_CODE_PATH /*resourcePath*/,
                 null /*legacyNativeLibraryPath*/,
                 "arm64-v8a" /*primaryCpuAbi*/,
                 "armeabi" /*secondaryCpuAbi*/,
@@ -561,34 +561,6 @@
                 false /*notLaunched*/, false /*stopped*/, true /*installed*/);
     }
 
-    @Test
-    public void testInsertPackageSetting() {
-        final PackageSetting ps = createPackageSetting(0 /*sharedUserId*/, 0 /*pkgFlags*/);
-        final PackageParser.Package pkg = new PackageParser.Package(PACKAGE_NAME);
-        pkg.applicationInfo.setCodePath(ps.codePathString);
-        pkg.applicationInfo.setResourcePath(ps.resourcePathString);
-        final Context context = InstrumentationRegistry.getContext();
-        final Object lock = new Object();
-        PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
-        final Settings settings =
-                new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
-        pkg.usesStaticLibraries = new ArrayList<>(
-                Arrays.asList("foo.bar1", "foo.bar2", "foo.bar3"));
-        pkg.usesStaticLibrariesVersions = new long[] {2, 4, 6};
-        settings.insertPackageSettingLPw(ps, pkg);
-        assertEquals(pkg, ps.pkg);
-        assertArrayEquals(pkg.usesStaticLibraries.toArray(new String[0]), ps.usesStaticLibraries);
-        assertArrayEquals(pkg.usesStaticLibrariesVersions, ps.usesStaticLibrariesVersions);
-
-        pkg.usesStaticLibraries = null;
-        pkg.usesStaticLibrariesVersions = null;
-        settings.insertPackageSettingLPw(ps, pkg);
-        assertEquals(pkg, ps.pkg);
-        assertNull("Actual: " + Arrays.toString(ps.usesStaticLibraries), ps.usesStaticLibraries);
-        assertNull("Actual: " + Arrays.toString(ps.usesStaticLibrariesVersions),
-                ps.usesStaticLibrariesVersions);
-    }
-
     private <T> void assertArrayEquals(T[] a, T[] b) {
         assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b),
                 Arrays.equals(a, b));
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index 5de393c..a628b7b 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -79,6 +79,11 @@
     }
 
     @Override
+    public Point getShownPositionLw() {
+        return new Point(parentFrame.left, parentFrame.top);
+    }
+
+    @Override
     public Rect getDisplayFrameLw() {
         return displayFrame;
     }
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
index 9cf6392..d9f4adf 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
@@ -31,7 +31,6 @@
 import android.support.test.filters.SmallTest;
 
 import java.io.File;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.time.Clock;
@@ -1400,7 +1399,7 @@
     /**
      * A fake IntentHelper implementation for use in tests.
      */
-    private static class FakeIntentHelper implements IntentHelper {
+    private static class FakeIntentHelper implements PackageTrackerIntentHelper {
 
         private PackageTracker mPackageTracker;
         private String mUpdateAppPackageName;
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
index 1cfae1e..f5969f3 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
@@ -68,6 +68,7 @@
 
     private FakeExecutor mFakeExecutor;
     private PermissionHelper mMockPermissionHelper;
+    private RulesManagerIntentHelper mMockIntentHelper;
     private PackageTracker mMockPackageTracker;
     private TimeZoneDistroInstaller mMockTimeZoneDistroInstaller;
 
@@ -77,11 +78,13 @@
 
         mMockPackageTracker = mock(PackageTracker.class);
         mMockPermissionHelper = mock(PermissionHelper.class);
+        mMockIntentHelper = mock(RulesManagerIntentHelper.class);
         mMockTimeZoneDistroInstaller = mock(TimeZoneDistroInstaller.class);
 
         mRulesManagerService = new RulesManagerService(
                 mMockPermissionHelper,
                 mFakeExecutor,
+                mMockIntentHelper,
                 mMockPackageTracker,
                 mMockTimeZoneDistroInstaller);
     }
@@ -329,6 +332,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -353,6 +357,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -372,6 +377,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -394,6 +400,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -416,6 +423,7 @@
         callback.assertNoResultReceived();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_SUCCESS);
@@ -428,6 +436,7 @@
         // Verify the expected calls were made to other components.
         verifyStageInstallCalled();
         verifyPackageTrackerCalled(token, true /* success */);
+        verifyStagedOperationIntentSent();
 
         // Check the callback was called.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -450,6 +459,7 @@
         // Assert nothing has happened yet.
         verifyNoInstallerCallsMade();
         callback.assertNoResultReceived();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_SUCCESS);
@@ -462,6 +472,7 @@
         // Verify the expected calls were made to other components.
         verifyStageInstallCalled();
         verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
+        verifyStagedOperationIntentSent();
 
         // Check the callback was received.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -486,6 +497,7 @@
         // Assert nothing has happened yet.
         verifyNoInstallerCallsMade();
         callback.assertNoResultReceived();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR);
@@ -502,6 +514,9 @@
         boolean expectedSuccess = true;
         verifyPackageTrackerCalled(token, expectedSuccess);
 
+        // Nothing should be staged, so no intents sent.
+        verifyNoIntentsSent();
+
         // Check the callback was received.
         callback.assertResultReceived(Callback.ERROR_INSTALL_VALIDATION_ERROR);
     }
@@ -529,6 +544,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -548,6 +564,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -566,6 +583,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -585,6 +603,7 @@
         callback.assertNoResultReceived();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_SUCCESS);
@@ -595,6 +614,7 @@
         // Verify the expected calls were made to other components.
         verifyStageUninstallCalled();
         verifyPackageTrackerCalled(token, true /* success */);
+        verifyStagedOperationIntentSent();
 
         // Check the callback was called.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -617,6 +637,7 @@
         callback.assertNoResultReceived();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_NOTHING_INSTALLED);
@@ -627,6 +648,7 @@
         // Verify the expected calls were made to other components.
         verifyStageUninstallCalled();
         verifyPackageTrackerCalled(token, true /* success */);
+        verifyUnstagedOperationIntentSent();
 
         // Check the callback was called.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -645,6 +667,7 @@
         // Assert nothing has happened yet.
         verifyNoInstallerCallsMade();
         callback.assertNoResultReceived();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_SUCCESS);
@@ -655,6 +678,7 @@
         // Verify the expected calls were made to other components.
         verifyStageUninstallCalled();
         verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
+        verifyStagedOperationIntentSent();
 
         // Check the callback was received.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -676,6 +700,7 @@
         // Assert nothing has happened yet.
         verifyNoInstallerCallsMade();
         callback.assertNoResultReceived();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_FAIL);
@@ -686,6 +711,7 @@
         // Verify the expected calls were made to other components.
         verifyStageUninstallCalled();
         verifyPackageTrackerCalled(token, false /* success */);
+        verifyNoIntentsSent();
 
         // Check the callback was received.
         callback.assertResultReceived(Callback.ERROR_UNKNOWN_FAILURE);
@@ -714,6 +740,7 @@
         // Verify the expected calls were made to other components.
         verifyPackageTrackerCalled(token, true /* success */);
         verifyNoInstallerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -734,6 +761,7 @@
         // Assert no other calls were made.
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -749,6 +777,7 @@
         // Assert everything required was done.
         verifyNoInstallerCallsMade();
         verifyPackageTrackerCalled(token, false /* success */);
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -761,6 +790,7 @@
         // Assert everything required was done.
         verifyNoInstallerCallsMade();
         verifyPackageTrackerCalled(null /* token */, true /* success */);
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -865,6 +895,21 @@
         reset(mMockPackageTracker);
     }
 
+    private void verifyNoIntentsSent() {
+        verifyNoMoreInteractions(mMockIntentHelper);
+        reset(mMockIntentHelper);
+    }
+
+    private void verifyStagedOperationIntentSent() {
+        verify(mMockIntentHelper).sendTimeZoneOperationStaged();
+        reset(mMockIntentHelper);
+    }
+
+    private void verifyUnstagedOperationIntentSent() {
+        verify(mMockIntentHelper).sendTimeZoneOperationUnstaged();
+        reset(mMockIntentHelper);
+    }
+
     private void configureCallerHasPermission() throws Exception {
         doNothing()
                 .when(mMockPermissionHelper)
diff --git a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
index 396fef4..57dd808 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
@@ -18,11 +18,9 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.graphics.Rect;
@@ -32,24 +30,17 @@
 import android.view.SurfaceSession;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.stubbing.Answer;
 
 /**
  * Build/Install/Run:
  * atest FrameworksServicesTests:com.android.server.wm.DimmerTests;
  */
 @Presubmit
-@Ignore("b/72450130")
 @RunWith(AndroidJUnit4.class)
 public class DimmerTests extends WindowTestsBase {
 
-    public DimmerTests() {
-        super(spy(new SurfaceAnimationRunner()));
-    }
-
     private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
         final SurfaceControl mControl = mock(SurfaceControl.class);
         final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class);
@@ -71,14 +62,11 @@
 
     private class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> {
         final SurfaceSession mSession = new SurfaceSession();
+        final SurfaceControl mHostControl = mock(SurfaceControl.class);
         final SurfaceControl.Transaction mHostTransaction = mock(SurfaceControl.Transaction.class);
 
         MockSurfaceBuildingContainer() {
             super(sWm);
-            mSurfaceControl = sWm.makeSurfaceBuilder(mSession)
-                    .setName("test surface")
-                    .setSize(1, 1)
-                    .build();
         }
 
         class MockSurfaceBuilder extends SurfaceControl.Builder {
@@ -88,34 +76,29 @@
 
             @Override
             public SurfaceControl build() {
-                return spy(sWm.makeSurfaceBuilder(mSession)
-                        .setName("test surface")
-                        .setSize(1, 1)
-                        .build());
+                return mock(SurfaceControl.class);
             }
         }
 
         @Override
-        SurfaceControl.Builder makeSurface() {
-            return sWm.makeSurfaceBuilder(mSession)
-                    .setName("test surface")
-                    .setSize(1, 1);
-        }
-
-        @Override
         SurfaceControl.Builder makeChildSurface(WindowContainer child) {
             return new MockSurfaceBuilder(mSession);
         }
 
         @Override
+        public SurfaceControl getSurfaceControl() {
+            return mHostControl;
+        }
+
+        @Override
         public SurfaceControl.Transaction getPendingTransaction() {
             return mHostTransaction;
         }
     }
 
-    MockSurfaceBuildingContainer mHost;
-    Dimmer mDimmer;
-    SurfaceControl.Transaction mTransaction;
+    private MockSurfaceBuildingContainer mHost;
+    private Dimmer mDimmer;
+    private SurfaceControl.Transaction mTransaction;
 
     @Before
     public void setUp() throws Exception {
@@ -123,13 +106,9 @@
         mHost = new MockSurfaceBuildingContainer();
 
         mTransaction = mock(SurfaceControl.Transaction.class);
-        mDimmer = new Dimmer(mHost);
-
-        doAnswer((Answer<Void>) invocation -> {
-            Runnable runnable = invocation.getArgument(3);
-            runnable.run();
-            return null;
-        }).when(sWm.mSurfaceAnimationRunner).startAnimation(any(), any(), any(), any());
+        mDimmer = new Dimmer(mHost,
+                (surfaceAnimator, t, anim, hidden) -> surfaceAnimator.mAnimationFinishedCallback
+                        .run());
     }
 
     @Test
@@ -137,7 +116,7 @@
         final float alpha = 0.8f;
         mDimmer.dimAbove(mTransaction, alpha);
 
-        SurfaceControl dimLayer = getDimLayer(null);
+        SurfaceControl dimLayer = getDimLayer();
 
         assertNotNull("Dimmer should have created a surface", dimLayer);
 
@@ -149,12 +128,12 @@
     public void testDimAboveNoChildRedundantlyUpdatesAlphaOnExistingSurface() throws Exception {
         float alpha = 0.8f;
         mDimmer.dimAbove(mTransaction, alpha);
-        final SurfaceControl firstSurface = getDimLayer(null);
+        final SurfaceControl firstSurface = getDimLayer();
 
         alpha = 0.9f;
         mDimmer.dimAbove(mTransaction, alpha);
 
-        assertEquals(firstSurface, getDimLayer(null));
+        assertEquals(firstSurface, getDimLayer());
         verify(mTransaction).setAlpha(firstSurface, 0.9f);
     }
 
@@ -167,18 +146,18 @@
         Rect bounds = new Rect(0, 0, width, height);
         mDimmer.updateDims(mTransaction, bounds);
 
-        verify(mTransaction).setSize(getDimLayer(null), width, height);
-        verify(mTransaction).show(getDimLayer(null));
+        verify(mTransaction).setSize(getDimLayer(), width, height);
+        verify(mTransaction).show(getDimLayer());
     }
 
     @Test
     public void testDimAboveNoChildNotReset() throws Exception {
         mDimmer.dimAbove(mTransaction, 0.8f);
-        SurfaceControl dimLayer = getDimLayer(null);
+        SurfaceControl dimLayer = getDimLayer();
         mDimmer.resetDimStates();
 
         mDimmer.updateDims(mTransaction, new Rect());
-        verify(mTransaction).show(getDimLayer(null));
+        verify(mTransaction).show(getDimLayer());
         verify(dimLayer, never()).destroy();
     }
 
@@ -189,12 +168,12 @@
 
         final float alpha = 0.8f;
         mDimmer.dimAbove(mTransaction, child, alpha);
-        SurfaceControl mDimLayer = getDimLayer(child);
+        SurfaceControl dimLayer = getDimLayer();
 
-        assertNotNull("Dimmer should have created a surface", mDimLayer);
+        assertNotNull("Dimmer should have created a surface", dimLayer);
 
-        verify(mTransaction).setAlpha(mDimLayer, alpha);
-        verify(mTransaction).setRelativeLayer(mDimLayer, child.mControl, 1);
+        verify(mTransaction).setAlpha(dimLayer, alpha);
+        verify(mTransaction).setRelativeLayer(dimLayer, child.mControl, 1);
     }
 
     @Test
@@ -204,12 +183,12 @@
 
         final float alpha = 0.8f;
         mDimmer.dimBelow(mTransaction, child, alpha);
-        SurfaceControl mDimLayer = getDimLayer(child);
+        SurfaceControl dimLayer = getDimLayer();
 
-        assertNotNull("Dimmer should have created a surface", mDimLayer);
+        assertNotNull("Dimmer should have created a surface", dimLayer);
 
-        verify(mTransaction).setAlpha(mDimLayer, alpha);
-        verify(mTransaction).setRelativeLayer(mDimLayer, child.mControl, -1);
+        verify(mTransaction).setAlpha(dimLayer, alpha);
+        verify(mTransaction).setRelativeLayer(dimLayer, child.mControl, -1);
     }
 
     @Test
@@ -219,7 +198,7 @@
 
         final float alpha = 0.8f;
         mDimmer.dimAbove(mTransaction, child, alpha);
-        SurfaceControl dimLayer = getDimLayer(child);
+        SurfaceControl dimLayer = getDimLayer();
         mDimmer.resetDimStates();
 
         mDimmer.updateDims(mTransaction, new Rect());
@@ -233,7 +212,7 @@
 
         final float alpha = 0.8f;
         mDimmer.dimAbove(mTransaction, child, alpha);
-        SurfaceControl dimLayer = getDimLayer(child);
+        SurfaceControl dimLayer = getDimLayer();
         mDimmer.resetDimStates();
         mDimmer.dimAbove(mTransaction, child, alpha);
 
@@ -242,7 +221,29 @@
         verify(dimLayer, never()).destroy();
     }
 
-    private SurfaceControl getDimLayer(WindowContainer windowContainer) {
-        return mDimmer.mDimLayerUsers.get(windowContainer).mDimLayer;
+    @Test
+    public void testDimUpdateWhileDimming() throws Exception {
+        Rect bounds = new Rect();
+        TestWindowContainer child = new TestWindowContainer();
+        mHost.addChild(child, 0);
+
+        final float alpha = 0.8f;
+        mDimmer.dimAbove(mTransaction, child, alpha);
+
+        SurfaceControl dimLayer = getDimLayer();
+        bounds.set(0, 0, 10, 10);
+        mDimmer.updateDims(mTransaction, bounds);
+        verify(mTransaction, times(1)).show(dimLayer);
+        verify(mTransaction).setSize(dimLayer, bounds.width(), bounds.height());
+        verify(mTransaction).setPosition(dimLayer, 0, 0);
+
+        bounds.set(10, 10, 30, 30);
+        mDimmer.updateDims(mTransaction, bounds);
+        verify(mTransaction).setSize(dimLayer, bounds.width(), bounds.height());
+        verify(mTransaction).setPosition(dimLayer, 10, 10);
+    }
+
+    private SurfaceControl getDimLayer() {
+        return mDimmer.mDimState.mDimLayer;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 2284bbb..63ac4af 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -28,6 +28,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -38,7 +39,6 @@
 import android.annotation.SuppressLint;
 import android.content.res.Configuration;
 import android.graphics.Path;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -166,6 +166,7 @@
         assertTrue(appWin.canBeImeTarget());
         WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
         assertEquals(appWin, imeTarget);
+        appWin.mHidden = false;
 
         // Verify that an child window can be an ime target.
         final WindowState childWin = createWindow(appWin,
diff --git a/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
index f23bd62..3a1485e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.graphics.Color.BLUE;
 import static android.graphics.Color.RED;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
@@ -27,7 +26,6 @@
 import static android.view.Gravity.RIGHT;
 import static android.view.Gravity.TOP;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -49,6 +47,7 @@
 import android.os.Handler;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Pair;
@@ -66,18 +65,19 @@
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
+import java.util.function.BooleanSupplier;
 
 /**
  * Tests for the {@link android.view.WindowManager.LayoutParams#PRIVATE_FLAG_IS_SCREEN_DECOR} flag.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.ScreenDecorWindowTests
+ *  atest FrameworksServicesTests:com.android.server.wm.ScreenDecorWindowTests
  */
 // TODO: Add test for FLAG_FULLSCREEN which hides the status bar and also other flags.
 // TODO: Test non-Activity windows.
 @SmallTest
-// TODO(b/68957554)
-//@Presubmit
+@Presubmit
+@FlakyTest(bugId = 68957554)
 @RunWith(AndroidJUnit4.class)
 public class ScreenDecorWindowTests {
 
@@ -123,40 +123,33 @@
     public void testScreenSides() throws Exception {
         // Decor on top
         final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
-        WindowInsets insets = getInsets(mTestActivity);
-        assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
 
         // Decor at the bottom
         updateWindow(decorWindow, BOTTOM, MATCH_PARENT, mDecorThickness, 0, 0);
-        insets = getInsets(mTestActivity);
-        assertGreaterOrEqual(insets.getSystemWindowInsetBottom(), mDecorThickness);
+        assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mDecorThickness);
 
         // Decor to the left
         updateWindow(decorWindow, LEFT, mDecorThickness, MATCH_PARENT, 0, 0);
-        insets = getInsets(mTestActivity);
-        assertGreaterOrEqual(insets.getSystemWindowInsetLeft(), mDecorThickness);
+        assertInsetGreaterOrEqual(mTestActivity, LEFT, mDecorThickness);
 
         // Decor to the right
         updateWindow(decorWindow, RIGHT, mDecorThickness, MATCH_PARENT, 0, 0);
-        insets = getInsets(mTestActivity);
-        assertGreaterOrEqual(insets.getSystemWindowInsetRight(), mDecorThickness);
+        assertInsetGreaterOrEqual(mTestActivity, RIGHT, mDecorThickness);
     }
 
     @Test
     public void testMultipleDecors() throws Exception {
         // Test 2 decor windows on-top.
         createDecorWindow(TOP, MATCH_PARENT, mHalfDecorThickness);
-        WindowInsets insets = getInsets(mTestActivity);
-        assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mHalfDecorThickness);
+        assertInsetGreaterOrEqual(mTestActivity, TOP, mHalfDecorThickness);
         createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
-        insets = getInsets(mTestActivity);
-        assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
 
         // And one at the bottom.
         createDecorWindow(BOTTOM, MATCH_PARENT, mHalfDecorThickness);
-        insets = getInsets(mTestActivity);
-        assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
-        assertGreaterOrEqual(insets.getSystemWindowInsetBottom(), mHalfDecorThickness);
+        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
+        assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mHalfDecorThickness);
     }
 
     @Test
@@ -164,18 +157,15 @@
         WindowInsets initialInsets = getInsets(mTestActivity);
 
         final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
-        WindowInsets insets = getInsets(mTestActivity);
-        assertEquals(mDecorThickness, insets.getSystemWindowInsetTop());
+        assertTopInsetEquals(mTestActivity, mDecorThickness);
 
         updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
                 0, PRIVATE_FLAG_IS_SCREEN_DECOR);
-        insets = getInsets(mTestActivity);
-        assertEquals(initialInsets.getSystemWindowInsetTop(), insets.getSystemWindowInsetTop());
+        assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
 
         updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
                 PRIVATE_FLAG_IS_SCREEN_DECOR, PRIVATE_FLAG_IS_SCREEN_DECOR);
-        insets = getInsets(mTestActivity);
-        assertEquals(mDecorThickness, insets.getSystemWindowInsetTop());
+        assertTopInsetEquals(mTestActivity, mDecorThickness);
     }
 
     @Test
@@ -183,17 +173,10 @@
         WindowInsets initialInsets = getInsets(mTestActivity);
 
         final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
-        WindowInsets insets = getInsets(mTestActivity);
-        assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+        assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
 
         removeWindow(decorWindow);
-        insets = getInsets(mTestActivity);
-        assertEquals(initialInsets.getSystemWindowInsetTop(), insets.getSystemWindowInsetTop());
-    }
-
-    private View createAppWindow() {
-        return createWindow("appWindow", TOP, MATCH_PARENT, MATCH_PARENT, BLUE,
-                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR, 0);
+        assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
     }
 
     private View createDecorWindow(int gravity, int width, int height) {
@@ -249,10 +232,6 @@
         waitForIdle();
     }
 
-    private WindowInsets getInsets(View v) {
-        return new WindowInsets(v.getRootWindowInsets());
-    }
-
     private WindowInsets getInsets(Activity a) {
         return new WindowInsets(a.getWindow().getDecorView().getRootWindowInsets());
     }
@@ -269,11 +248,59 @@
         lp.flags = (lp.flags & ~mask) | (flags & mask);
     }
 
+    /**
+     * Asserts the top inset of {@param activity} is equal to {@param expected} waiting as needed.
+     */
+    private void assertTopInsetEquals(Activity activity, int expected) throws Exception {
+        waitFor(() -> getInsets(activity).getSystemWindowInsetTop() == expected);
+        assertEquals(expected, getInsets(activity).getSystemWindowInsetTop());
+    }
+
+    /**
+     * Asserts the inset at {@param side} of {@param activity} is equal to {@param expected}
+     * waiting as needed.
+     */
+    private void assertInsetGreaterOrEqual(Activity activity, int side, int expected)
+            throws Exception {
+        waitFor(() -> {
+            final WindowInsets insets = getInsets(activity);
+            switch (side) {
+                case TOP: return insets.getSystemWindowInsetTop() >= expected;
+                case BOTTOM: return insets.getSystemWindowInsetBottom() >= expected;
+                case LEFT: return insets.getSystemWindowInsetLeft() >= expected;
+                case RIGHT: return insets.getSystemWindowInsetRight() >= expected;
+                default: return true;
+            }
+        });
+
+        final WindowInsets insets = getInsets(activity);
+        switch (side) {
+            case TOP: assertGreaterOrEqual(insets.getSystemWindowInsetTop(), expected); break;
+            case BOTTOM: assertGreaterOrEqual(insets.getSystemWindowInsetBottom(), expected); break;
+            case LEFT: assertGreaterOrEqual(insets.getSystemWindowInsetLeft(), expected); break;
+            case RIGHT: assertGreaterOrEqual(insets.getSystemWindowInsetRight(), expected); break;
+        }
+    }
+
     /** Asserts that the first entry is greater than or equal to the second entry. */
     private void assertGreaterOrEqual(int first, int second) throws Exception {
         Assert.assertTrue("Excepted " + first + " >= " + second, first >= second);
     }
 
+    private void waitFor(BooleanSupplier waitCondition) {
+        int retriesLeft = 5;
+        do {
+            if (waitCondition.getAsBoolean()) {
+                break;
+            }
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException e) {
+                // Well I guess we are not waiting...
+            }
+        } while (retriesLeft-- > 0);
+    }
+
     private void finishActivity(Activity a) {
         if (a == null) {
             return;
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 81fd889..7a55904 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
@@ -69,11 +70,6 @@
     private Runnable mRunnableWhenAddingSplashScreen;
 
     static synchronized WindowManagerService getWindowManagerService(Context context) {
-        return getWindowManagerService(context, new SurfaceAnimationRunner());
-    }
-
-    static synchronized WindowManagerService getWindowManagerService(Context context,
-            SurfaceAnimationRunner surfaceAnimationRunner) {
         if (sWm == null) {
             // We only want to do this once for the test process as we don't want WM to try to
             // register a bunch of local services again.
@@ -111,7 +107,14 @@
             }
 
             sWm = WindowManagerService.main(context, ims, true, false,
-                    false, new TestWindowManagerPolicy(), surfaceAnimationRunner);
+                    false, new TestWindowManagerPolicy());
+
+            sWm.onInitReady();
+
+            // Display creation is driven by the ActivityManagerService via ActivityStackSupervisor.
+            // We emulate those steps here.
+            sWm.mRoot.createDisplayContent(sWm.mDisplayManager.getDisplay(DEFAULT_DISPLAY),
+                    mock(DisplayWindowController.class));
         }
         return sWm;
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 6a4710b..74c72bf 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -36,10 +36,15 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
 
 /**
  * Tests for the {@link WindowState} class.
@@ -57,15 +62,17 @@
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
         final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
 
-        assertFalse(parentWindow.mHidden);
+        // parentWindow is initially set to hidden.
+        assertTrue(parentWindow.mHidden);
+        assertFalse(parentWindow.isParentWindowHidden());
+        assertTrue(child1.isParentWindowHidden());
+        assertTrue(child2.isParentWindowHidden());
+
+        parentWindow.mHidden = false;
         assertFalse(parentWindow.isParentWindowHidden());
         assertFalse(child1.isParentWindowHidden());
         assertFalse(child2.isParentWindowHidden());
 
-        parentWindow.mHidden = true;
-        assertFalse(parentWindow.isParentWindowHidden());
-        assertTrue(child1.isParentWindowHidden());
-        assertTrue(child2.isParentWindowHidden());
     }
 
     @Test
@@ -237,11 +244,11 @@
     }
 
     private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) {
+        reset(mPowerManagerWrapper);
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
         root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
-        root.mTurnOnScreen = false;
 
         root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
-        assertTrue(root.mTurnOnScreen);
+        verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 7918901..91d5ea4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -29,6 +29,7 @@
 import org.junit.Assert;
 import org.junit.After;
 import org.junit.Before;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import android.content.Context;
@@ -84,15 +85,8 @@
     WindowState mChildAppWindowBelow;
     HashSet<WindowState> mCommonWindows;
 
-    private final SurfaceAnimationRunner mSurfaceAnimationRunner;
-
-    public WindowTestsBase() {
-        this(new SurfaceAnimationRunner());
-    }
-
-    public WindowTestsBase(SurfaceAnimationRunner surfaceAnimationRunner) {
-        mSurfaceAnimationRunner = surfaceAnimationRunner;
-    }
+    @Mock
+    static WindowState.PowerManagerWrapper mPowerManagerWrapper;
 
     @Before
     public void setUp() throws Exception {
@@ -108,7 +102,7 @@
         final Context context = InstrumentationRegistry.getTargetContext();
         AttributeCache.init(context);
 
-        sWm = TestWindowManagerPolicy.getWindowManagerService(context, mSurfaceAnimationRunner);
+        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
         beforeCreateDisplay();
 
         context.getDisplay().getDisplayInfo(mDisplayInfo);
@@ -255,7 +249,7 @@
         attrs.setTitle(name);
 
         final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
-                0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow);
+                0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, mPowerManagerWrapper);
         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
         // adding it to the token...
         token.addWindow(w);
@@ -294,7 +288,8 @@
         final int displayId = sNextDisplayId++;
         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
                 mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-        return new DisplayContent(display, sWm, new WallpaperController(sWm));
+        return new DisplayContent(display, sWm, new WallpaperController(sWm),
+                mock(DisplayWindowController.class));
     }
 
     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 6b6df29..7b2c040 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -38,6 +38,7 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -49,8 +50,10 @@
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
+import android.app.IActivityManager;
 import android.app.INotificationManager;
 import android.app.Notification;
+import android.app.Notification.MessagingStyle.Message;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
 import android.app.NotificationManager;
@@ -64,9 +67,11 @@
 import android.content.pm.ParceledListSlice;
 import android.graphics.Color;
 import android.media.AudioManager;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
@@ -149,6 +154,10 @@
     @Mock private ICompanionDeviceManager mCompanionMgr;
     @Mock SnoozeHelper mSnoozeHelper;
     @Mock GroupHelper mGroupHelper;
+    @Mock
+    IBinder mPermOwner;
+    @Mock
+    IActivityManager mAm;
 
     // Use a Testable subclass so we can simulate calls from the system without failing.
     private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -179,6 +188,11 @@
         protected void reportSeen(NotificationRecord r) {
             return;
         }
+
+        @Override
+        protected void reportUserInteraction(NotificationRecord r) {
+            return;
+        }
     }
 
     @Before
@@ -208,6 +222,7 @@
         when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
         when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
+        when(mAm.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
 
         // write to a test file; the system file isn't readable from tests
         mFile = new File(mContext.getCacheDir(), "test.xml");
@@ -238,7 +253,7 @@
                     mPackageManager, mPackageManagerClient, mockLightsManager,
                     mListeners, mAssistants, mConditionProviders,
                     mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
-                    mGroupHelper);
+                    mGroupHelper, mAm);
         } catch (SecurityException e) {
             if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
                 throw e;
@@ -592,6 +607,8 @@
                 mBinderService.getActiveNotifications(PKG);
         assertEquals(0, notifs.length);
         assertEquals(0, mService.getNotificationRecordCount());
+        verify(mAm, atLeastOnce()).revokeUriPermissionFromOwner(
+                any(), any(), anyInt(), anyInt());
     }
 
     @Test
@@ -610,6 +627,7 @@
         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
         verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture());
         assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface());
+        verify(mAm, atLeastOnce()).revokeUriPermissionFromOwner(any(), any(), anyInt(), anyInt());
     }
 
     @Test
@@ -624,6 +642,7 @@
                 mBinderService.getActiveNotifications(sbn.getPackageName());
         assertEquals(0, notifs.length);
         assertEquals(0, mService.getNotificationRecordCount());
+        verify(mAm, atLeastOnce()).revokeUriPermissionFromOwner(any(), any(), anyInt(), anyInt());
     }
 
     @Test
@@ -637,6 +656,7 @@
                 mBinderService.getActiveNotifications(sbn.getPackageName());
         assertEquals(0, notifs.length);
         assertEquals(0, mService.getNotificationRecordCount());
+        verify(mAm, atLeastOnce()).revokeUriPermissionFromOwner(any(), any(), anyInt(), anyInt());
     }
 
     @Test
@@ -658,6 +678,7 @@
         ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class);
         verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture());
         assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface());
+        verify(mAm, atLeastOnce()).revokeUriPermissionFromOwner(any(), any(), anyInt(), anyInt());
     }
 
     @Test
@@ -676,6 +697,7 @@
         mBinderService.cancelAllNotifications(PKG, parent.sbn.getUserId());
         waitForIdle();
         assertEquals(0, mService.getNotificationRecordCount());
+        verify(mAm, atLeastOnce()).revokeUriPermissionFromOwner(any(), any(), anyInt(), anyInt());
     }
 
     @Test
@@ -689,6 +711,7 @@
         waitForIdle();
 
         assertEquals(0, mService.getNotificationRecordCount());
+        verify(mAm, atLeastOnce()).revokeUriPermissionFromOwner(any(), any(), anyInt(), anyInt());
     }
 
     @Test
@@ -1229,7 +1252,7 @@
                 captor.getValue().getAction());
         assertEquals(PKG, captor.getValue().getPackage());
         assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
-                        NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID));
+                        NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID));
         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
     }
 
@@ -1251,7 +1274,7 @@
                 captor.getValue().getAction());
         assertEquals(PKG, captor.getValue().getPackage());
         assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra(
-                NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID));
+                NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID));
         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
     }
 
@@ -1287,7 +1310,7 @@
                 captor.getValue().getAction());
         assertEquals(PKG, captor.getValue().getPackage());
         assertEquals(existing.getId(), captor.getValue().getStringExtra(
-                NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID));
+                NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID));
         assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
     }
 
@@ -1308,7 +1331,7 @@
                 captor.getValue().getAction());
         assertEquals(PKG, captor.getValue().getPackage());
         assertEquals(existing.getId(), captor.getValue().getStringExtra(
-                NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID));
+                NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID));
         assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
     }
 
@@ -2447,4 +2470,64 @@
         mBinderService.getBackupPayload(1);
         assertEquals(1, mService.countSystemChecks - systemChecks);
     }
+
+    @Test
+    public void revokeUriPermissions_update() throws Exception {
+        NotificationChannel c = new NotificationChannel(
+                TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
+        c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
+        Message message1 = new Message("", 0, "");
+        message1.setData("", Uri.fromParts("old", "", "old stuff"));
+        Message message2 = new Message("", 1, "");
+        message2.setData("", Uri.fromParts("new", "", "new stuff"));
+
+        Notification.Builder nb = new Notification.Builder(mContext, c.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setStyle(new Notification.MessagingStyle("")
+                        .addMessage(message1)
+                        .addMessage(message2));
+        StatusBarNotification oldSbn = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+                nb.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord oldRecord =
+                new NotificationRecord(mContext, oldSbn, c);
+
+        Notification.Builder nb1 = new Notification.Builder(mContext, c.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setStyle(new Notification.MessagingStyle("").addMessage(message2));
+        StatusBarNotification newSbn = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+                nb1.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord newRecord =
+                new NotificationRecord(mContext, newSbn, c);
+
+        mService.revokeUriPermissions(newRecord, oldRecord);
+
+        verify(mAm, times(1)).revokeUriPermissionFromOwner(any(), eq(message1.getDataUri()),
+                anyInt(), anyInt());
+    }
+
+    @Test
+    public void revokeUriPermissions_cancel() throws Exception {
+        NotificationChannel c = new NotificationChannel(
+                TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
+        c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
+        Message message1 = new Message("", 0, "");
+        message1.setData("", Uri.fromParts("old", "", "old stuff"));
+
+        Notification.Builder nb = new Notification.Builder(mContext, c.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setStyle(new Notification.MessagingStyle("")
+                        .addMessage(message1));
+        StatusBarNotification oldSbn = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
+                nb.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord oldRecord =
+                new NotificationRecord(mContext, oldSbn, c);
+
+        mService.revokeUriPermissions(null, oldRecord);
+
+        verify(mAm, times(1)).revokeUriPermissionFromOwner(any(), eq(message1.getDataUri()),
+                anyInt(), anyInt());
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index cc21199..32db752 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -177,6 +177,12 @@
     long mAppIdleParoleDurationMillis;
     long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS;
     long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS;
+    /** Minimum time a strong usage event should keep the bucket elevated. */
+    long mStrongUsageTimeoutMillis;
+    /** Minimum time a notification seen event should keep the bucket elevated. */
+    long mNotificationSeenTimeoutMillis;
+    /** Minimum time a system update event should keep the buckets elevated. */
+    long mSystemUpdateUsageTimeoutMillis;
 
     volatile boolean mAppIdleEnabled;
     boolean mAppIdleTempParoled;
@@ -330,7 +336,7 @@
                     synchronized (mAppIdleLock) {
                         AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
                                 STANDBY_BUCKET_ACTIVE, elapsedRealtime,
-                                elapsedRealtime + 2 * ONE_HOUR);
+                                elapsedRealtime + mStrongUsageTimeoutMillis);
                         maybeInformListeners(packageName, userId, elapsedRealtime,
                                 appUsage.currentBucket, false);
                     }
@@ -539,6 +545,7 @@
         }
     }
 
+    @GuardedBy("mAppIdleLock")
     @StandbyBuckets int getBucketForLocked(String packageName, int userId,
             long elapsedRealtime) {
         int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId,
@@ -627,11 +634,11 @@
                 if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) {
                     mAppIdleHistory.reportUsage(appHistory, event.mPackage,
                             STANDBY_BUCKET_WORKING_SET,
-                            elapsedRealtime, elapsedRealtime + 2 * ONE_HOUR);
+                            elapsedRealtime, elapsedRealtime + mNotificationSeenTimeoutMillis);
                 } else {
                     mAppIdleHistory.reportUsage(event.mPackage, userId,
                             STANDBY_BUCKET_ACTIVE,
-                            elapsedRealtime, elapsedRealtime + 2 * ONE_HOUR);
+                            elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
                 }
 
                 final boolean userStartedInteracting =
@@ -1113,10 +1120,10 @@
                 final PackageInfo pi = packages.get(i);
                 String packageName = pi.packageName;
                 if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
-                    // Mark app as used for 4 hours. After that it can timeout to whatever the
+                    // Mark app as used for 2 hours. After that it can timeout to whatever the
                     // past usage pattern was.
                     mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 0,
-                            elapsedRealtime + 4 * ONE_HOUR);
+                            elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
                 }
             }
         }
@@ -1395,6 +1402,12 @@
         private static final String KEY_PAROLE_DURATION = "parole_duration";
         private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds";
         private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds";
+        private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration";
+        private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION =
+                "notification_seen_duration";
+        private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION =
+                "system_update_usage_duration";
+
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
@@ -1455,7 +1468,15 @@
                         ELAPSED_TIME_THRESHOLDS);
                 mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4,
                         COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours
-
+                mStrongUsageTimeoutMillis = mParser.getDurationMillis
+                        (KEY_STRONG_USAGE_HOLD_DURATION,
+                                COMPRESS_TIME ? ONE_MINUTE : 1 * ONE_HOUR);
+                mNotificationSeenTimeoutMillis = mParser.getDurationMillis
+                        (KEY_NOTIFICATION_SEEN_HOLD_DURATION,
+                                COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR);
+                mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis
+                        (KEY_SYSTEM_UPDATE_HOLD_DURATION,
+                                COMPRESS_TIME ? 2 * ONE_MINUTE : 2 * ONE_HOUR);
             }
         }
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 36a2a95..3b0fd1f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -654,7 +654,7 @@
         public boolean isAppInactive(String packageName, int userId) {
             try {
                 userId = ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(),
-                        Binder.getCallingUid(), userId, false, true, "isAppInactive", null);
+                        Binder.getCallingUid(), userId, false, false, "isAppInactive", null);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index e5f50de..6806947 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -103,6 +103,11 @@
     private static final boolean DEBUG = false;
 
     /**
+     * The name of the xml file in which screen unlocked functions are stored.
+     */
+    private static final String USB_PREFS_XML = "UsbDeviceManagerPrefs.xml";
+
+    /**
      * The SharedPreference setting per user that stores the screen unlocked functions between
      * sessions.
      */
@@ -229,14 +234,12 @@
         int userHandle = ActivityManager.getCurrentUser();
         boolean secure = mContext.getSystemService(KeyguardManager.class)
                 .isDeviceSecure(userHandle);
-        boolean unlocking = mContext.getSystemService(UserManager.class)
-                .isUserUnlockingOrUnlocked(userHandle);
         if (DEBUG) {
             Slog.v(TAG, "onKeyguardStateChanged: isShowing:" + isShowing + " secure:" + secure
-                    + " unlocking:" + unlocking + " user:" + userHandle);
+                    + " user:" + userHandle);
         }
-        // We are unlocked when the keyguard is down or non-secure, and user storage is unlocked.
-        mHandler.sendMessage(MSG_UPDATE_SCREEN_LOCK, (isShowing && secure) || !unlocking);
+        // We are unlocked when the keyguard is down or non-secure.
+        mHandler.sendMessage(MSG_UPDATE_SCREEN_LOCK, (isShowing && secure));
     }
 
     @Override
@@ -500,7 +503,6 @@
             mContentResolver = context.getContentResolver();
 
             mCurrentUser = ActivityManager.getCurrentUser();
-            mScreenUnlockedFunctions = UsbManager.FUNCTION_NONE;
             mScreenLocked = true;
 
             /*
@@ -510,6 +512,16 @@
             mAdbEnabled = UsbHandlerLegacy.containsFunction(getSystemProperty(
                     USB_PERSISTENT_CONFIG_PROPERTY, ""), UsbManager.USB_FUNCTION_ADB);
 
+            mSettings = getPinnedSharedPrefs(mContext);
+            if (mSettings == null) {
+                Slog.e(TAG, "Couldn't load shared preferences");
+            } else {
+                mScreenUnlockedFunctions = UsbManager.usbFunctionsFromString(
+                        mSettings.getString(
+                                String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, mCurrentUser),
+                                ""));
+            }
+
             // We do not show the USB notification if the primary volume supports mass storage.
             // The legacy mass storage UI will be used instead.
             final StorageManager storageManager = StorageManager.from(mContext);
@@ -664,11 +676,10 @@
         }
 
         protected SharedPreferences getPinnedSharedPrefs(Context context) {
-            final File prefsFile = new File(new File(
-                    Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL,
-                            context.getUserId(), context.getPackageName()), "shared_prefs"),
-                    UsbDeviceManager.class.getSimpleName() + ".xml");
-            return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
+            final File prefsFile = new File(
+                    Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), USB_PREFS_XML);
+            return context.createDeviceProtectedStorageContext()
+                    .getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
         }
 
         private boolean isUsbStateChanged(Intent intent) {
@@ -888,11 +899,13 @@
                     break;
                 case MSG_SET_SCREEN_UNLOCKED_FUNCTIONS:
                     mScreenUnlockedFunctions = (Long) msg.obj;
-                    SharedPreferences.Editor editor = mSettings.edit();
-                    editor.putString(String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF,
-                            mCurrentUser),
-                            UsbManager.usbFunctionsToString(mScreenUnlockedFunctions));
-                    editor.commit();
+                    if (mSettings != null) {
+                        SharedPreferences.Editor editor = mSettings.edit();
+                        editor.putString(String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF,
+                                mCurrentUser),
+                                UsbManager.usbFunctionsToString(mScreenUnlockedFunctions));
+                        editor.commit();
+                    }
                     if (!mScreenLocked && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
                         // If the screen is unlocked, also set current functions.
                         setScreenUnlockedFunctions();
@@ -903,14 +916,6 @@
                         break;
                     }
                     mScreenLocked = msg.arg1 == 1;
-                    if (mSettings == null && !mScreenLocked) {
-                        // Shared preferences aren't accessible until the user has been unlocked.
-                        mSettings = getPinnedSharedPrefs(mContext);
-                        mScreenUnlockedFunctions = UsbManager.usbFunctionsFromString(
-                                mSettings.getString(
-                                String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF, mCurrentUser),
-                                ""));
-                    }
                     if (!mBootCompleted) {
                         break;
                     }
@@ -964,12 +969,11 @@
                         }
                         mCurrentUser = msg.arg1;
                         mScreenLocked = true;
+                        mScreenUnlockedFunctions = UsbManager.FUNCTION_NONE;
                         if (mSettings != null) {
                             mScreenUnlockedFunctions = UsbManager.usbFunctionsFromString(
-                                    mSettings.getString(
-                                            String.format(Locale.ENGLISH, UNLOCKED_CONFIG_PREF,
-                                            mCurrentUser),
-                                    ""));
+                                    mSettings.getString(String.format(Locale.ENGLISH,
+                                            UNLOCKED_CONFIG_PREF, mCurrentUser), ""));
                         }
                         setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
                     }
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index 4b2d9b9..43f189b 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -314,6 +314,7 @@
      * Upgrade any single-user settings from {@link #sSingleUserSettingsFile}.
      * Should only by called by owner.
      */
+    @GuardedBy("mLock")
     private void upgradeSingleUserLocked() {
         if (sSingleUserSettingsFile.exists()) {
             mDevicePreferenceMap.clear();
@@ -347,6 +348,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void readSettingsLocked() {
         if (DEBUG) Slog.v(TAG, "readSettingsLocked()");
 
@@ -386,6 +388,7 @@
      * <p>In the uncommon case that the system crashes in between the scheduling and the write the
      * update is lost.</p>
      */
+    @GuardedBy("mLock")
     private void scheduleWriteSettingsLocked() {
         if (mIsWriteSettingsScheduled) {
             return;
@@ -869,6 +872,7 @@
         return null;
     }
 
+    @GuardedBy("mLock")
     private boolean clearCompatibleMatchesLocked(@NonNull UserPackage userPackage,
             @NonNull DeviceFilter filter) {
         ArrayList<DeviceFilter> keysToRemove = new ArrayList<>();
@@ -892,6 +896,7 @@
         return !keysToRemove.isEmpty();
     }
 
+    @GuardedBy("mLock")
     private boolean clearCompatibleMatchesLocked(@NonNull UserPackage userPackage,
             @NonNull AccessoryFilter filter) {
         ArrayList<AccessoryFilter> keysToRemove = new ArrayList<>();
@@ -915,6 +920,7 @@
         return !keysToRemove.isEmpty();
     }
 
+    @GuardedBy("mLock")
     private boolean handlePackageAddedLocked(UserPackage userPackage, ActivityInfo aInfo,
             String metaDataName) {
         XmlResourceParser parser = null;
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 1edc469..c1a7591 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -236,6 +236,7 @@
      *
      * @return Iff the caller is in the current user's profile group
      */
+    @GuardedBy("mLock")
     private boolean isCallerInCurrentUserProfileGroupLocked() {
         int userIdInt = UserHandle.getCallingUserId();
 
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 6799417..8c18518 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -352,8 +352,11 @@
          */
         public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
 
+        /** Call supports the deflect feature. */
+        public static final int CAPABILITY_SUPPORT_DEFLECT = 0x01000000;
+
         //******************************************************************************************
-        // Next CAPABILITY value: 0x01000000
+        // Next CAPABILITY value: 0x02000000
         //******************************************************************************************
 
         /**
@@ -528,6 +531,9 @@
             if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
                 builder.append(" CAPABILITY_CAN_PULL_CALL");
             }
+            if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) {
+                builder.append(" CAPABILITY_SUPPORT_DEFLECT");
+            }
             builder.append("]");
             return builder.toString();
         }
@@ -1235,6 +1241,15 @@
     }
 
     /**
+     * Instructs this {@link #STATE_RINGING} {@code Call} to deflect.
+     *
+     * @param address The address to which the call will be deflected.
+     */
+    public void deflect(Uri address) {
+        mInCallAdapter.deflectCall(mTelecomCallId, address);
+    }
+
+    /**
      * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
      *
      * @param rejectWithMessage Whether to reject with a text message.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 63f970a..24184e0 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -328,8 +328,11 @@
      */
     public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000;
 
+    /** Call supports the deflect feature. */
+    public static final int CAPABILITY_SUPPORT_DEFLECT = 0x02000000;
+
     //**********************************************************************************************
-    // Next CAPABILITY value: 0x02000000
+    // Next CAPABILITY value: 0x04000000
     //**********************************************************************************************
 
     /**
@@ -726,6 +729,9 @@
         if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
             builder.append(isLong ? " CAPABILITY_CAN_PULL_CALL" : " pull");
         }
+        if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) {
+            builder.append(isLong ? " CAPABILITY_SUPPORT_DEFLECT" : " sup_def");
+        }
 
         builder.append("]");
         return builder.toString();
@@ -787,6 +793,10 @@
             builder.append(isLong ? " PROPERTY_HAS_CDMA_VOICE_PRIVACY" : " priv");
         }
 
+        if (can(properties, PROPERTY_IS_RTT)) {
+            builder.append(isLong ? " PROPERTY_IS_RTT" : " rtt");
+        }
+
         builder.append("]");
         return builder.toString();
     }
@@ -2646,6 +2656,7 @@
      * side of the coll.
      */
     public final void sendRttSessionRemotelyTerminated() {
+        unsetRttProperty();
         mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this));
     }
 
@@ -2747,6 +2758,12 @@
 
     /**
      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
+     * a request to deflect.
+     */
+    public void onDeflect(Uri address) {}
+
+    /**
+     * Notifies this Connection, which is in {@link #STATE_RINGING}, of
      * a request to reject.
      */
     public void onReject() {}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index c1040ad..211699e 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -124,6 +124,7 @@
     private static final String SESSION_ABORT = "CS.ab";
     private static final String SESSION_ANSWER = "CS.an";
     private static final String SESSION_ANSWER_VIDEO = "CS.anV";
+    private static final String SESSION_DEFLECT = "CS.def";
     private static final String SESSION_REJECT = "CS.r";
     private static final String SESSION_REJECT_MESSAGE = "CS.rWM";
     private static final String SESSION_SILENCE = "CS.s";
@@ -181,6 +182,7 @@
     private static final int MSG_CONNECTION_SERVICE_FOCUS_GAINED = 31;
     private static final int MSG_HANDOVER_FAILED = 32;
     private static final int MSG_HANDOVER_COMPLETE = 33;
+    private static final int MSG_DEFLECT = 34;
 
     private static Connection sNullConnection;
 
@@ -353,6 +355,20 @@
         }
 
         @Override
+        public void deflect(String callId, Uri address, Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_DEFLECT);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.arg2 = address;
+                args.arg3 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_DEFLECT, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void reject(String callId, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_REJECT);
             try {
@@ -847,6 +863,17 @@
                     }
                     break;
                 }
+                case MSG_DEFLECT: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession((Session) args.arg3, SESSION_HANDLER + SESSION_DEFLECT);
+                    try {
+                        deflect((String) args.arg1, (Uri) args.arg2);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_REJECT: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
@@ -1605,6 +1632,11 @@
         findConnectionForAction(callId, "answer").onAnswer();
     }
 
+    private void deflect(String callId, Uri address) {
+        Log.d(this, "deflect %s", callId);
+        findConnectionForAction(callId, "deflect").onDeflect(address);
+    }
+
     private void reject(String callId) {
         Log.d(this, "reject %s", callId);
         findConnectionForAction(callId, "reject").onReject();
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index dcf5c27..1de67a5 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -33,47 +33,48 @@
 public final class DisconnectCause implements Parcelable {
 
     /** Disconnected because of an unknown or unspecified reason. */
-    public static final int UNKNOWN = 0;
+    public static final int UNKNOWN = TelecomProtoEnums.UNKNOWN; // = 0
     /** Disconnected because there was an error, such as a problem with the network. */
-    public static final int ERROR = 1;
+    public static final int ERROR = TelecomProtoEnums.ERROR; // = 1
     /** Disconnected because of a local user-initiated action, such as hanging up. */
-    public static final int LOCAL = 2;
+    public static final int LOCAL = TelecomProtoEnums.LOCAL; // = 2
     /**
      * Disconnected because of a remote user-initiated action, such as the other party hanging up
      * up.
      */
-    public static final int REMOTE = 3;
+    public static final int REMOTE = TelecomProtoEnums.REMOTE; // = 3
     /** Disconnected because it has been canceled. */
-    public static final int CANCELED = 4;
+    public static final int CANCELED = TelecomProtoEnums.CANCELED; // = 4
     /** Disconnected because there was no response to an incoming call. */
-    public static final int MISSED = 5;
+    public static final int MISSED = TelecomProtoEnums.MISSED; // = 5
     /** Disconnected because the user rejected an incoming call. */
-    public static final int REJECTED = 6;
+    public static final int REJECTED = TelecomProtoEnums.REJECTED; // = 6
     /** Disconnected because the other party was busy. */
-    public static final int BUSY = 7;
+    public static final int BUSY = TelecomProtoEnums.BUSY; // = 7
     /**
      * Disconnected because of a restriction on placing the call, such as dialing in airplane
      * mode.
      */
-    public static final int RESTRICTED = 8;
+    public static final int RESTRICTED = TelecomProtoEnums.RESTRICTED; // = 8
     /** Disconnected for reason not described by other disconnect codes. */
-    public static final int OTHER = 9;
+    public static final int OTHER = TelecomProtoEnums.OTHER; // = 9
     /**
      * Disconnected because the connection manager did not support the call. The call will be tried
      * again without a connection manager. See {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}.
      */
-    public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10;
+    public static final int CONNECTION_MANAGER_NOT_SUPPORTED =
+            TelecomProtoEnums.CONNECTION_MANAGER_NOT_SUPPORTED; // = 10
 
     /**
      * Disconnected because the user did not locally answer the incoming call, but it was answered
      * on another device where the call was ringing.
      */
-    public static final int ANSWERED_ELSEWHERE = 11;
+    public static final int ANSWERED_ELSEWHERE = TelecomProtoEnums.ANSWERED_ELSEWHERE; // = 11
 
     /**
      * Disconnected because the call was pulled from the current device to another device.
      */
-    public static final int CALL_PULLED = 12;
+    public static final int CALL_PULLED = TelecomProtoEnums.CALL_PULLED; // = 12
 
     /**
      * Reason code (returned via {@link #getReason()}) which indicates that a call could not be
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 658685f..8678e33 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.net.Uri;
 import android.bluetooth.BluetoothDevice;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -61,6 +62,19 @@
     }
 
     /**
+     * Instructs Telecom to deflect the specified call.
+     *
+     * @param callId The identifier of the call to deflect.
+     * @param address The address to deflect.
+     */
+    public void deflectCall(String callId, Uri address) {
+        try {
+            mAdapter.deflectCall(callId, address);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Instructs Telecom to reject the specified call.
      *
      * @param callId The identifier of the call to reject.
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index fcf04c9..af65c65 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -60,6 +60,26 @@
  * </service>
  * }
  * </pre>
+ * <p>
+ * In addition to implementing the {@link InCallService} API, you must also declare an activity in
+ * your manifest which handles the {@link Intent#ACTION_DIAL} intent.  The example below illustrates
+ * how this is done:
+ * <pre>
+ * {@code
+ * <activity android:name="your.package.YourDialerActivity"
+ *           android:label="@string/yourDialerActivityLabel">
+ *      <intent-filter>
+ *           <action android:name="android.intent.action.DIAL" />
+ *           <category android:name="android.intent.category.DEFAULT" />
+ *      </intent-filter>
+ * </activity>
+ * }
+ * </pre>
+ * <p>
+ * When a user installs your application and runs it for the first time, you should prompt the user
+ * to see if they would like your application to be the new default phone app.  See the
+ * {@link TelecomManager#ACTION_CHANGE_DEFAULT_DIALER} intent documentation for more information on
+ * how to do this.
  */
 public abstract class InCallService extends Service {
 
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 1fe5db5..a180da6 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1320,7 +1320,7 @@
     public boolean endCall() {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().endCall();
+                return getTelecomService().endCall(mContext.getPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#endCall", e);
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 3a84f00..e35093c 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.telecom;
 
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.telecom.CallAudioState;
@@ -58,6 +59,8 @@
 
     void answer(String callId, in Session.Info sessionInfo);
 
+    void deflect(String callId, in Uri address, in Session.Info sessionInfo);
+
     void reject(String callId, in Session.Info sessionInfo);
 
     void rejectWithMessage(String callId, String message, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 87ccd3e..57df5c1 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.telecom;
 
+import android.net.Uri;
 import android.os.Bundle;
 import android.telecom.PhoneAccountHandle;
 
@@ -29,6 +30,8 @@
 oneway interface IInCallAdapter {
     void answerCall(String callId, int videoState);
 
+    void deflectCall(String callId, in Uri address);
+
     void rejectCall(String callId, boolean rejectWithMessage, String textMessage);
 
     void disconnectCall(String callId);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 3460754..b4e7d56 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -187,7 +187,7 @@
     /**
      * @see TelecomServiceImpl#endCall
      */
-    boolean endCall();
+    boolean endCall(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#acceptRingingCall
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 8c45724..63263bd 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -33,6 +33,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SmsMessage;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Patterns;
 
@@ -3345,73 +3346,118 @@
     }
 
     /**
-     * Contains carrier identification information.
-     * @hide
+     * Contains carrier identification information for the current subscriptions.
+     * @see SubscriptionManager#getActiveSubscriptionIdList()
      */
     public static final class CarrierIdentification implements BaseColumns {
         /**
-         * Numeric operator ID (as String). {@code MCC + MNC}
-         * <P>Type: TEXT </P>
+         * Not instantiable.
+         * @hide
          */
-        public static final String MCCMNC = "mccmnc";
+        private CarrierIdentification() {}
 
         /**
-         * Group id level 1 (as String).
-         * <P>Type: TEXT </P>
+         * The {@code content://} style URI for this provider.
          */
-        public static final String GID1 = "gid1";
+        public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification");
 
         /**
-         * Group id level 2 (as String).
-         * <P>Type: TEXT </P>
+         * The authority string for the CarrierIdentification Provider
+         * @hide
          */
-        public static final String GID2 = "gid2";
+        public static final String AUTHORITY = "carrier_identification";
+
 
         /**
-         * Public Land Mobile Network name.
-         * <P>Type: TEXT </P>
+         * Generates a content {@link Uri} used to receive updates on carrier identity change
+         * on the given subscriptionId
+         * <p>
+         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+         * carrier identity {@link TelephonyManager#getAndroidCarrierIdForSubscription()}
+         * while your app is running. You can also use a {@link JobService} to ensure your app
+         * is notified of changes to the {@link Uri} even when it is not running.
+         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+         * updates to the {@link Uri}.
+         *
+         * @param subscriptionId the subscriptionId to receive updates on
+         * @return the Uri used to observe carrier identity changes
          */
-        public static final String PLMN = "plmn";
+        public static Uri getUriForSubscriptionId(int subscriptionId) {
+            return CONTENT_URI.buildUpon().appendEncodedPath(
+                    String.valueOf(subscriptionId)).build();
+        }
 
         /**
-         * Prefix xpattern of IMSI (International Mobile Subscriber Identity).
-         * <P>Type: TEXT </P>
-         */
-        public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern";
-
-        /**
-         * Service Provider Name.
-         * <P>Type: TEXT </P>
-         */
-        public static final String SPN = "spn";
-
-        /**
-         * Prefer APN name.
-         * <P>Type: TEXT </P>
-         */
-        public static final String APN = "apn";
-
-        /**
-         * Prefix of Integrated Circuit Card Identifier.
-         * <P>Type: TEXT </P>
-         */
-        public static final String ICCID_PREFIX = "iccid_prefix";
-
-        /**
-         * User facing carrier name.
+         * A user facing carrier name.
+         * @see TelephonyManager#getAndroidCarrierNameForSubscription()
          * <P>Type: TEXT </P>
          */
         public static final String NAME = "carrier_name";
 
         /**
          * A unique carrier id
+         * @see TelephonyManager#getAndroidCarrierIdForSubscription()
          * <P>Type: INTEGER </P>
          */
         public static final String CID = "carrier_id";
 
         /**
-         * The {@code content://} URI for this table.
+         * Contains mappings between matching rules with carrier id for all carriers.
+         * @hide
          */
-        public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification");
+        public static final class All implements BaseColumns {
+            /**
+             * Numeric operator ID (as String). {@code MCC + MNC}
+             * <P>Type: TEXT </P>
+             */
+            public static final String MCCMNC = "mccmnc";
+
+            /**
+             * Group id level 1 (as String).
+             * <P>Type: TEXT </P>
+             */
+            public static final String GID1 = "gid1";
+
+            /**
+             * Group id level 2 (as String).
+             * <P>Type: TEXT </P>
+             */
+            public static final String GID2 = "gid2";
+
+            /**
+             * Public Land Mobile Network name.
+             * <P>Type: TEXT </P>
+             */
+            public static final String PLMN = "plmn";
+
+            /**
+             * Prefix xpattern of IMSI (International Mobile Subscriber Identity).
+             * <P>Type: TEXT </P>
+             */
+            public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern";
+
+            /**
+             * Service Provider Name.
+             * <P>Type: TEXT </P>
+             */
+            public static final String SPN = "spn";
+
+            /**
+             * Prefer APN name.
+             * <P>Type: TEXT </P>
+             */
+            public static final String APN = "apn";
+
+            /**
+             * Prefix of Integrated Circuit Card Identifier.
+             * <P>Type: TEXT </P>
+             */
+            public static final String ICCID_PREFIX = "iccid_prefix";
+
+            /**
+             * The {@code content://} URI for this table.
+             */
+            public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification/all");
+        }
     }
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7eb691b..c8c898a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1376,6 +1376,12 @@
      */
     public static final String KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL = "allow_hold_in_ims_call";
 
+    /**
+     * Flag indicating whether the carrier supports call deflection for an incoming IMS call.
+     * @hide
+     */
+    public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL =
+            "carrier_allow_deflect_ims_call_bool";
 
     /**
      * Flag indicating whether the carrier always wants to play an "on-hold" tone when a call has
@@ -1844,6 +1850,7 @@
     static {
         sDefaults = new PersistableBundle();
         sDefaults.putBoolean(KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL, true);
+        sDefaults.putBoolean(KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL, false);
         sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true);
         sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false);
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
deleted file mode 100644
index b362df9..0000000
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ /dev/null
@@ -1,160 +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.telephony;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.location.LocationManager;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Process;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.util.SparseBooleanArray;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Helper for performing location access checks.
- * @hide
- */
-public final class LocationAccessPolicy {
-    /**
-     * API to determine if the caller has permissions to get cell location.
-     *
-     * @param pkgName Package name of the application requesting access
-     * @param uid The uid of the package
-     * @param pid The pid of the package
-     * @return boolean true or false if permissions is granted
-     */
-    public static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName,
-            int uid, int pid) throws SecurityException {
-        Trace.beginSection("TelephonyLocationCheck");
-        try {
-            // Always allow the phone process to access location. This avoid breaking legacy code
-            // that rely on public-facing APIs to access cell location, and it doesn't create a
-            // info leak risk because the cell location is stored in the phone process anyway.
-            if (uid == Process.PHONE_UID) {
-                return true;
-            }
-
-            // We always require the location permission and also require the
-            // location mode to be on for non-legacy apps. Legacy apps are
-            // required to be in the foreground to at least mitigate the case
-            // where a legacy app the user is not using tracks their location.
-            // Granting ACCESS_FINE_LOCATION to an app automatically grants it
-            // ACCESS_COARSE_LOCATION.
-
-            if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, pid, uid) ==
-                    PackageManager.PERMISSION_DENIED) {
-                return false;
-            }
-            final int opCode = AppOpsManager.permissionToOpCode(
-                    Manifest.permission.ACCESS_COARSE_LOCATION);
-            if (opCode != AppOpsManager.OP_NONE && context.getSystemService(AppOpsManager.class)
-                    .noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
-                return false;
-            }
-            if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))
-                    && !isLegacyForeground(context, pkgName, uid)) {
-                return false;
-            }
-            // If the user or profile is current, permission is granted.
-            // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
-            return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context);
-        } finally {
-            Trace.endSection();
-        }
-    }
-
-    private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
-        int locationMode = Settings.Secure.getIntForUser(context.getContentResolver(),
-                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, userId);
-        return locationMode != Settings.Secure.LOCATION_MODE_OFF
-                && locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
-    }
-
-    private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName,
-            int uid) {
-        long token = Binder.clearCallingIdentity();
-        try {
-            return isLegacyVersion(context, pkgName) && isForegroundApp(context, uid);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) {
-        try {
-            if (context.getPackageManager().getApplicationInfo(pkgName, 0)
-                    .targetSdkVersion <= Build.VERSION_CODES.O) {
-                return true;
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            // In case of exception, assume known app (more strict checking)
-            // Note: This case will never happen since checkPackage is
-            // called to verify validity before checking app's version.
-        }
-        return false;
-    }
-
-    private static boolean isForegroundApp(@NonNull Context context, int uid) {
-        final ActivityManager am = context.getSystemService(ActivityManager.class);
-        return am.getUidImportance(uid) <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
-    }
-
-    private static boolean checkInteractAcrossUsersFull(@NonNull Context context) {
-        return context.checkCallingOrSelfPermission(
-                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-
-    private static boolean isCurrentProfile(@NonNull Context context, int uid) {
-        long token = Binder.clearCallingIdentity();
-        try {
-            final int currentUser = ActivityManager.getCurrentUser();
-            final int callingUserId = UserHandle.getUserId(uid);
-            if (callingUserId == currentUser) {
-                return true;
-            } else {
-                List<UserInfo> userProfiles = context.getSystemService(
-                        UserManager.class).getProfiles(currentUser);
-                for (UserInfo user : userProfiles) {
-                    if (user.id == callingUserId) {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 34f2dac..debf43d 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -612,9 +612,9 @@
      *                 onSubscriptionsChanged overridden.
      */
     public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
-        String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+        String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         if (DBG) {
-            logd("register OnSubscriptionsChangedListener pkgName=" + pkgName
+            logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
                     + " listener=" + listener);
         }
         try {
@@ -623,7 +623,7 @@
             ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                     "telephony.registry"));
             if (tr != null) {
-                tr.addOnSubscriptionsChangedListener(pkgName, listener.callback);
+                tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
             }
         } catch (RemoteException ex) {
             // Should not happen
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 5c290da..03d8b5c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -904,6 +904,61 @@
     public static final String EVENT_CALL_FORWARDED =
             "android.telephony.event.EVENT_CALL_FORWARDED";
 
+    /**
+     * {@link android.telecom.Connection} event used to indicate that a supplementary service
+     * notification has been received.
+     * <p>
+     * Sent via {@link android.telecom.Connection#sendConnectionEvent(String, Bundle)}.
+     * The {@link Bundle} parameter is expected to include the following extras:
+     * <ul>
+     *     <li>{@link #EXTRA_NOTIFICATION_TYPE} - the notification type.</li>
+     *     <li>{@link #EXTRA_NOTIFICATION_CODE} - the notification code.</li>
+     *     <li>{@link #EXTRA_NOTIFICATION_MESSAGE} - human-readable message associated with the
+     *     supplementary service notification.</li>
+     * </ul>
+     * @hide
+     */
+    public static final String EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION =
+            "android.telephony.event.EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION";
+
+    /**
+     * Integer extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} which indicates
+     * the type of supplementary service notification which occurred.
+     * Will be either
+     * {@link com.android.internal.telephony.gsm.SuppServiceNotification#NOTIFICATION_TYPE_CODE_1}
+     * or
+     * {@link com.android.internal.telephony.gsm.SuppServiceNotification#NOTIFICATION_TYPE_CODE_2}
+     * <p>
+     * Set in the extras for the {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} connection event.
+     * @hide
+     */
+    public static final String EXTRA_NOTIFICATION_TYPE =
+            "android.telephony.extra.NOTIFICATION_TYPE";
+
+    /**
+     * Integer extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} which indicates
+     * the supplementary service notification which occurred.
+     * <p>
+     * Depending on the {@link #EXTRA_NOTIFICATION_TYPE}, the code will be one of the {@code CODE_*}
+     * codes defined in {@link com.android.internal.telephony.gsm.SuppServiceNotification}.
+     * <p>
+     * Set in the extras for the {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} connection event.
+     * @hide
+     */
+    public static final String EXTRA_NOTIFICATION_CODE =
+            "android.telephony.extra.NOTIFICATION_CODE";
+
+    /**
+     * {@link CharSequence} extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION}
+     * which contains a human-readable message which can be displayed to the user for the
+     * supplementary service notification.
+     * <p>
+     * Set in the extras for the {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} connection event.
+     * @hide
+     */
+    public static final String EXTRA_NOTIFICATION_MESSAGE =
+            "android.telephony.extra.NOTIFICATION_MESSAGE";
+
     /* Visual voicemail protocols */
 
     /**
@@ -6587,11 +6642,48 @@
      * @hide
      */
     public void setBasebandVersionForPhone(int phoneId, String version) {
+        setTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_BASEBAND_VERSION, version);
+    }
+
+    /**
+     * Get baseband version for the default phone.
+     *
+     * @return baseband version.
+     * @hide
+     */
+    public String getBasebandVersion() {
+        int phoneId = getPhoneId();
+        return getBasebandVersionForPhone(phoneId);
+    }
+
+    /**
+     * Get baseband version for the default phone using the legacy approach.
+     * This change was added in P, to ensure backward compatiblity.
+     *
+     * @return baseband version.
+     * @hide
+     */
+    private String getBasebandVersionLegacy(int phoneId) {
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
             String prop = TelephonyProperties.PROPERTY_BASEBAND_VERSION +
                     ((phoneId == 0) ? "" : Integer.toString(phoneId));
-            SystemProperties.set(prop, version);
+            return SystemProperties.get(prop);
         }
+        return null;
+    }
+
+    /**
+     * Get baseband version by phone id.
+     *
+     * @return baseband version.
+     * @hide
+     */
+    public String getBasebandVersionForPhone(int phoneId) {
+        String version = getBasebandVersionLegacy(phoneId);
+        if (version != null && !version.isEmpty()) {
+            setBasebandVersionForPhone(phoneId, version);
+        }
+        return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_BASEBAND_VERSION, "");
     }
 
     /**
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 0b3cbad..0c17147 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -55,10 +55,11 @@
     /** Card state restricted. */
     public static final int CARD_STATE_INFO_RESTRICTED = 4;
 
-    public final boolean isActive;
-    public final boolean isEuicc;
-    public final String cardId;
-    public final @CardStateInfo int cardStateInfo;
+    private final boolean mIsActive;
+    private final boolean mIsEuicc;
+    private final String mCardId;
+    private final @CardStateInfo int mCardStateInfo;
+    private final int mLogicalSlotIdx;
 
     public static final Creator<UiccSlotInfo> CREATOR = new Creator<UiccSlotInfo>() {
         @Override
@@ -73,18 +74,20 @@
     };
 
     private UiccSlotInfo(Parcel in) {
-        isActive = in.readByte() != 0;
-        isEuicc = in.readByte() != 0;
-        cardId = in.readString();
-        cardStateInfo = in.readInt();
+        mIsActive = in.readByte() != 0;
+        mIsEuicc = in.readByte() != 0;
+        mCardId = in.readString();
+        mCardStateInfo = in.readInt();
+        mLogicalSlotIdx = in.readInt();
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeByte((byte) (isActive ? 1 : 0));
-        dest.writeByte((byte) (isEuicc ? 1 : 0));
-        dest.writeString(cardId);
-        dest.writeInt(cardStateInfo);
+        dest.writeByte((byte) (mIsActive ? 1 : 0));
+        dest.writeByte((byte) (mIsEuicc ? 1 : 0));
+        dest.writeString(mCardId);
+        dest.writeInt(mCardStateInfo);
+        dest.writeInt(mLogicalSlotIdx);
     }
 
     @Override
@@ -93,28 +96,33 @@
     }
 
     public UiccSlotInfo(boolean isActive, boolean isEuicc, String cardId,
-            @CardStateInfo int cardStateInfo) {
-        this.isActive = isActive;
-        this.isEuicc = isEuicc;
-        this.cardId = cardId;
-        this.cardStateInfo = cardStateInfo;
+            @CardStateInfo int cardStateInfo, int logicalSlotIdx) {
+        this.mIsActive = isActive;
+        this.mIsEuicc = isEuicc;
+        this.mCardId = cardId;
+        this.mCardStateInfo = cardStateInfo;
+        this.mLogicalSlotIdx = logicalSlotIdx;
     }
 
     public boolean getIsActive() {
-        return isActive;
+        return mIsActive;
     }
 
     public boolean getIsEuicc() {
-        return isEuicc;
+        return mIsEuicc;
     }
 
     public String getCardId() {
-        return cardId;
+        return mCardId;
     }
 
     @CardStateInfo
     public int getCardStateInfo() {
-        return cardStateInfo;
+        return mCardStateInfo;
+    }
+
+    public int getLogicalSlotIdx() {
+        return mLogicalSlotIdx;
     }
 
     @Override
@@ -127,32 +135,36 @@
         }
 
         UiccSlotInfo that = (UiccSlotInfo) obj;
-        return (isActive == that.isActive)
-                && (isEuicc == that.isEuicc)
-                && (cardId == that.cardId)
-                && (cardStateInfo == that.cardStateInfo);
+        return (mIsActive == that.mIsActive)
+                && (mIsEuicc == that.mIsEuicc)
+                && (mCardId == that.mCardId)
+                && (mCardStateInfo == that.mCardStateInfo)
+                && (mLogicalSlotIdx == that.mLogicalSlotIdx);
     }
 
     @Override
     public int hashCode() {
         int result = 1;
-        result = 31 * result + (isActive ? 1 : 0);
-        result = 31 * result + (isEuicc ? 1 : 0);
-        result = 31 * result + Objects.hashCode(cardId);
-        result = 31 * result + cardStateInfo;
+        result = 31 * result + (mIsActive ? 1 : 0);
+        result = 31 * result + (mIsEuicc ? 1 : 0);
+        result = 31 * result + Objects.hashCode(mCardId);
+        result = 31 * result + mCardStateInfo;
+        result = 31 * result + mLogicalSlotIdx;
         return result;
     }
 
     @Override
     public String toString() {
-        return "UiccSlotInfo (isActive="
-                + isActive
-                + ", isEuicc="
-                + isEuicc
-                + ", cardId="
-                + cardId
+        return "UiccSlotInfo (mIsActive="
+                + mIsActive
+                + ", mIsEuicc="
+                + mIsEuicc
+                + ", mCardId="
+                + mCardId
                 + ", cardState="
-                + cardStateInfo
+                + mCardStateInfo
+                + ", phoneId="
+                + mLogicalSlotIdx
                 + ")";
     }
 }
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index c3d103f..a20d4f5 100644
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -754,6 +754,22 @@
     }
 
     /**
+     * Deflects an incoming call.
+     *
+     * @param number number to be deflected to
+     */
+    public void deflect(String number) {
+        if (mClosed) {
+            return;
+        }
+
+        try {
+            miSession.deflect(number);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Rejects an incoming call or session update.
      *
      * @param reason reason code to reject an incoming call
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
index 00cb1e2..e5ed825 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
@@ -182,6 +182,15 @@
     }
 
     /**
+     * Deflects an incoming call.
+     *
+     * @param deflectNumber number to deflect the call
+     */
+    @Override
+    public void deflect(String deflectNumber) {
+    }
+
+    /**
      * Rejects an incoming call or session update.
      *
      * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}.
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index c6ca6fd..7b9fe2b 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -174,6 +174,11 @@
         }
 
         @Override
+        public void deflect(String deflectNumber) {
+            ImsCallSessionImplBase.this.deflect(deflectNumber);
+        }
+
+        @Override
         public void reject(int reason) {
             ImsCallSessionImplBase.this.reject(reason);
         }
@@ -395,6 +400,14 @@
     }
 
     /**
+     * Deflects an incoming call.
+     *
+     * @param deflectNumber number to deflect the call
+     */
+    public void deflect(String deflectNumber) {
+    }
+
+    /**
      * Rejects an incoming call or session update.
      *
      * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}.
diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
index 203e6cf..15234e5 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
@@ -136,6 +136,13 @@
     void accept(int callType, in ImsStreamMediaProfile profile);
 
     /**
+     * Deflects an incoming call.
+     *
+     * @param deflectNumber number to deflect the call
+     */
+    void deflect(String deflectNumber);
+
+    /**
      * Rejects an incoming call or session update.
      *
      * @param reason reason code to reject an incoming call
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 62fed61..b65cda9 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -24,6 +24,9 @@
 
     srcs: ["src/**/*.java"],
 
+    // Needs to be consistent with the repackaged version of this make target.
+    java_version: "1.8",
+
     no_framework_libs: true,
     hostdex: true,
     libs: [
@@ -55,21 +58,22 @@
     name: "repackaged.android.test.base",
 
     static_libs: ["android.test.base"],
-
     no_framework_libs: true,
     libs: [
         "framework",
     ],
 
     jarjar_rules: "jarjar-rules.txt",
+    // Pin java_version until jarjar is certified to support later versions. http://b/72703434
+    java_version: "1.8",
 }
 
 // Build the android.test.base-minus-junit library
 // ===============================================
 // This contains the android.test classes from android.test.base plus
 // the com.android.internal.util.Predicate[s] classes. This is only
-// intended for inclusion in the android.test.legacy static library and
-// must not be used elsewhere.
+// intended for inclusion in the android.test.legacy and
+// legacy-android-test static libraries and must not be used elsewhere.
 java_library_static {
     name: "android.test.base-minus-junit",
 
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index b1ae40e..54e07a16 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -19,6 +19,8 @@
 java_library {
     name: "android.test.mock",
 
+    // Needs to be consistent with the repackaged version of this make target.
+    java_version: "1.8",
     srcs: ["src/**/*.java"],
 
     no_framework_libs: true,
@@ -35,4 +37,6 @@
     static_libs: ["android.test.mock"],
 
     jarjar_rules: "jarjar-rules.txt",
+    // Pin java_version until jarjar is certified to support later versions. http://b/72703434
+    java_version: "1.8",
 }
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index dfaeed5..66b9527 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -19,6 +19,8 @@
 java_library {
     name: "android.test.runner",
 
+    // Needs to be consistent with the repackaged version of this make target.
+    java_version: "1.8",
     srcs: ["src/**/*.java"],
 
     no_framework_libs: true,
@@ -31,7 +33,8 @@
 
 // Build the android.test.runner-minus-junit library
 // =================================================
-// This is provided solely for use by the legacy-android-test module.
+// This is only intended for inclusion in the android.test.legacy and
+// legacy-android-test static libraries and must not be used elsewhere.
 java_library {
     name: "android.test.runner-minus-junit",
 
@@ -54,4 +57,6 @@
     static_libs: ["android.test.runner"],
 
     jarjar_rules: "jarjar-rules.txt",
+    // Pin java_version until jarjar is certified to support later versions. http://b/72703434
+    java_version: "1.8",
 }
diff --git a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
index 021e386..23a151c 100644
--- a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
+++ b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
@@ -15,6 +15,9 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworks.perftests.amteststestapp">
+    <uses-sdk
+            android:minSdkVersion="21"
+            android:targetSdkVersion="27" />
     <application android:name=".TestApplication">
         <activity android:name=".TestActivity" android:exported="true"/>
         <provider
@@ -29,5 +32,8 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </receiver>
+        <service
+                android:name=".TestService"
+                android:exported="true" />
     </application>
 </manifest>
diff --git a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java
index 7ea9ba3..4e7bb4c 100644
--- a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java
+++ b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java
@@ -17,16 +17,18 @@
 package com.android.frameworks.perftests.amteststestapp;
 
 import android.app.Activity;
-import android.os.Bundle;
+import android.os.Looper;
 
 import com.android.frameworks.perftests.am.util.Constants;
 import com.android.frameworks.perftests.am.util.Utils;
 
 public class TestActivity extends Activity {
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        Utils.sendTime(getIntent(), Constants.TYPE_ACTIVITY_CREATED);
+    protected void onResume() {
+        super.onResume();
+        Looper.myQueue().addIdleHandler(() -> {
+            Utils.sendTime(getIntent(), Constants.TYPE_TARGET_PACKAGE_START);
+            return false;
+        });
     }
 }
diff --git a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestService.java b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestService.java
new file mode 100644
index 0000000..b6534fc
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestService.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.amteststestapp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+import com.android.frameworks.perftests.am.util.Constants;
+import com.android.frameworks.perftests.am.util.Utils;
+
+public class TestService extends Service {
+    @Override
+    public IBinder onBind(Intent intent) {
+        return new Binder();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Utils.sendTime(intent, Constants.TYPE_SERVICE_START);
+        return super.onStartCommand(intent, flags, startId);
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml b/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml
index 4e194c6..a1ab33a 100644
--- a/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml
+++ b/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml
@@ -15,6 +15,9 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworks.perftests.amtests">
+    <uses-sdk
+            android:minSdkVersion="21"
+            android:targetSdkVersion="27" />
     <uses-permission android:name="android.permission.DUMP" />
     <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
 
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
index 661abe9..cf175e0 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
@@ -16,8 +16,11 @@
 
 package com.android.frameworks.perftests.am.tests;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
 import android.perftests.utils.ManualBenchmarkState;
 import android.perftests.utils.PerfManualStatusReporter;
 import android.support.test.InstrumentationRegistry;
@@ -26,13 +29,17 @@
 import com.android.frameworks.perftests.am.util.TimeReceiver;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.function.LongSupplier;
 
 public class BasePerfTest {
     private static final String TAG = BasePerfTest.class.getSimpleName();
+    private static final long AWAIT_SERVICE_CONNECT_MS = 2000;
 
     private TimeReceiver mTimeReceiver;
 
@@ -52,14 +59,70 @@
         TargetPackageUtils.killTargetPackage(mContext);
     }
 
-    protected Intent createIntent(String action) {
+    protected void addReceivedTimeNs(String type) {
+        mTimeReceiver.addTimeForTypeToQueue(type, System.nanoTime());
+    }
+
+    protected Intent createServiceIntent() {
+        final Intent intent = new Intent();
+        intent.setClassName(TargetPackageUtils.PACKAGE_NAME,
+                TargetPackageUtils.SERVICE_NAME);
+        putTimeReceiverBinderExtra(intent);
+        return intent;
+    }
+
+    protected ServiceConnection bindAndWaitForConnectedService() {
+        return bindAndWaitForConnectedService(0);
+    }
+
+    protected ServiceConnection bindAndWaitForConnectedService(int flags) {
+        CountDownLatch countDownLatch = new CountDownLatch(1);
+        final ServiceConnection serviceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                countDownLatch.countDown();
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+            }
+        };
+
+        final Intent intent = createServiceIntent();
+        final boolean success = mContext.bindService(intent, serviceConnection,
+                Context.BIND_AUTO_CREATE | flags);
+        Assert.assertTrue("Could not bind to service", success);
+
+        try {
+            boolean connectedSuccess = countDownLatch.await(AWAIT_SERVICE_CONNECT_MS,
+                    TimeUnit.MILLISECONDS);
+            Assert.assertTrue("Timeout when waiting for ServiceConnection.onServiceConnected()",
+                    connectedSuccess);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+
+        return serviceConnection;
+    }
+
+    protected void unbindFromService(ServiceConnection serviceConnection) {
+        if (serviceConnection != null) {
+            mContext.unbindService(serviceConnection);
+        }
+    }
+
+    protected Intent createBroadcastIntent(String action) {
         final Intent intent = new Intent(action);
         intent.addFlags(
                 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
-        intent.putExtras(mTimeReceiver.createReceiveTimeExtraBinder());
+        putTimeReceiverBinderExtra(intent);
         return intent;
     }
 
+    protected void putTimeReceiverBinderExtra(Intent intent) {
+        intent.putExtras(mTimeReceiver.createReceiveTimeExtraBinder());
+    }
+
     private void setUpIteration() {
         mTimeReceiver.clear();
         TargetPackageUtils.killTargetPackage(mContext);
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
index 795f498..f7dab03 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
@@ -33,7 +33,8 @@
         runPerfFunction(() -> {
             startTargetPackage();
 
-            final Intent intent = createIntent(Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
+            final Intent intent = createBroadcastIntent(
+                    Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
 
             final long startTime = System.nanoTime();
 
@@ -48,7 +49,8 @@
     @Test
     public void manifestBroadcastNotRunning() {
         runPerfFunction(() -> {
-            final Intent intent = createIntent(Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
+            final Intent intent = createBroadcastIntent(
+                    Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
 
             final long startTime = System.nanoTime();
 
@@ -65,7 +67,8 @@
         runPerfFunction(() -> {
             startTargetPackage();
 
-            final Intent intent = createIntent(Constants.ACTION_BROADCAST_REGISTERED_RECEIVE);
+            final Intent intent = createBroadcastIntent(
+                    Constants.ACTION_BROADCAST_REGISTERED_RECEIVE);
 
             final long startTime = System.nanoTime();
 
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java
new file mode 100644
index 0000000..6d2935a
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.am.tests;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.perftests.am.util.Constants;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ServiceBindPerfTest extends BasePerfTest {
+    /**
+     * Create and return a ServiceConnection that will add the current time with type
+     * Constants.TYPE_SERVICE_CONNECTED.
+     */
+    private ServiceConnection createServiceConnectionReportTime() {
+        return new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                addReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+            }
+        };
+    }
+
+    /**
+     * Try to bind to the service with the input parameters, throwing a RuntimeException with the
+     * errorMessage on failure.
+     */
+    private void bindService(Intent intent, ServiceConnection serviceConnection, int flags) {
+        final boolean success = mContext.bindService(intent, serviceConnection, flags);
+        Assert.assertTrue("Could not bind to service", success);
+    }
+
+    /**
+     * Benchmark time from Context.bindService() to Service.onBind() when target package is not
+     * running.
+     */
+    @Test
+    public void bindServiceNotRunning() {
+        runPerfFunction(() -> {
+            final Intent intent = createServiceIntent();
+            final ServiceConnection serviceConnection = createServiceConnectionReportTime();
+
+            final long startTimeNs = System.nanoTime();
+            bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+            try {
+                final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+                return endTimeNs - startTimeNs;
+            } finally {
+                unbindFromService(serviceConnection);
+            }
+        });
+    }
+
+    /**
+     * Benchmark time from Context.bindService() to Service.onBind() when target package is running.
+     */
+    @Test
+    public void bindServiceRunning() {
+        runPerfFunction(() -> {
+            startTargetPackage();
+
+            final Intent intent = createServiceIntent();
+            final ServiceConnection serviceConnection = createServiceConnectionReportTime();
+
+            final long startTimeNs = System.nanoTime();
+            bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+            try {
+                final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+                return endTimeNs - startTimeNs;
+            } finally {
+                unbindFromService(serviceConnection);
+            }
+        });
+    }
+
+    /**
+     * Benchmark time from Context.bindService() to Service.onBind() when service is already bound
+     * to.
+     */
+    @Test
+    public void bindServiceAlreadyBound() {
+        runPerfFunction(() -> {
+            startTargetPackage();
+
+            final Intent intent = createServiceIntent();
+            final ServiceConnection alreadyBoundServiceConnection = bindAndWaitForConnectedService();
+
+            try {
+                final ServiceConnection serviceConnection = createServiceConnectionReportTime();
+
+                final long startTimeNs = System.nanoTime();
+                try {
+                    bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+                    final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+                    return endTimeNs - startTimeNs;
+                } finally {
+                    unbindFromService(serviceConnection);
+                }
+            } finally {
+                unbindFromService(alreadyBoundServiceConnection);
+            }
+        });
+    }
+
+    /**
+     * Benchmark time from Context.bindService() (without BIND_ALLOW_OOM_MANAGEMENT) to
+     * Service.onBind() when service is already bound to with BIND_ALLOW_OOM_MANAGEMENT.
+     */
+    @Test
+    public void bindServiceAllowOomManagement() {
+        runPerfFunction(() -> {
+            final Intent intentNoOom = createServiceIntent();
+            final ServiceConnection serviceConnectionOom = bindAndWaitForConnectedService(
+                    Context.BIND_ALLOW_OOM_MANAGEMENT);
+
+            try {
+                final ServiceConnection serviceConnectionNoOom =
+                        createServiceConnectionReportTime();
+                try {
+                    final long startTimeNs = System.nanoTime();
+                    bindService(intentNoOom, serviceConnectionNoOom, Context.BIND_AUTO_CREATE);
+                    final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+
+                    return endTimeNs - startTimeNs;
+                } finally {
+                    unbindFromService(serviceConnectionNoOom);
+                }
+            } finally {
+                unbindFromService(serviceConnectionOom);
+            }
+        });
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
new file mode 100644
index 0000000..626ee02
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.frameworks.perftests.am.tests;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.perftests.am.util.Constants;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ServiceStartPerfTest extends BasePerfTest {
+
+    /**
+     * Tries to start the service with the given intent, throwing a RuntimeException with the
+     * errorMessage on failure.
+     */
+    private void startService(Intent intent) {
+        final ComponentName componentName = mContext.startService(intent);
+        Assert.assertNotNull("Could not start service", componentName);
+    }
+
+    /**
+     * Benchmark time from Context.startService() to Service.onStartCommand() when target process is
+     * not running.
+     */
+    @Test
+    public void startServiceNotRunning() {
+        runPerfFunction(() -> {
+            final Intent intent = createServiceIntent();
+
+            final long startTimeNs = System.nanoTime();
+
+            startService(intent);
+
+            final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_START);
+            return endTimeNs - startTimeNs;
+        });
+    }
+
+    /**
+     * Benchmark time from Context.startService() to Service.onStartCommand() when target process is
+     * running.
+     */
+    @Test
+    public void startServiceProcessRunning() {
+        runPerfFunction(() -> {
+            startTargetPackage();
+
+            final Intent intent = createServiceIntent();
+
+            final long startTimeNs = System.nanoTime();
+            startService(intent);
+            final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_START);
+
+            return endTimeNs - startTimeNs;
+        });
+    }
+
+    /**
+     * Benchmark time from Context.startService() to Service.onStartCommand() when service is
+     * already bound to.
+     */
+    @Test
+    public void startServiceAlreadyBound() {
+        runPerfFunction(() -> {
+            final ServiceConnection alreadyBoundServiceConnection =
+                    bindAndWaitForConnectedService();
+            try {
+                final Intent intent = createServiceIntent();
+
+                final long startTimeNs = System.nanoTime();
+                startService(intent);
+                final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_START);
+
+                return endTimeNs - startTimeNs;
+            } finally {
+                unbindFromService(alreadyBoundServiceConnection);
+            }
+        });
+    }
+
+    /**
+     * Benchmark time from Context.startService() with FLAG_GRANT_READ_URI_PERMISSION to
+     * Service.onStartCommand() when target process is running.
+     */
+    @Test
+    public void startServiceProcessRunningReadUriPermission() {
+        runPerfFunction(() -> {
+            final ServiceConnection alreadyBoundServiceConnection =
+                    bindAndWaitForConnectedService();
+            try {
+                final Intent intent = createServiceIntent();
+                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+                final long startTimeNs = System.nanoTime();
+                startService(intent);
+                final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_START);
+
+                return endTimeNs - startTimeNs;
+            } finally {
+                unbindFromService(alreadyBoundServiceConnection);
+            }
+        });
+    }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
index c867141..3db8abc 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
@@ -27,6 +27,7 @@
 
     public static final String PACKAGE_NAME = "com.android.frameworks.perftests.amteststestapp";
     public static final String ACTIVITY_NAME = PACKAGE_NAME + ".TestActivity";
+    public static final String SERVICE_NAME = PACKAGE_NAME + ".TestService";
 
     private static final long WAIT_TIME_MS = 100L;
 
@@ -62,7 +63,7 @@
             sleep();
         }
         // make sure Application has run
-        timeReceiver.getReceivedTimeNs(Constants.TYPE_ACTIVITY_CREATED);
+        timeReceiver.getReceivedTimeNs(Constants.TYPE_TARGET_PACKAGE_START);
         Utils.drainBroadcastQueue();
     }
 
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java
index 9cf6ee7..a86a5c7 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java
@@ -45,20 +45,23 @@
         }
     }
 
+    public void addTimeForTypeToQueue(String type, long timeNs) {
+        if (type == null) {
+            throw new IllegalArgumentException("type is null when adding time to queue");
+        }
+        if (timeNs < 0) {
+            throw new RuntimeException(
+                    "time is negative/non-existant (" + timeNs + ") when adding time to queue");
+        }
+        mQueue.add(new ReceivedMessage(type, timeNs));
+    }
+
     public Bundle createReceiveTimeExtraBinder() {
         Bundle extras = new Bundle();
         extras.putBinder(Constants.EXTRA_RECEIVER_CALLBACK, new ITimeReceiverCallback.Stub() {
             @Override
             public void sendTime(String type, long timeNs) throws RemoteException {
-                if (type == null) {
-                    throw new RuntimeException("receivedType is null");
-                }
-                if (timeNs < 0) {
-                    throw new RuntimeException(
-                            "receivedTime is negative/non-existant: " + timeNs);
-                }
-                Log.i(TAG, type + " " + timeNs);
-                mQueue.add(new ReceivedMessage(type, timeNs));
+                addTimeForTypeToQueue(type, timeNs);
             }
         });
         return extras;
diff --git a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
index 6528028..ffb3f84 100644
--- a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
+++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
@@ -17,8 +17,11 @@
 package com.android.frameworks.perftests.am.util;
 
 public class Constants {
-    public static final String TYPE_ACTIVITY_CREATED = "activity_create";
+    public static final String TYPE_TARGET_PACKAGE_START = "target_package_start";
     public static final String TYPE_BROADCAST_RECEIVE = "broadcast_receive";
+    public static final String TYPE_SERVICE_BIND = "service_bind";
+    public static final String TYPE_SERVICE_START = "service_start";
+    public static final String TYPE_SERVICE_CONNECTED = "service_connection_connect";
 
     public static final String ACTION_BROADCAST_MANIFEST_RECEIVE =
             "com.android.frameworks.perftests.ACTION_BROADCAST_MANIFEST_RECEIVE";
diff --git a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
index d46fff4..a7d5ae8 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
@@ -99,6 +99,21 @@
     }
 
     @Test
+    public void tonal_rangeTest() {
+        Tonal.ConfigParser config = new Tonal.ConfigParser(InstrumentationRegistry.getContext());
+        for (Tonal.TonalPalette palette : config.getTonalPalettes()) {
+            assertTrue("minHue should be >= to 0.", palette.minHue >= 0);
+            assertTrue("maxHue should be <= to 360.", palette.maxHue <= 360);
+
+            assertTrue("S should be >= to 0.", palette.s[0] >= 0);
+            assertTrue("S should be <= to 1.", palette.s[1] <= 1);
+
+            assertTrue("L should be >= to 0.", palette.l[0] >= 0);
+            assertTrue("L should be <= to 1.", palette.l[1] <= 1);
+        }
+    }
+
+    @Test
     public void tonal_blacklistTest() {
         // Make sure that palette generation will fail.
         final Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
diff --git a/tests/JankBench/Android.mk b/tests/JankBench/Android.mk
index 12568a0..291ba78 100644
--- a/tests/JankBench/Android.mk
+++ b/tests/JankBench/Android.mk
@@ -19,7 +19,7 @@
 
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
-    android-support-design \
+    $(ANDROID_SUPPORT_DESIGN_TARGETS) \
     android-support-v4 \
     android-support-v7-appcompat \
     android-support-v7-cardview \
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index 60327e5..c8e6c20 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -15,7 +15,7 @@
 LOCAL_USE_AAPT2 := true
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
-    android-support-design \
+    $(ANDROID_SUPPORT_DESIGN_TARGETS) \
     android-support-v4 \
     android-support-v7-appcompat \
     android-support-v7-cardview \
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 9aad413..04266c5 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -172,7 +172,7 @@
         final int iterations = 1000;
         final String expectedAndroidOui = "da:a1:19";
         for (int i = 0; i < iterations; i++) {
-            MacAddress mac = MacAddress.createRandomUnicastAddress();
+            MacAddress mac = MacAddress.createRandomUnicastAddressWithGoogleBase();
             String stringRepr = mac.toString();
 
             assertTrue(stringRepr + " expected to be a locally assigned address",
@@ -195,6 +195,15 @@
             assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
                     stringRepr.startsWith(expectedLocalOui));
         }
+
+        for (int i = 0; i < iterations; i++) {
+            MacAddress mac = MacAddress.createRandomUnicastAddress();
+            String stringRepr = mac.toString();
+
+            assertTrue(stringRepr + " expected to be a locally assigned address",
+                    mac.isLocallyAssigned());
+            assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
+        }
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 6e643a3..e7abede 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -318,6 +318,7 @@
 
     // This test has an inherent race condition in it, and cannot be enabled for continuous testing
     // or presubmit tests. It is kept for manual runs and documentation purposes.
+    @Ignore
     public void verifyThatNotWaitingForIdleCausesRaceConditions() {
         // Bring up a network that we can use to send messages to ConnectivityService.
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 669afe1..734a5ab 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4848,6 +4848,7 @@
     const String16 pathInterpolator16("pathInterpolator");
     const String16 objectAnimator16("objectAnimator");
     const String16 gradient16("gradient");
+    const String16 animatedSelector16("animated-selector");
 
     const int minSdk = getMinSdkVersion(bundle);
     if (minSdk >= SDK_LOLLIPOP_MR1) {
@@ -4876,7 +4877,8 @@
                     node->getElementName() == animatedVector16 ||
                     node->getElementName() == objectAnimator16 ||
                     node->getElementName() == pathInterpolator16 ||
-                    node->getElementName() == gradient16)) {
+                    node->getElementName() == gradient16 ||
+                    node->getElementName() == animatedSelector16)) {
             // We were told not to version vector tags, so skip the children here.
             continue;
         }
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index c9e272c..15c5eae 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -450,7 +450,7 @@
 
 static bool IsVectorElement(const std::string& name) {
   return name == "vector" || name == "animated-vector" || name == "pathInterpolator" ||
-         name == "objectAnimator" || name == "gradient";
+         name == "objectAnimator" || name == "gradient" || name == "animated-selector";
 }
 
 template <typename T>
@@ -1446,6 +1446,13 @@
 
     ContainerReaderEntry* entry;
     ContainerReader reader(input_stream.get());
+
+    if (reader.HadError()) {
+      context_->GetDiagnostics()->Error(DiagMessage(src)
+                                        << "failed to read file: " << reader.GetError());
+      return false;
+    }
+
     while ((entry = reader.Next()) != nullptr) {
       if (entry->Type() == ContainerEntryType::kResTable) {
         pb::ResourceTable pb_table;
diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt
index f278aec..d75aea5 100644
--- a/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt
+++ b/tools/sdkparcelables/src/com/android/sdkparcelables/AncestorCollector.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.sdkparcelables
 
 import org.objectweb.asm.ClassVisitor
@@ -25,4 +41,4 @@
 
         super.visit(version, access, name, signature, superName, interfaces)
     }
-}
\ No newline at end of file
+}
diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
index 3e9d92c..22e8d78 100644
--- a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
+++ b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.sdkparcelables
 
 import org.objectweb.asm.ClassReader
@@ -53,4 +69,4 @@
 fun usage() {
     System.err.println("Usage: <input jar> <output aidl>")
     kotlin.system.exitProcess(1)
-}
\ No newline at end of file
+}
diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt
index 620f798..d6a0a45 100644
--- a/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt
+++ b/tools/sdkparcelables/src/com/android/sdkparcelables/ParcelableDetector.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.sdkparcelables
 
 /** A class that uses an ancestor map to find all classes that
diff --git a/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt b/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt
index edfc825..c9bcbc9 100644
--- a/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt
+++ b/tools/sdkparcelables/tests/com/android/sdkparcelables/ParcelableDetectorTest.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.sdkparcelables
 
 import junit.framework.TestCase.assertEquals
diff --git a/wifi/java/android/net/wifi/IRttManager.aidl b/wifi/java/android/net/wifi/IRttManager.aidl
deleted file mode 100644
index 3831809..0000000
--- a/wifi/java/android/net/wifi/IRttManager.aidl
+++ /dev/null
@@ -1,28 +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;
-import android.os.Messenger;
-import android.net.wifi.RttManager;
-
-/**
- * {@hide}
- */
-interface IRttManager
-{
-    Messenger getMessenger(in IBinder binder, out int[] key);
-    RttManager.RttCapabilities getRttCapabilities();
-}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index fe63aa1..bdbc149 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -12,7 +12,7 @@
 import android.net.wifi.rtt.RangingResult;
 import android.net.wifi.rtt.RangingResultCallback;
 import android.net.wifi.rtt.WifiRttManager;
-import android.os.Looper;
+import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -24,6 +24,7 @@
 
 /** @hide */
 @SystemApi
+@Deprecated
 @SystemService(Context.WIFI_RTT_SERVICE)
 public class RttManager {
 
@@ -181,6 +182,7 @@
     /**
      * This class describe the RTT capability of the Hardware
      */
+    @Deprecated
     public static class RttCapabilities implements Parcelable {
         /** @deprecated It is not supported*/
         @Deprecated
@@ -314,12 +316,16 @@
              };
     }
 
+    /**
+     * This method is deprecated. Please use the {@link WifiRttManager} API.
+     */
     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
     public RttCapabilities getRttCapabilities() {
         return mRttCapabilities;
     }
 
     /** specifies parameters for RTT request */
+    @Deprecated
     public static class RttParams {
         /**
          * type of destination device being ranged
@@ -502,6 +508,7 @@
     }
 
     /** pseudo-private class used to parcel arguments */
+    @Deprecated
     public static class ParcelableRttParams implements Parcelable {
 
         @NonNull
@@ -589,12 +596,14 @@
                 };
     }
 
+    @Deprecated
     public static class WifiInformationElement {
         /** Information Element ID 0xFF means element is invalid. */
         public byte id;
         public byte[] data;
     }
     /** specifies RTT results */
+    @Deprecated
     public static class RttResult {
         /** mac address of the device being ranged. */
         public String bssid;
@@ -746,6 +755,7 @@
 
 
     /** pseudo-private class used to parcel results. */
+    @Deprecated
     public static class ParcelableRttResults implements Parcelable {
 
         public RttResult mResults[];
@@ -838,8 +848,8 @@
                     }
                     dest.writeByte(result.LCR.id);
                     if (result.LCR.id != (byte) 0xFF) {
-                        dest.writeInt((byte) result.LCR.data.length);
-                        dest.writeByte(result.LCR.id);
+                        dest.writeByte((byte) result.LCR.data.length);
+                        dest.writeByteArray(result.LCR.data);
                     }
                     dest.writeByte(result.secure ? (byte) 1 : 0);
                 }
@@ -911,7 +921,7 @@
                 };
     }
 
-
+    @Deprecated
     public static interface RttListener {
         public void onSuccess(RttResult[] results);
         public void onFailure(int reason, String description);
@@ -919,52 +929,10 @@
     }
 
     /**
-     * A parcelable that contains rtt client information.
-     *
-     * @hide
-     */
-    public static class RttClient implements Parcelable {
-        // Package name of RttClient.
-        private final String mPackageName;
-
-        public RttClient(String packageName) {
-            mPackageName = packageName;
-        }
-
-        protected RttClient(Parcel in) {
-            mPackageName = in.readString();
-        }
-
-        public static final Creator<RttManager.RttClient> CREATOR =
-                new Creator<RttManager.RttClient>() {
-            @Override
-            public RttManager.RttClient createFromParcel(Parcel in) {
-                return new RttManager.RttClient(in);
-            }
-
-            @Override
-            public RttManager.RttClient[] newArray(int size) {
-                return new RttManager.RttClient[size];
-            }
-        };
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel parcel, int i) {
-            parcel.writeString(mPackageName);
-        }
-
-        public String getPackageName() {
-            return mPackageName;
-        }
-    }
-
-    /**
      * Request to start an RTT ranging
+     * <p>
+     * This method is deprecated. Please use the
+     * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)} API.
      *
      * @param params  -- RTT request Parameters
      * @param listener -- Call back to inform RTT result
@@ -1036,6 +1004,10 @@
         }
     }
 
+    /**
+     * This method is deprecated and performs no function. Please use the {@link WifiRttManager}
+     * API.
+     */
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public void stopRanging(RttListener listener) {
         Log.e(TAG, "stopRanging: unsupported operation - nop");
@@ -1050,6 +1022,7 @@
      * The client can freely destroy or reuse the callback after {@link RttManager#disableResponder}
      * is called.
      */
+    @Deprecated
     public abstract static class ResponderCallback {
         /** Callback when responder is enabled. */
         public abstract void onResponderEnabled(ResponderConfig config);
@@ -1065,6 +1038,10 @@
      * Note calling this method with the same callback when the responder is already enabled won't
      * change the responder state, a cached {@link ResponderConfig} from the last enabling will be
      * returned through the callback.
+     * <p>
+     * This method is deprecated and will throw an {@link UnsupportedOperationException}
+     * exception. Please use the {@link WifiRttManager} API to perform a Wi-Fi Aware peer-to-peer
+     * ranging.
      *
      * @param callback Callback for responder enabling/disabling result.
      * @throws IllegalArgumentException If {@code callback} is null.
@@ -1081,6 +1058,10 @@
      * <p>
      * Calling this method when responder isn't enabled won't have any effect. The callback can be
      * reused for enabling responder after this method is called.
+     * <p>
+     * This method is deprecated and will throw an {@link UnsupportedOperationException}
+     * exception. Please use the {@link WifiRttManager} API to perform a Wi-Fi Aware peer-to-peer
+     * ranging.
      *
      * @param callback The same callback used for enabling responder.
      * @throws IllegalArgumentException If {@code callback} is null.
@@ -1097,6 +1078,7 @@
      *
      * @see ScanResult
      */
+    @Deprecated
     public static class ResponderConfig implements Parcelable {
 
         // TODO: make all fields final once we can get mac address from responder HAL APIs.
@@ -1202,7 +1184,6 @@
     /** @hide */
     public static final int CMD_OP_REG_BINDER           = BASE + 9;
 
-    private final Context mContext;
     private final WifiRttManager mNewService;
     private RttCapabilities mRttCapabilities;
 
@@ -1211,17 +1192,14 @@
      * Applications will almost always want to use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
      * the standard {@link android.content.Context#WIFI_RTT_SERVICE Context.WIFI_RTT_SERVICE}.
-     * @param context the application context
-     * @param service the Binder interface
-     * @param looper Looper for running the callbacks.
+     * @param service the new WifiRttManager service
      *
      * @hide
      */
-    public RttManager(Context context, IRttManager service, Looper looper) {
-        mContext = context;
-        mNewService = (WifiRttManager) mContext.getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
+    public RttManager(Context context, WifiRttManager service) {
+        mNewService = service;
 
-        boolean rttSupported = mContext.getPackageManager().hasSystemFeature(
+        boolean rttSupported = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_WIFI_RTT);
 
         mRttCapabilities = new RttCapabilities();
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index c46789c..8024bf0 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -273,27 +273,6 @@
     public RadioChainInfo[] radioChainInfos;
 
     /**
-     * @hide
-     * Update RSSI of the scan result
-     * @param previousRssi
-     * @param previousSeen
-     * @param maxAge
-     */
-    public void averageRssi(int previousRssi, long previousSeen, int maxAge) {
-
-        if (seen == 0) {
-            seen = System.currentTimeMillis();
-        }
-        long age = seen - previousSeen;
-
-        if (previousSeen > 0 && age > 0 && age < maxAge/2) {
-            // Average the RSSI with previously seen instances of this scan result
-            double alpha = 0.5 - (double) age / (double) maxAge;
-            level = (int) ((double) level * (1 - alpha) + (double) previousRssi * alpha);
-        }
-    }
-
-    /**
      * Status indicating the scan result does not correspond to a user's saved configuration
      * @hide
      * @removed
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 7da2656..ddcf327 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -917,6 +917,9 @@
      * Does not guarantee that the returned address is valid for use.
      */
     public MacAddress getRandomizedMacAddress() {
+        if (mRandomizedMacAddress == null) {
+            mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS;
+        }
         return mRandomizedMacAddress;
     }
 
@@ -1617,6 +1620,7 @@
         creatorUid = -1;
         shared = true;
         dtimInterval = 0;
+        mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS;
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java
index 32f21b9..52b3d86 100644
--- a/wifi/java/android/net/wifi/rtt/RangingRequest.java
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java
@@ -156,14 +156,18 @@
         /**
          * Add the device specified by the {@code peerMacAddress} to the list of devices with
          * which to measure range.
-         *
+         * <p>
          * The MAC address may be obtained out-of-band from a peer Wi-Fi Aware device. A Wi-Fi
          * Aware device may obtain its MAC address using the {@link IdentityChangedListener}
          * provided to
          * {@link WifiAwareManager#attach(AttachCallback, IdentityChangedListener, Handler)}.
-         *
-         * * Note: in order to use this API the device must support Wi-Fi Aware
-         * {@link android.net.wifi.aware}.
+         * <p>
+         * Note: in order to use this API the device must support Wi-Fi Aware
+         * {@link android.net.wifi.aware}. The peer device which is being ranged to must be
+         * configured to publish a service (with any name) with:
+         * <li>Type {@link android.net.wifi.aware.PublishConfig#PUBLISH_TYPE_UNSOLICITED}.
+         * <li>Ranging enabled
+         * {@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)}.
          *
          * @param peerMacAddress The MAC address of the Wi-Fi Aware peer.
          * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
@@ -179,12 +183,16 @@
         /**
          * Add a device specified by a {@link PeerHandle} to the list of devices with which to
          * measure range.
-         *
+         * <p>
          * The {@link PeerHandle} may be obtained as part of the Wi-Fi Aware discovery process. E.g.
          * using {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)}.
-         *
+         * <p>
          * Note: in order to use this API the device must support Wi-Fi Aware
-         * {@link android.net.wifi.aware}.
+         * {@link android.net.wifi.aware}. The peer device which is being ranged to must be
+         * configured to publish a service (with any name) with:
+         * <li>Type {@link android.net.wifi.aware.PublishConfig#PUBLISH_TYPE_UNSOLICITED}.
+         * <li>Ranging enabled
+         * {@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)}.
          *
          * @param peerHandle The peer handler of the peer Wi-Fi Aware device.
          * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index e7377c1..8a3a7f5 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -176,6 +176,8 @@
     @Test
     public void testGetOrCreateRandomizedMacAddress_SavesAndReturnsSameAddress() {
         WifiConfiguration config = new WifiConfiguration();
+        assertEquals(MacAddress.ALL_ZEROS_ADDRESS, config.getRandomizedMacAddress());
+
         MacAddress firstMacAddress = config.getOrCreateRandomizedMacAddress();
         MacAddress secondMacAddress = config.getOrCreateRandomizedMacAddress();
 
@@ -185,6 +187,8 @@
     @Test
     public void testSetRandomizedMacAddress_ChangesSavedAddress() {
         WifiConfiguration config = new WifiConfiguration();
+        assertEquals(MacAddress.ALL_ZEROS_ADDRESS, config.getRandomizedMacAddress());
+
         MacAddress macToChangeInto = MacAddress.createRandomUnicastAddress();
         config.setRandomizedMacAddress(macToChangeInto);
         MacAddress macAfterChange = config.getOrCreateRandomizedMacAddress();
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 71ca068..f3a78bd 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -611,6 +611,7 @@
     /**
      * Verify the watchLocalOnlyHotspot call goes to WifiServiceImpl.
      */
+    @Test
     public void testWatchLocalOnlyHotspot() throws Exception {
         TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
 
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java
index 1e8382f..e8e4dc2 100644
--- a/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java
@@ -59,10 +59,10 @@
      */
     @Test
     public void testChannelFinalize() throws Exception {
-        WifiP2pManager.Channel channel = new WifiP2pManager.Channel(mContextMock,
-                mTestLooper.getLooper(), null, null, mDut);
-
-        leakageDetectorRule.assertUnreleasedResourceCount(channel, 1);
+        try (WifiP2pManager.Channel channel = new WifiP2pManager.Channel(mContextMock,
+                mTestLooper.getLooper(), null, null, mDut)) {
+            leakageDetectorRule.assertUnreleasedResourceCount(channel, 1);
+        }
     }
 
     /**