Merge "Add handle suppression to learned state" into qt-dev
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 0b81027..eed7f62 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -322,7 +322,7 @@
     }
 
     // Pulled events will start at field 10000.
-    // Next: 10059
+    // Next: 10062
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000;
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -385,6 +385,7 @@
         FaceSettings face_settings = 10058;
         CoolingDevice cooling_device = 10059;
         AppOps app_ops = 10060;
+        ProcessSystemIonHeapSize process_system_ion_heap_size = 10061;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -6369,6 +6370,28 @@
     optional int64 size_in_bytes = 1;
 }
 
+/*
+ * Logs the per-process size of the system ion heap.
+ *
+ * Pulled from StatsCompanionService.
+ */
+message ProcessSystemIonHeapSize {
+    // The uid if available. -1 means not available.
+    optional int32 uid = 1 [(is_uid) = true];
+
+    // The process name (from /proc/PID/cmdline).
+    optional string process_name = 2;
+
+    // Sum of sizes of all allocations.
+    optional int32 total_size_in_kilobytes = 3;
+
+    // Number of allocations.
+    optional int32 allocation_count = 4;
+
+    // Size of the largest allocation.
+    optional int32 max_size_in_kilobytes = 5;
+}
+
 /**
  * Push network stack events.
  *
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 914d60d..475f18a 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -156,6 +156,9 @@
         // system_ion_heap_size
         {android::util::SYSTEM_ION_HEAP_SIZE,
          {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}},
+        // process_system_ion_heap_size
+        {android::util::PROCESS_SYSTEM_ION_HEAP_SIZE,
+         {.puller = new StatsCompanionServicePuller(android::util::PROCESS_SYSTEM_ION_HEAP_SIZE)}},
         // temperature
         {android::util::TEMPERATURE,
          {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 3494a7f..eb33137 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -25,6 +25,7 @@
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.SurfaceUtils;
 import android.os.Handler;
+import android.os.ConditionVariable;
 import android.util.Range;
 import android.view.Surface;
 
@@ -51,6 +52,7 @@
         extends CameraConstrainedHighSpeedCaptureSession implements CameraCaptureSessionCore {
     private final CameraCharacteristics mCharacteristics;
     private final CameraCaptureSessionImpl mSessionImpl;
+    private final ConditionVariable mInitialized = new ConditionVariable();
 
     /**
      * Create a new CameraCaptureSession.
@@ -68,6 +70,7 @@
         CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
         mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback,
                 stateExecutor, deviceImpl, deviceStateExecutor, configureSuccess);
+        mInitialized.open();
     }
 
     @Override
@@ -321,11 +324,13 @@
 
         @Override
         public void onConfigured(CameraCaptureSession session) {
+            mInitialized.block();
             mCallback.onConfigured(CameraConstrainedHighSpeedCaptureSessionImpl.this);
         }
 
         @Override
         public void onConfigureFailed(CameraCaptureSession session) {
+            mInitialized.block();
             mCallback.onConfigureFailed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
         }
 
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 1b41694..53298d8 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -30,7 +30,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.os.storage.IStorageManager;
 import android.provider.Settings;
 import android.telephony.euicc.EuiccManager;
 import android.text.TextUtils;
@@ -39,8 +38,6 @@
 import android.view.Display;
 import android.view.WindowManager;
 
-import com.android.internal.content.PackageHelper;
-
 import libcore.io.Streams;
 
 import java.io.ByteArrayInputStream;
@@ -858,18 +855,31 @@
     public static void rebootPromptAndWipeUserData(Context context, String reason)
             throws IOException {
         boolean checkpointing = false;
+        boolean needReboot = false;
+        IVold vold = null;
+        try {
+            vold = IVold.Stub.asInterface(ServiceManager.checkService("vold"));
+            if (vold != null) {
+                checkpointing = vold.needsCheckpoint();
+            } else  {
+                Log.w(TAG, "Failed to get vold");
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to check for checkpointing");
+        }
 
         // If we are running in checkpointing mode, we should not prompt a wipe.
         // Checkpointing may save us. If it doesn't, we will wind up here again.
-        try {
-            IStorageManager storageManager = PackageHelper.getStorageManager();
-            if (storageManager.needsCheckpoint()) {
-                Log.i(TAG, "Rescue Party requested wipe. Aborting update instead.");
-                storageManager.abortChanges("rescueparty", false);
-                return;
+        if (checkpointing) {
+            try {
+                vold.abortChanges("rescueparty", false);
+                Log.i(TAG, "Rescue Party requested wipe. Aborting update");
+            } catch (Exception e) {
+                Log.i(TAG, "Rescue Party requested wipe. Rebooting instead.");
+                PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+                pm.reboot("rescueparty");
             }
-        } catch (RemoteException e) {
-            Log.i(TAG, "Failed to handle with checkpointing. Continuing with wipe.");
+            return;
         }
 
         String reasonArg = null;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index bf0ef94..2c2c295 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1122,6 +1122,9 @@
             if (limit > lineEnd) {
                 limit = lineEnd;
             }
+            if (limit == start) {
+                continue;
+            }
             level[limit - lineStart - 1] =
                     (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
         }
@@ -1220,8 +1223,8 @@
     }
 
     /**
-     * Computes in linear time the results of calling
-     * #getHorizontal for all offsets on a line.
+     * Computes in linear time the results of calling #getHorizontal for all offsets on a line.
+     *
      * @param line The line giving the offsets we compute information for
      * @param clamped Whether to clamp the results to the width of the layout
      * @param primary Whether the results should be the primary or the secondary horizontal
@@ -1257,7 +1260,7 @@
         TextLine.recycle(tl);
 
         if (clamped) {
-            for (int offset = 0; offset <= wid.length; ++offset) {
+            for (int offset = 0; offset < wid.length; ++offset) {
                 if (wid[offset] > mWidth) {
                     wid[offset] = mWidth;
                 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5636f48..aceb276 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1107,7 +1107,13 @@
      */
     public void registerRtFrameCallback(FrameDrawingCallback callback) {
         if (mAttachInfo.mThreadedRenderer != null) {
-            mAttachInfo.mThreadedRenderer.registerRtFrameCallback(callback);
+            mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frame -> {
+                try {
+                    callback.onFrameDraw(frame);
+                } catch (Exception e) {
+                    Log.e(TAG, "Exception while executing onFrameDraw", e);
+                }
+            });
         }
     }
 
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5294714..f9d27bb 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2327,10 +2327,12 @@
 
         private static final int MAX_SUGGESTED_APP_TARGETS = 4;
         private static final int MAX_CHOOSER_TARGETS_PER_APP = 2;
-        private static final int MAX_SHORTCUT_TARGETS_PER_APP = 8;
 
         private static final int MAX_SERVICE_TARGETS = 8;
 
+        private final int mMaxShortcutTargetsPerApp =
+                getResources().getInteger(R.integer.config_maxShortcutTargetsPerApp);
+
         private int mNumShortcutResults = 0;
 
         // Reserve spots for incoming direct share targets by adding placeholders
@@ -2648,7 +2650,7 @@
             final float baseScore = getBaseScore(origTarget, isShortcutResult);
             Collections.sort(targets, mBaseTargetComparator);
 
-            final int maxTargets = isShortcutResult ? MAX_SHORTCUT_TARGETS_PER_APP
+            final int maxTargets = isShortcutResult ? mMaxShortcutTargetsPerApp
                                        : MAX_CHOOSER_TARGETS_PER_APP;
             float lastScore = 0;
             boolean shouldNotify = false;
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index 56a40a3..da1b72f 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.policy;
 
+import android.content.AutofillOptions;
 import android.content.ContentCaptureOptions;
 import android.content.Context;
 import android.content.res.AssetManager;
@@ -98,6 +99,15 @@
     }
 
     @Override
+    public AutofillOptions getAutofillOptions() {
+        Context activityContext = mActivityContext.get();
+        if (activityContext != null) {
+            return activityContext.getAutofillOptions();
+        }
+        return null;
+    }
+
+    @Override
     public ContentCaptureOptions getContentCaptureOptions() {
         Context activityContext = mActivityContext.get();
         if (activityContext != null) {
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
index 1bbd87c..82593b5 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -637,6 +637,7 @@
         private static String argCountPrefix(int argCount) {
             switch (argCount) {
                 case MASK_ARG_COUNT: return "";
+                case 0: return "";
                 case 1: return "";
                 case 2: return "Bi";
                 case 3: return "Tri";
@@ -646,7 +647,7 @@
                 case 7: return "Hept";
                 case 8: return "Oct";
                 case 9: return "Nona";
-                default: throw new IllegalArgumentException("" + argCount);
+                default: return "" + argCount + "arg";
             }
         }
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4783a25..82c27f0 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1160,6 +1160,7 @@
   /*
    *  Grant the following capabilities to the Bluetooth user:
    *    - CAP_WAKE_ALARM
+   *    - CAP_NET_ADMIN
    *    - CAP_NET_RAW
    *    - CAP_NET_BIND_SERVICE (for DHCP client functionality)
    *    - CAP_SYS_NICE (for setting RT priority for audio-related threads)
@@ -1167,6 +1168,7 @@
 
   if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
     capabilities |= (1LL << CAP_WAKE_ALARM);
+    capabilities |= (1LL << CAP_NET_ADMIN);
     capabilities |= (1LL << CAP_NET_RAW);
     capabilities |= (1LL << CAP_NET_BIND_SERVICE);
     capabilities |= (1LL << CAP_SYS_NICE);
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 6164191..c023438 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2053,7 +2053,7 @@
     // OS: P
     WIFI_SCANNING_NEEDED_DIALOG = 1373;
 
-    // OPEN: Settings > System > Gestures > Swipe up gesture
+    // OPEN: Settings > System > Gestures > System navigation
     // CATEGORY: SETTINGS
     // OS: P
     SETTINGS_GESTURE_SWIPE_UP = 1374;
@@ -2389,4 +2389,16 @@
     // CATEGORY: SETTINGS
     // OS: Q
     MODULE_LICENSES_DASHBOARD = 1746;
+
+    // OPEN: Settings > System > Gestures > System navigation > Info icon
+    // CATEGORY: SETTINGS
+    // OS: Q
+    // Note: Info icon is visible only when gesture navigation is not available and disabled
+    SETTINGS_GESTURE_NAV_NOT_AVAILABLE_DLG = 1747;
+
+    // OPEN: Settings > System > Gestures > System navigation > Gear icon
+    // CATEGORY: SETTINGS
+    // OS: Q
+    // Note: Gear icon is shown next to gesture navigation preference and opens sensitivity dialog
+    SETTINGS_GESTURE_NAV_BACK_SENSITIVITY_DLG = 1748;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 890ad5e..fef4dcd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -824,6 +824,11 @@
      grants your app this permission. If you don't need this permission, be sure your <a
      href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
      targetSdkVersion}</a> is 4 or higher.
+     <p>Is this permission is not whitelisted for an app that targets an API level before
+     {@link android.os.Build.VERSION_CODES#Q} this permission cannot be granted to apps.</p>
+     <p>Is this permission is not whitelisted for an app that targets an API level
+     {@link android.os.Build.VERSION_CODES#Q} or later the app will be forced into isolated storage.
+     </p>
      -->
     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -845,6 +850,8 @@
          read/write files in your application-specific directories returned by
          {@link android.content.Context#getExternalFilesDir} and
          {@link android.content.Context#getExternalCacheDir}.
+         <p>Is this permission is not whitelisted for an app that targets an API level before
+         {@link android.os.Build.VERSION_CODES#Q} this permission cannot be granted to apps.</p>
     -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -2537,7 +2544,7 @@
     <!-- @SystemApi @TestApi @hide Allows an application to modify config settings.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WRITE_DEVICE_CONFIG"
-        android:protectionLevel="signature|configurator"/>
+        android:protectionLevel="signature|verifier|configurator"/>
 
     <!-- @SystemApi @hide Allows an application to read config settings.
     <p>Not for use by third-party applications. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 8dfb969..77fca8f 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -326,6 +326,8 @@
              grantable in its full form to apps that meet special criteria
              per platform policy. Otherwise, a weaker form of the permission
              would be granted. The weak grant depends on the permission.
+             <p>What weak grant means is described in the documentation of
+             the permissions.
         -->
         <flag name="softRestricted" value="0x8" />
         <!-- This permission is restricted immutably which means that its
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d6604f4..eb7d02b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4143,4 +4143,6 @@
          one bar higher than they actually are -->
     <bool name="config_inflateSignalStrength">false</bool>
 
+    <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q -->
+    <integer name="config_maxShortcutTargetsPerApp">3</integer>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 50814c5..b38c12e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2812,6 +2812,7 @@
   <java-symbol type="layout" name="chooser_grid_preview_file" />
   <java-symbol type="id" name="chooser_row_text_option" />
   <java-symbol type="dimen" name="chooser_row_text_option_translate" />
+  <java-symbol type="integer" name="config_maxShortcutTargetsPerApp" />
   <java-symbol type="layout" name="resolve_grid_item" />
   <java-symbol type="id" name="day_picker_view_pager" />
   <java-symbol type="layout" name="day_picker_content_material" />
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 990161a..93a6b15 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -743,6 +743,9 @@
         assertPrimaryIsTrailingPrevious(
                 RTL + LRI + RTL + LTR + PDI + RTL,
                 new boolean[]{false, false, true, false, false, false, false});
+        assertPrimaryIsTrailingPrevious(
+                "",
+                new boolean[]{false});
     }
 }
 
diff --git a/data/keyboards/Vendor_045e_Product_02e3.kl b/data/keyboards/Vendor_045e_Product_02e3.kl
new file mode 100644
index 0000000..0a6e7d7
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_02e3.kl
@@ -0,0 +1,56 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Microsoft X-Box One Elite Pad - Model 1698 - USB
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 0x130   BUTTON_A
+key 0x131   BUTTON_B
+key 0x133   BUTTON_X
+key 0x134   BUTTON_Y
+
+key 0x136   BUTTON_L1
+key 0x137   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left stick
+axis 0x00 X
+axis 0x01 Y
+# Right stick
+axis 0x03 Z
+axis 0x04 RZ
+
+key 0x13d   BUTTON_THUMBL
+key 0x13e   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+
+# Two overlapping rectangles
+key 0x13a   BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 0x13b   BUTTON_START
+
+# Xbox key
+key 0x13c   BUTTON_MODE
diff --git a/data/keyboards/Vendor_0e6f_Product_02a4.kl b/data/keyboards/Vendor_0e6f_Product_02a4.kl
new file mode 100644
index 0000000..9ffae33
--- /dev/null
+++ b/data/keyboards/Vendor_0e6f_Product_02a4.kl
@@ -0,0 +1,54 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# PDP Wired Controller for Xbox One - Stealth Series
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 304   BUTTON_A
+key 305   BUTTON_B
+key 307   BUTTON_X
+key 308   BUTTON_Y
+
+key 310   BUTTON_L1
+key 311   BUTTON_R1
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Left and right stick.
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+
+key 317   BUTTON_THUMBL
+key 318   BUTTON_THUMBR
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 314    BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 315    BUTTON_START
+
+# Xbox key
+key 316    BUTTON_MODE
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index db6a858..10f76b0 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -58,9 +58,6 @@
         "android.hardware.cas.native@1.0",
         "android.hidl.memory@1.0",
         "android.hidl.token@1.0-utils",
-
-        // to speed up later users of this library
-        "libsfplugin_ccodec",
     ],
 
     header_libs: ["libhardware_headers"],
diff --git a/packages/SettingsLib/SearchWidget/res/values-sw/strings.xml b/packages/SettingsLib/SearchWidget/res/values-sw/strings.xml
index 297ecdb..199845b 100644
--- a/packages/SettingsLib/SearchWidget/res/values-sw/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-sw/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="search_menu" msgid="1604061903696928905">"Tafuta mipangilio"</string>
+    <string name="search_menu" msgid="1604061903696928905">"Tafuta katika mipangilio"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index bdbde46..13890e0 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -219,7 +219,7 @@
     <string name="mock_location_app_set" msgid="8966420655295102685">"অনুরূপ লোকেশন অ্যাপ্লিকেশান: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="7044075693643009662">"নেটওয়ার্কিং"</string>
     <string name="wifi_display_certification" msgid="8611569543791307533">"ওয়্যারলেস ডিসপ্লে সার্টিফিকেশন"</string>
-    <string name="wifi_verbose_logging" msgid="4203729756047242344">"ওয়াই-ফাই ভারবোস লগিং সক্ষম করুন"</string>
+    <string name="wifi_verbose_logging" msgid="4203729756047242344">"ওয়াই-ফাই ভারবোস লগিং চালু করুন"</string>
     <string name="wifi_scan_throttling" msgid="160014287416479843">"ওয়াই-ফাই স্ক্যান থ্রোটলিং"</string>
     <string name="mobile_data_always_on" msgid="8774857027458200434">"মোবাইল ডেটা সব সময় সক্রিয় থাক"</string>
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন"</string>
@@ -262,7 +262,7 @@
     <string name="allow_mock_location_summary" msgid="317615105156345626">"মক অবস্থানগুলি মঞ্জুর করুন"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"অ্যাট্রিবিউট ইন্সপেকশন দেখা চালু করুন"</string>
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"ওয়াই-ফাই সক্রিয় থাকার সময়েও (দ্রুত নেটওয়ার্কে পাল্টানোর জন্য) সর্বদা মোবাইল ডেটা সক্রিয় রাখুন।"</string>
-    <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন উপলব্ধ থাকলে ব্যবহার করুন"</string>
+    <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন উপলভ্য থাকলে ব্যবহার করুন"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"USB ডিবাগিং মঞ্জুর করবেন?"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"USB ডিবাগিং কেবলমাত্র বিকাশ করার উদ্দেশ্যে। আপনার কম্পিউটার এবং আপনার ডিভাইসের মধ্যে ডেটা অনুলিপি করতে এটি ব্যবহার করুন, বিজ্ঞপ্তি ছাড়া আপনার ডিভাইসে অ্যাপ্লিকেশানগুলি ইনস্টল করুন এবং ডেটা লগ পড়ুন।"</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"আপনি আগে যে সব কম্পিউটার USB ডিবাগিং এর অ্যাক্সেসের অনুমতি দিয়েছিলেন তা প্রত্যাহার করবেন?"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index d464256..afdb105 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -220,7 +220,7 @@
     <string name="debug_networking_category" msgid="7044075693643009662">"Xarxes"</string>
     <string name="wifi_display_certification" msgid="8611569543791307533">"Certificació de pantalla sense fil"</string>
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"Activa el registre Wi‑Fi detallat"</string>
-    <string name="wifi_scan_throttling" msgid="160014287416479843">"Regulació de la cerca de xarxes Wi‑Fi"</string>
+    <string name="wifi_scan_throttling" msgid="160014287416479843">"Limitació de la cerca de xarxes Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8774857027458200434">"Dades mòbils sempre actives"</string>
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Acceleració per maquinari per a compartició de xarxa"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostra els dispositius Bluetooth sense el nom"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 7c03afb..d8da638 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -246,7 +246,7 @@
     <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Hostname des DNS-Anbieters eingeben"</string>
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"Verbindung nicht möglich"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
-    <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"WLAN-Protokollierungsebene erhöhen, in WiFi Picker pro SSID RSSI anzeigen"</string>
+    <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"WLAN-Protokollierungsebene erhöhen, pro SSID RSSI in WiFi Picker anzeigen"</string>
     <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"Verringert den Akkuverbrauch und verbessert die Netzwerkleistung"</string>
     <string name="wifi_metered_label" msgid="4514924227256839725">"Kostenpflichtig"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"Kostenlos"</string>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 5e50297..63f6c3e 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -43,7 +43,7 @@
     <item msgid="8937994881315223448">"Conectado a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
     <item msgid="1330262655415760617">"Suspendida"</item>
     <item msgid="7698638434317271902">"Desconectando de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
-    <item msgid="197508606402264311">"Desconectada"</item>
+    <item msgid="197508606402264311">"Desconectado"</item>
     <item msgid="8578370891960825148">"Con error"</item>
     <item msgid="5660739516542454527">"Bloqueada"</item>
     <item msgid="1805837518286731242">"Inhabilitando conexión inestable temporalmente..."</item>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index e1277d8..8baf7a2 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -23,7 +23,7 @@
     <string name="wifi_fail_to_scan" msgid="1265540342578081461">"No se puede buscar redes."</string>
     <string name="wifi_security_none" msgid="7985461072596594400">"Ninguna"</string>
     <string name="wifi_remembered" msgid="4955746899347821096">"Guardado"</string>
-    <string name="wifi_disconnected" msgid="8085419869003922556">"Desconectada"</string>
+    <string name="wifi_disconnected" msgid="8085419869003922556">"Desconectado"</string>
     <string name="wifi_disabled_generic" msgid="4259794910584943386">"Inhabilitado"</string>
     <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Error de configuración de IP"</string>
     <string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"No conectado debido a la baja calidad de la red"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index d2e3a38..fd3936d 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -246,7 +246,7 @@
     <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Idatzi DNS hornitzailearen ostalari-izena"</string>
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"Ezin izan da konektatu"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Erakutsi hari gabe bistaratzeko ziurtagiriaren aukerak"</string>
-    <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Erakutsi datu gehiago wifi-sareetan saioa hastean. Erakutsi sarearen identifikatzailea eta seinalearen indarra wifi-sareen hautagailuan."</string>
+    <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Erakutsi datu gehiago wifi-sareetan saioa hastean. Erakutsi sarearen identifikatzailea eta seinalearen indarra wifi-sareen hautatzailean."</string>
     <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"Bateria gutxiago kontsumituko da, eta sarearen errendimendua hobetuko."</string>
     <string name="wifi_metered_label" msgid="4514924227256839725">"Sare neurtua"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"Neurtu gabeko sarea"</string>
@@ -261,7 +261,7 @@
     <string name="allow_mock_location" msgid="2787962564578664888">"Onartu kokapen faltsuak"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"Onartu kokapen faltsuak"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"Gaitu ikuspegiaren atributuak ikuskatzeko aukera"</string>
-    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantendu mugikorreko datuak beti aktibo, baita wifi-konexioa aktibo dagoenean ere (sarez bizkor aldatu ahal izateko)"</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Mantendu datu-konexioa beti aktibo, baita wifi-konexioa aktibo dagoenean ere (sare batetik bestera bizkor aldatu ahal izateko)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Erabilgarri badago, erabili konexioa partekatzeko hardwarearen azelerazioa"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"USB arazketa onartu?"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"USB arazketa garapen-xedeetarako soilik dago diseinatuta. Erabil ezazu ordenagailuaren eta gailuaren artean datuak kopiatzeko, aplikazioak gailuan jakinarazi gabe instalatzeko eta erregistro-datuak irakurtzeko."</string>
@@ -462,7 +462,7 @@
     <string name="alarm_template_far" msgid="3779172822607461675">"data: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="zen_mode_duration_settings_title" msgid="229547412251222757">"Iraupena"</string>
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Galdetu beti"</string>
-    <string name="zen_mode_forever" msgid="2704305038191592967">"Desaktibatu arte"</string>
+    <string name="zen_mode_forever" msgid="2704305038191592967">"Zuk desaktibatu arte"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Oraintxe"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Gailu hau"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 6632752..352c276 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -261,7 +261,7 @@
     <string name="allow_mock_location" msgid="2787962564578664888">"مکان‌های کاذب مجاز هستند"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"مکان‌های کاذب مجاز هستند"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"فعال کردن نمایش بازبینی ویژگی"</string>
-    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"‏داده سلولی همیشه فعال نگه داشته می‌شود، حتی وقتی Wi-Fi فعال است (برای جابه‌جایی سریع شبکه)."</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"‏داده تلفن همراه همیشه فعال نگه داشته می‌شود، حتی وقتی Wi-Fi فعال است (برای جابه‌جایی سریع شبکه)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"استفاده از شتاب سخت‌افزاری اشتراک‌گذاری اینترنت درصورت دردسترس بودن"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"‏اشکال‌زدایی USB انجام شود؟"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"‏اشکال‌زدایی USB فقط برای اهداف برنامه‌نویسی در نظر گرفته شده است. از آن برای رونوشت‌برداری داده بین رایانه و دستگاهتان، نصب برنامه‌ها در دستگاهتان بدون اعلان و خواندن داده‌های گزارش استفاده کنید."</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 3aa8db9..cf4ee13 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -146,7 +146,7 @@
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Partage connexion Bluetooth"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Partage de connexion"</string>
     <string name="tether_settings_title_all" msgid="8356136101061143841">"Partage de connexion"</string>
-    <string name="managed_user_title" msgid="8109605045406748842">"Toutes applis profession."</string>
+    <string name="managed_user_title" msgid="8109605045406748842">"Toutes les applis professionnelles"</string>
     <string name="user_guest" msgid="8475274842845401871">"Invité"</string>
     <string name="unknown" msgid="1592123443519355854">"Inconnu"</string>
     <string name="running_process_item_user_label" msgid="3129887865552025943">"Utilisateur : <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
@@ -243,7 +243,7 @@
     <string name="private_dns_mode_off" msgid="8236575187318721684">"Désactivé"</string>
     <string name="private_dns_mode_opportunistic" msgid="8314986739896927399">"Automatique"</string>
     <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nom d\'hôte du fournisseur DNS privé"</string>
-    <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Saisissez le nom d\'hôte du fournisseur DNS"</string>
+    <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Indiquez le nom d\'hôte du fournisseur DNS"</string>
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"Impossible de se connecter"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options pour la certification de l\'affichage sans fil"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler les infos Wi-Fi, afficher par RSSI de SSID dans l\'outil de sélection Wi-Fi"</string>
@@ -385,8 +385,8 @@
     <string name="power_discharging_duration_enhanced" msgid="1992003260664804080">"Temps restant en fonction de votre utilisation (<xliff:g id="LEVEL">%2$s</xliff:g>) : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <!-- no translation found for power_remaining_duration_only_short (9183070574408359726) -->
     <skip />
-    <string name="power_discharge_by_enhanced" msgid="2095821536747992464">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g> en fonction de votre utilisation (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
-    <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g> en fonction de votre utilisation"</string>
+    <string name="power_discharge_by_enhanced" msgid="2095821536747992464">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g> selon utilisation (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+    <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g> selon utilisation"</string>
     <string name="power_discharge_by" msgid="6453537733650125582">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
     <string name="power_discharge_by_only" msgid="107616694963545745">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Jusqu\'à <xliff:g id="TIME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 4bd1c78..b998a74 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -402,8 +402,8 @@
     <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7466484148515796216">"É posible que a tableta se apague en breve (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="603933521600231649">"É posible que o dispositivo se apague en breve (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
-    <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tempo que queda ata cargar de todo: <xliff:g id="TIME">%1$s</xliff:g>"</string>
-    <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ata completar a carga"</string>
+    <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Tempo que queda para completar a carga: <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar a carga"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Descoñecido"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Cargando"</string>
     <string name="battery_info_status_charging_lower" msgid="8689770213898117994">"cargando"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index c5176b0..68c0f17 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -220,7 +220,7 @@
     <string name="debug_networking_category" msgid="7044075693643009662">"Reti"</string>
     <string name="wifi_display_certification" msgid="8611569543791307533">"Certificazione display wireless"</string>
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"Attiva logging dettagliato Wi-Fi"</string>
-    <string name="wifi_scan_throttling" msgid="160014287416479843">"Limitazione della ricerca di reti Wi‑Fi"</string>
+    <string name="wifi_scan_throttling" msgid="160014287416479843">"Limita ricerca di reti Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8774857027458200434">"Dati mobili sempre attivi"</string>
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering accelerazione hardware"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostra dispositivi Bluetooth senza nome"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 1e57297..246e3eb 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -221,7 +221,7 @@
     <string name="wifi_display_certification" msgid="8611569543791307533">"Сымсыз дисплей сертификаты"</string>
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi егжей-тегжейлі журналы"</string>
     <string name="wifi_scan_throttling" msgid="160014287416479843">"Wi‑Fi іздеуін шектеу"</string>
-    <string name="mobile_data_always_on" msgid="8774857027458200434">"Мобильдік деректер әрқашан қосулы"</string>
+    <string name="mobile_data_always_on" msgid="8774857027458200434">"Мобильдік интернет әрқашан қосулы"</string>
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Тетеринг режиміндегі аппараттық жеделдету"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Bluetooth құрылғыларын атаусыз көрсету"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Абсолютті дыбыс деңгейін өшіру"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index fb09c2f..36cf2d4 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -402,8 +402,8 @@
     <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7466484148515796216">"ថេប្លេត​អាចនឹង​បិទក្នុង​ពេលបន្តិច​ទៀត (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="603933521600231649">"ឧបករណ៍​អាចនឹង​បិទក្នុង​ពេលបន្តិច​ទៀត (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
-    <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"សល់ <xliff:g id="TIME">%1$s</xliff:g> ទើប​សាកថ្ម​ពេញ"</string>
-    <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> រហូតដល់សាកពេញ"</string>
+    <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបសាកថ្មពេញ"</string>
+    <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើបសាកថ្មពេញ"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"មិន​ស្គាល់"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"កំពុងបញ្ចូល​ថ្ម"</string>
     <string name="battery_info_status_charging_lower" msgid="8689770213898117994">"កំពុង​សាក​ថ្ម"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index abdfa04..8f8bbc1 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -247,7 +247,7 @@
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"연결할 수 없음"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"무선 디스플레이 인증서 옵션 표시"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi 로깅 수준을 높이고, Wi‑Fi 선택도구에서 SSID RSSI당 값을 표시"</string>
-    <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"배터리 소모를 줄이고 네트워크 성능을 개선합니다."</string>
+    <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"배터리 소모를 줄이고 네트워크 성능 개선"</string>
     <string name="wifi_metered_label" msgid="4514924227256839725">"종량제 네트워크"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"무제한 네트워크"</string>
     <string name="select_logd_size_title" msgid="7433137108348553508">"로거 버퍼 크기"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 8bed22f..dda3462 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -262,7 +262,7 @@
     <string name="allow_mock_location_summary" msgid="317615105156345626">"Овозможи лажни локации"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"Овозможете проверка на атрибутот на приказот"</string>
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Секогаш држи го активен мобилниот интернет, дури и при активно Wi-Fi (за брзо префрлување мрежа)."</string>
-    <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Ако е достапно, користете хардверско забрзување за врзување"</string>
+    <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Ако е достапно, користи хардверско забрзување за врзување"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"Овозможи отстранување грешки на USB?"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"Отстранувањето грешки на USB е наменето само за целите на развој. Користете го за копирање податоци меѓу вашиот компјутер и вашиот уред, за инсталирање апликации на вашиот уред без известување и за читање евиденција на податоци."</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"Отповикај пристап кон отстранување грешка од USB од сите претходно овластени компјутери?"</string>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index a364db9..7b46760 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -145,9 +145,9 @@
   </string-array>
   <string-array name="bluetooth_audio_active_device_summaries">
     <item msgid="4862957058729193940"></item>
-    <item msgid="6481691720774549651">", अॅक्टिव्ह"</item>
-    <item msgid="8962366465966010158">", अॅक्टिव्ह (मीडिया)"</item>
-    <item msgid="4046665544396189228">", अॅक्टिव्ह (फोन)"</item>
+    <item msgid="6481691720774549651">", अ‍ॅक्टिव्ह"</item>
+    <item msgid="8962366465966010158">", अ‍ॅक्टिव्ह (मीडिया)"</item>
+    <item msgid="4046665544396189228">", अ‍ॅक्टिव्ह (फोन)"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"बंद"</item>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 367b13d..54723a8 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -34,7 +34,7 @@
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"पासवर्ड तपासा आणि पुन्‍हा प्रयत्‍न करा"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"परिक्षेत्रामध्ये नाही"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"स्वयंचलितपणे कनेक्ट करणार नाही"</string>
-    <string name="wifi_no_internet" msgid="4663834955626848401">"इंटरनेट अॅक्सेस नाही"</string>
+    <string name="wifi_no_internet" msgid="4663834955626848401">"इंटरनेट अ‍ॅक्सेस नाही"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे सेव्ह केले"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s द्वारे स्वयंचलितपणे कनेक्ट केले"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्क रेटिंग प्रदात्याद्वारे स्वयंचलितपणे कनेक्ट केले"</string>
@@ -46,7 +46,7 @@
     <string name="wifi_limited_connection" msgid="7717855024753201527">"मर्यादित कनेक्शन"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"इंटरनेट नाही"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन करणे आवश्यक आहे"</string>
-    <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"अॅक्सेस पॉइंट तात्पुरते भरलेले"</string>
+    <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"अ‍ॅक्सेस पॉइंट तात्पुरते भरलेले"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ने कनेक्‍ट केले"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ने उपलब्‍ध"</string>
     <string name="osu_opening_provider" msgid="5488997661548640424">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> उघडत आहे"</string>
@@ -74,8 +74,8 @@
     <string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"कनेक्ट केले (फोन नाही), बॅटरी <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"कनेक्ट केले (मीडिया नाही), बॅटरी <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"कनेक्ट केले (फोन किंवा मीडिया नाही), बॅटरी <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_active_battery_level" msgid="3149689299296462009">"अॅक्टिव्ह, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी"</string>
-    <string name="bluetooth_active_battery_level_untethered" msgid="6662649951391456747">"अॅक्टिव्ह, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> बॅटरी, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बॅटरी"</string>
+    <string name="bluetooth_active_battery_level" msgid="3149689299296462009">"अ‍ॅक्टिव्ह, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी"</string>
+    <string name="bluetooth_active_battery_level_untethered" msgid="6662649951391456747">"अ‍ॅक्टिव्ह, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> बॅटरी, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बॅटरी"</string>
     <string name="bluetooth_battery_level" msgid="1447164613319663655">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी"</string>
     <string name="bluetooth_battery_level_untethered" msgid="5974406100211667177">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> बॅटरी, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बॅटरी"</string>
     <string name="bluetooth_active_no_battery_level" msgid="8380223546730241956">"अ‍ॅक्टिव्ह"</string>
@@ -83,12 +83,12 @@
     <string name="bluetooth_profile_headset" msgid="7815495680863246034">"फोन कॉल"</string>
     <string name="bluetooth_profile_opp" msgid="9168139293654233697">"फाइल स्थानांतरण"</string>
     <string name="bluetooth_profile_hid" msgid="3680729023366986480">"इनपुट डिव्हाइस"</string>
-    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"इंटरनेट अॅक्सेस"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"इंटरनेट अ‍ॅक्सेस"</string>
     <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"संपर्क शेअरिंग"</string>
     <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"संपर्क सामायिकरणासाठी वापरा"</string>
     <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"इंटरनेट कनेक्शन शेअररण"</string>
     <string name="bluetooth_profile_map" msgid="1019763341565580450">"मजकूर मेसेज"</string>
-    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम अॅक्सेस"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम अ‍ॅक्सेस"</string>
     <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD ऑडिओ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
     <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD ऑडिओ"</string>
     <string name="bluetooth_profile_hearing_aid" msgid="6680721080542444257">"श्रवण यंत्रे"</string>
@@ -102,7 +102,7 @@
     <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"इनपुट डिव्हाइसवर कनेक्ट केले"</string>
     <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"इंटरनेट अॅक्सेससाठी डिव्हाइसशी कनेक्ट केले"</string>
     <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"डिव्हाइससह स्थानिक इंटरनेट कनेक्शन शेअर करत आहे"</string>
-    <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"इंटरनेट अॅक्सेस करण्यासाठी वापरा"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"इंटरनेट अ‍ॅक्सेस करण्यासाठी वापरा"</string>
     <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"नकाशासाठी वापरा"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM प्रवेशासाठी वापरा"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"मीडिया ऑडिओसाठी वापरा"</string>
@@ -113,7 +113,7 @@
     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"पेअर करा"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"पेअर करा"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"रद्द करा"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"कनेक्‍ट केल्यावर पेअरींग तुमचे संपर्क आणि कॉल इतिहास यामध्ये अॅक्सेस देते."</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"कनेक्‍ट केल्यावर पेअरींग तुमचे संपर्क आणि कॉल इतिहास यामध्ये अ‍ॅक्सेस देते."</string>
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी जोडू शकलो नाही."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"अयोग्य पिन किंवा पासकीमुळे <xliff:g id="DEVICE_NAME">%1$s</xliff:g> सह जोडू शकलो नाही."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी संवाद प्रस्थापित करू शकत नाही."</string>
@@ -138,15 +138,15 @@
     <string name="accessibility_wifi_security_type_none" msgid="1223747559986205423">"नेटवर्क उघडा"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="862921720418885331">"सुरक्षित नेटवर्क"</string>
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
-    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"काढलेले अॅप्स"</string>
-    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"काढलेले अॅप्स आणि वापरकर्ते"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"काढलेले अ‍ॅप्स"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"काढलेले अ‍ॅप्स आणि वापरकर्ते"</string>
     <string name="data_usage_ota" msgid="5377889154805560860">"सिस्टम अपडेट"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB टेदरिंग"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"पोर्टेबल हॉटस्पॉट"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ब्लूटूथ टेदरिंग"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"टेदरिंग"</string>
     <string name="tether_settings_title_all" msgid="8356136101061143841">"टेदरिंग आणि पोर्टेबल हॉटस्पॉट"</string>
-    <string name="managed_user_title" msgid="8109605045406748842">"सर्व कार्य अॅप्स"</string>
+    <string name="managed_user_title" msgid="8109605045406748842">"सर्व कार्य अ‍ॅप्स"</string>
     <string name="user_guest" msgid="8475274842845401871">"अतिथी"</string>
     <string name="unknown" msgid="1592123443519355854">"अज्ञात"</string>
     <string name="running_process_item_user_label" msgid="3129887865552025943">"वापरकर्ता: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
@@ -200,7 +200,7 @@
     <string name="development_settings_not_available" msgid="4308569041701535607">"या वापरकर्त्यासाठी डेव्हलपर पर्याय उपलब्ध नाहीत"</string>
     <string name="vpn_settings_not_available" msgid="956841430176985598">"या वापरकर्त्यासाठी VPN सेटिंग्ज उपलब्ध नाहीत"</string>
     <string name="tethering_settings_not_available" msgid="6765770438438291012">"या वापरकर्त्यासाठी टेदरिंग सेटिंग्ज उपलब्ध नाहीत"</string>
-    <string name="apn_settings_not_available" msgid="7873729032165324000">"या वापरकर्त्यासाठी अॅक्सेस बिंदू नाव सेटिंग्ज उपलब्ध नाहीत"</string>
+    <string name="apn_settings_not_available" msgid="7873729032165324000">"या वापरकर्त्यासाठी अ‍ॅक्सेस बिंदू नाव सेटिंग्ज उपलब्ध नाहीत"</string>
     <string name="enable_adb" msgid="7982306934419797485">"USB डीबग करणे"</string>
     <string name="enable_adb_summary" msgid="4881186971746056635">"USB कनेक्ट केलेले असताना डीबग मोड"</string>
     <string name="clear_adb_keys" msgid="4038889221503122743">"USB डीबग करणारी प्रमाणीकरणे रीव्होक करा"</string>
@@ -261,14 +261,14 @@
     <string name="allow_mock_location" msgid="2787962564578664888">"बनावट स्थानांना अनुमती द्या"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"बनावट स्थानांना अनुमती द्या"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"दृश्‍य विशेषता तपासणी सुरू करा"</string>
-    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"जरी वाय-फाय चालू असले तरीही, मोबाईल डेटा नेहमी चालू ठेवा (नेटवर्क जलदरीत्या स्विच करण्यासाठी)."</string>
-    <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"उपलब्ध असल्यास टेदरिंग हार्डवेअर प्रवेग वापरा"</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"वाय-फाय चालू असतानाही मोबाइल डेटा नेहमी सुरू ठेवा (नेटवर्क जलदरीत्या स्विच करण्यासाठी)."</string>
+    <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"उपलब्ध असल्यास टेदरिंग हार्डवेअर अॅक्सिलरेशन वापरा"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"USB डीबग करण्यास अनुमती द्यायची?"</string>
-    <string name="adb_warning_message" msgid="7316799925425402244">"USB डीबग करण्याचा हेतू फक्त विकास उद्देशांसाठी आहे. याचा वापर तुमचा कॉंप्युटर आणि तुमचे डिव्हाइस यांच्या दरम्यान डेटा कॉपी करण्यासाठी करा, सूचनेशिवाय तुमच्या डिव्हाइस वर अॅप्स इंस्टॉल करा आणि लॉग डेटा वाचा."</string>
-    <string name="adb_keys_warning_message" msgid="5659849457135841625">"तुम्ही पूर्वी अॉथोराइझ केलेल्या सर्व संगणकांवरुन USB डीबग करण्यासाठी अॅक्सेस रीव्होक करायचा?"</string>
+    <string name="adb_warning_message" msgid="7316799925425402244">"USB डीबग करण्याचा हेतू फक्त विकास उद्देशांसाठी आहे. याचा वापर तुमचा कॉंप्युटर आणि तुमचे डिव्हाइस यांच्या दरम्यान डेटा कॉपी करण्यासाठी करा, सूचनेशिवाय तुमच्या डिव्हाइस वर अ‍ॅप्स इंस्टॉल करा आणि लॉग डेटा वाचा."</string>
+    <string name="adb_keys_warning_message" msgid="5659849457135841625">"तुम्ही पूर्वी अॉथोराइझ केलेल्या सर्व संगणकांवरुन USB डीबग करण्यासाठी अ‍ॅक्सेस रीव्होक करायचा?"</string>
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"विकास सेटिंग्जला अनुमती द्यायची?"</string>
     <string name="dev_settings_warning_message" msgid="2298337781139097964">"या सेटिंग्जचा हेतू फक्त विकास वापरासाठी आहे. त्यामुळे तुमचे डिव्हाइस आणि त्यावरील अॅप्लिकेशन ब्रेक होऊ शकतात किंवा नेहमीपेक्षा वेगळे वर्तन करू शकतात."</string>
-    <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB वर अॅप्स पडताळून पाहा"</string>
+    <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB वर अ‍ॅप्स पडताळून पाहा"</string>
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानिकारक वर्तनासाठी ADB/ADT द्वारे इंस्टॉल अ‍ॅप्स तपासा."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="2351196058115755520">"नावांशिवाय ब्‍लूटूथ डीव्‍हाइस (फक्‍त MAC पत्‍ते) दाखवले जातील"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"रिमोट डिव्हाइसमध्ये सहन न होणारा मोठा आवाज किंवा नियंत्रणाचा अभाव यासारखी आवाजाची समस्या असल्यास ब्लूटूथ संपूर्ण आवाज वैशिष्ट्य बंद करते."</string>
@@ -290,7 +290,7 @@
     <string name="media_category" msgid="4388305075496848353">"मीडिया"</string>
     <string name="debug_monitoring_category" msgid="7640508148375798343">"परीक्षण"</string>
     <string name="strict_mode" msgid="1938795874357830695">"कठोर मोड सुरू"</string>
-    <string name="strict_mode_summary" msgid="142834318897332338">"मुख्य थ्रेडवर अॅप्स मोठी कार्ये करतात तेव्हा स्क्रीन फ्लॅश करा"</string>
+    <string name="strict_mode_summary" msgid="142834318897332338">"मुख्य थ्रेडवर अ‍ॅप्स मोठी कार्ये करतात तेव्हा स्क्रीन फ्लॅश करा"</string>
     <string name="pointer_location" msgid="6084434787496938001">"पॉइंटर स्थान"</string>
     <string name="pointer_location_summary" msgid="840819275172753713">"वर्तमान स्पर्श डेटा दर्शविणारे स्क्रीन ओव्हरले"</string>
     <string name="show_touches" msgid="2642976305235070316">"टॅप दाखवा"</string>
@@ -322,7 +322,7 @@
     <string name="transition_animation_scale_title" msgid="387527540523595875">"ट्रांझिशन अॅनिमेशन स्केल"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"अॅनिमेटर कालावधी स्केल"</string>
     <string name="overlay_display_devices_title" msgid="5364176287998398539">"दुय्यम डिस्प्ले सिम्युलेट करा"</string>
-    <string name="debug_applications_category" msgid="4206913653849771549">"अॅप्स"</string>
+    <string name="debug_applications_category" msgid="4206913653849771549">"अ‍ॅप्स"</string>
     <string name="immediately_destroy_activities" msgid="1579659389568133959">"अॅक्टिव्हिटी ठेवू नका"</string>
     <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"वापरकर्त्याने प्रत्येक अॅक्टिव्हिटी सोडताच ती नष्ट करा"</string>
     <string name="app_process_limit_title" msgid="4280600650253107163">"पार्श्वभूमी प्रक्रिया मर्यादा"</string>
@@ -353,7 +353,7 @@
     <item msgid="8280754435979370728">"डोळ्यांनी पाहिले तसे नैसर्गिक रंग"</item>
     <item msgid="5363960654009010371">"डिजिटल सामग्रीसाठी ऑप्टिमाइझ केलेले रंग"</item>
   </string-array>
-    <string name="inactive_apps_title" msgid="9042996804461901648">"स्टँडबाय अॅप्स"</string>
+    <string name="inactive_apps_title" msgid="9042996804461901648">"स्टँडबाय अ‍ॅप्स"</string>
     <string name="inactive_app_inactive_summary" msgid="5091363706699855725">"निष्क्रिय. टॉगल करण्यासाठी टॅप करा."</string>
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"सक्रिय. टॉगल करण्यासाठी टॅप करा."</string>
     <string name="standby_bucket_summary" msgid="6567835350910684727">"अ‍ॅप स्टँडबाय स्थिती: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 648cc4a..5725c22 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -247,7 +247,7 @@
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"କନେକ୍ଟ କରିହେଲା ନାହିଁ"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ୱେୟାରଲେସ୍‌ ଡିସ୍‌ପ୍ଲେ ସାର୍ଟିଫିକେସନ୍ ପାଇଁ ବିକଳ୍ପ ଦେଖାନ୍ତୁ"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ୱାଇ-ଫାଇ ଲଗିଙ୍ଗ ସ୍ତର ବଢ଼ାନ୍ତୁ, ୱାଇ-ଫାଇ ପିକର୍‌ରେ ପ୍ରତି SSID RSSI ଦେଖାନ୍ତୁ"</string>
-    <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କମ୍ ଏବଂ ନେଟ୍‌ୱାର୍କ ପ୍ରଦର୍ଶନ ଉନ୍ନତ କରିଥାଏ"</string>
+    <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କମ୍ ଏବଂ ନେଟ୍‌ୱାର୍କ କାର୍ଯ୍ୟକ୍ଷମତା ଉନ୍ନତ କରିଥାଏ"</string>
     <string name="wifi_metered_label" msgid="4514924227256839725">"ମପାଯାଉଥିବା"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"ମପାଯାଉନଥିବା"</string>
     <string name="select_logd_size_title" msgid="7433137108348553508">"ଲଗର୍‌ ବଫର୍‌ ସାଇଜ୍"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 7967c71..faccda7 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -403,7 +403,7 @@
     <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="603933521600231649">"ਡੀਵਾਈਸ ਛੇਤੀ ਹੀ ਬੰਦ ਹੋ ਸਕਦਾ ਹੈ (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"ਪੂਰੀ ਤਰ੍ਹਾਂ ਚਾਰਜ ਹੋਣ ਲਈ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
-    <string name="power_charging_duration" msgid="4676999980973411875">"ਪੂਰੀ ਤਰ੍ਹਾਂ ਚਾਰਜ ਹੋਣ ਤੱਕ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਪੂਰੀ ਤਰ੍ਹਾਂ ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"ਅਗਿਆਤ"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="battery_info_status_charging_lower" msgid="8689770213898117994">"ਚਾਰਜ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 0401e7f..806be6e 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -220,7 +220,7 @@
     <string name="debug_networking_category" msgid="7044075693643009662">"Сети"</string>
     <string name="wifi_display_certification" msgid="8611569543791307533">"Серт. беспроводн. мониторов"</string>
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"Подробный журнал Wi‑Fi"</string>
-    <string name="wifi_scan_throttling" msgid="160014287416479843">"Регулирование поиска сетей Wi‑Fi"</string>
+    <string name="wifi_scan_throttling" msgid="160014287416479843">"Ограничивать поиск сетей Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8774857027458200434">"Не отключать мобильный Интернет"</string>
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"Аппаратное ускорение в режиме модема"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Показывать Bluetooth-устройства без названий"</string>
@@ -247,7 +247,7 @@
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"Ошибка подключения"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показывать параметры сертификации беспроводных мониторов"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Вести подробный журнал, показывать RSSI для каждого SSID при выборе сети"</string>
-    <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"Уменьшает расход заряда батареи и улучшает работу сетей."</string>
+    <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"Уменьшает расход заряда батареи и улучшает работу сети"</string>
     <string name="wifi_metered_label" msgid="4514924227256839725">"Сеть с тарификацией трафика"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"Сеть без тарификации трафика"</string>
     <string name="select_logd_size_title" msgid="7433137108348553508">"Размер буфера журнала"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 213b285..b16d5d9 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -246,7 +246,7 @@
     <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Vnesite ime gostitelja pri ponudniku DNS"</string>
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"Povezave ni bilo mogoče vzpostaviti"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string>
-    <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povečaj raven zapis. dnev. za Wi-Fi; v izbir. Wi‑Fi-ja pokaži glede na SSID RSSI"</string>
+    <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povečaj raven zapisovanja dnevnika za Wi-Fi; v izbirniku Wi‑Fi-ja pokaži glede na SSID RSSI"</string>
     <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"Zmanjša porabo energije akumulatorja in izboljša delovanje omrežja"</string>
     <string name="wifi_metered_label" msgid="4514924227256839725">"Omejen prenos podatkov"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"Z neomejenim prenosom podatkov"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 910b94e..0b184d2 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -247,7 +247,7 @@
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"เชื่อมต่อไม่ได้"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"แสดงตัวเลือกสำหรับการรับรองการแสดงผล แบบไร้สาย"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
-    <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"ลดการหมดเปลืองแบตเตอรี่และเพิ่มประสิทธิภาพเครือข่าย"</string>
+    <string name="wifi_scan_throttling_summary" msgid="4461922728822495763">"ลดการเปลืองแบตเตอรี่และเพิ่มประสิทธิภาพเครือข่าย"</string>
     <string name="wifi_metered_label" msgid="4514924227256839725">"มีการวัดปริมาณอินเทอร์เน็ต"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"ไม่มีการวัดปริมาณอินเทอร์เน็ต"</string>
     <string name="select_logd_size_title" msgid="7433137108348553508">"ขนาดบัฟเฟอร์ของตัวบันทึก"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3fe2492..8199ea3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -885,10 +885,10 @@
     <string name="quick_settings_night_secondary_label_on_at">On at <xliff:g id="time" example="10 pm">%s</xliff:g></string>
     <!-- QuickSettings: Secondary text for when the Night Light or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->
     <string name="quick_settings_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string>
-    <!-- QuickSettings: Label for the toggle to activate Dark theme (A.K.A Dark Mode). [CHAR LIMIT=20] -->
-    <string name="quick_settings_ui_mode_night_label">Dark Theme</string>
-    <!-- QuickSettings: Label for the Dark theme tile when enabled by battery saver. [CHAR LIMIT=40] -->
-    <string name="quick_settings_ui_mode_night_label_battery_saver">Dark Theme\nBattery saver</string>
+    <!-- QuickSettings: Label for the toggle to activate dark theme (A.K.A Dark Mode). [CHAR LIMIT=20] -->
+    <string name="quick_settings_ui_mode_night_label">Dark theme</string>
+    <!-- QuickSettings: Label for the dark theme tile when enabled by battery saver. [CHAR LIMIT=40] -->
+    <string name="quick_settings_ui_mode_night_label_battery_saver">Dark theme\nBattery saver</string>
 
     <!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
     <string name="quick_settings_nfc_label">NFC</string>
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
index 178f4c3..8ef7b6c 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
@@ -92,15 +92,14 @@
         mPaint.setStrokeJoin(Paint.Join.MITER);
         mPaint.setAntiAlias(true);
 
-        int cornerRadiusBottom = DisplayUtils.getCornerRadiusBottom(context);
-        int cornerRadiusTop = DisplayUtils.getCornerRadiusTop(context);
+
         int displayWidth = DisplayUtils.getWidth(context);
         int displayHeight = DisplayUtils.getHeight(context);
-        CircularCornerPathRenderer cornerPathRenderer = new CircularCornerPathRenderer(
-                cornerRadiusBottom, cornerRadiusTop, displayWidth, displayHeight);
-        mGuide = new PerimeterPathGuide(context, cornerPathRenderer,
+        mGuide = new PerimeterPathGuide(context, createCornerPathRenderer(context),
                 mStrokeWidth / 2, displayWidth, displayHeight);
 
+        int cornerRadiusBottom = DisplayUtils.getCornerRadiusBottom(context);
+        int cornerRadiusTop = DisplayUtils.getCornerRadiusTop(context);
         mViewHeight = Math.max(cornerRadiusBottom, cornerRadiusTop);
 
         final int dualToneDarkTheme = Utils.getThemeAttr(mContext, R.attr.darkIconTheme);
@@ -243,6 +242,19 @@
     }
 
     /**
+     * Returns CornerPathRenderer to be used for rendering invocation lights.
+     *
+     * To render corners that aren't circular, override this method in a subclass.
+     */
+    protected CornerPathRenderer createCornerPathRenderer(Context context) {
+        int displayWidth = DisplayUtils.getWidth(context);
+        int displayHeight = DisplayUtils.getHeight(context);
+        int cornerRadiusBottom = DisplayUtils.getCornerRadiusBottom(context);
+        int cornerRadiusTop = DisplayUtils.getCornerRadiusTop(context);
+        return new CircularCornerPathRenderer(
+                cornerRadiusBottom, cornerRadiusTop, displayWidth, displayHeight);
+    }
+    /**
      * Receives an intensity from 0 (lightest) to 1 (darkest) and sets the handle color
      * appropriately. Intention is to match the home handle color.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 1521889..3cc8ec9a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -96,7 +96,7 @@
             mInternalFalsingManager = new FalsingManagerImpl(context);
         } else {
             mInternalFalsingManager = new BrightLineFalsingManager(
-                    new FalsingDataProvider(context),
+                    new FalsingDataProvider(context.getResources().getDisplayMetrics()),
                     Dependency.get(AsyncSensorManager.class)
             );
         }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java
index 4975e63..8b11ceb 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingDataProvider.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.classifier.brightline;
 
-import android.content.Context;
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
@@ -51,8 +50,7 @@
     private MotionEvent mFirstRecentMotionEvent;
     private MotionEvent mLastMotionEvent;
 
-    public FalsingDataProvider(Context context) {
-        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+    public FalsingDataProvider(DisplayMetrics displayMetrics) {
         mXdpi = displayMetrics.xdpi;
         mYdpi = displayMetrics.ydpi;
         mWidthPixels = displayMetrics.widthPixels;
@@ -145,12 +143,20 @@
 
     boolean isHorizontal() {
         recalculateData();
+        if (mRecentMotionEvents.isEmpty()) {
+            return false;
+        }
+
         return Math.abs(mFirstRecentMotionEvent.getX() - mLastMotionEvent.getX()) > Math
                 .abs(mFirstRecentMotionEvent.getY() - mLastMotionEvent.getY());
     }
 
     boolean isRight() {
         recalculateData();
+        if (mRecentMotionEvents.isEmpty()) {
+            return false;
+        }
+
         return mLastMotionEvent.getX() > mFirstRecentMotionEvent.getX();
     }
 
@@ -160,6 +166,10 @@
 
     boolean isUp() {
         recalculateData();
+        if (mRecentMotionEvents.isEmpty()) {
+            return false;
+        }
+
         return mLastMotionEvent.getY() < mFirstRecentMotionEvent.getY();
     }
 
@@ -168,8 +178,13 @@
             return;
         }
 
-        mFirstRecentMotionEvent = mRecentMotionEvents.get(0);
-        mLastMotionEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
+        if (mRecentMotionEvents.isEmpty()) {
+            mFirstRecentMotionEvent = null;
+            mLastMotionEvent = null;
+        } else {
+            mFirstRecentMotionEvent = mRecentMotionEvents.get(0);
+            mLastMotionEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
+        }
 
         calculateAngleInternal();
 
@@ -245,5 +260,7 @@
         }
 
         mRecentMotionEvents.clear();
+
+        mDirty = true;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index d4c7366..2047797 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -104,15 +104,19 @@
     private final AlarmManager.OnAlarmListener mUpdateNextAlarm = this::updateNextAlarm;
     private final HashSet<Integer> mMediaInvisibleStates;
     private final Object mMediaToken = new Object();
-    private SettableWakeLock mMediaWakeLock;
-    private ZenModeController mZenModeController;
+    @VisibleForTesting
+    protected SettableWakeLock mMediaWakeLock;
+    @VisibleForTesting
+    protected ZenModeController mZenModeController;
     private String mDatePattern;
     private DateFormat mDateFormat;
     private String mLastText;
     private boolean mRegistered;
     private String mNextAlarm;
     private NextAlarmController mNextAlarmController;
+    @VisibleForTesting
     protected AlarmManager mAlarmManager;
+    @VisibleForTesting
     protected ContentResolver mContentResolver;
     private AlarmManager.AlarmClockInfo mNextAlarmInfo;
     private PendingIntent mPendingIntent;
@@ -297,22 +301,44 @@
 
     @Override
     public boolean onCreateSliceProvider() {
-        mAlarmManager = getContext().getSystemService(AlarmManager.class);
-        mContentResolver = getContext().getContentResolver();
-        mNextAlarmController = new NextAlarmControllerImpl(getContext());
-        mNextAlarmController.addCallback(this);
-        mZenModeController = new ZenModeControllerImpl(getContext(), mHandler);
-        mZenModeController.addCallback(this);
-        mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
-        mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
-        mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"),
-                "media");
-        KeyguardSliceProvider.sInstance = this;
-        registerClockUpdate();
-        updateClockLocked();
+        synchronized (this) {
+            KeyguardSliceProvider oldInstance = KeyguardSliceProvider.sInstance;
+            if (oldInstance != null) {
+                oldInstance.onDestroy();
+            }
+
+            mAlarmManager = getContext().getSystemService(AlarmManager.class);
+            mContentResolver = getContext().getContentResolver();
+            mNextAlarmController = new NextAlarmControllerImpl(getContext());
+            mNextAlarmController.addCallback(this);
+            mZenModeController = new ZenModeControllerImpl(getContext(), mHandler);
+            mZenModeController.addCallback(this);
+            mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
+            mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
+            mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"),
+                    "media");
+            KeyguardSliceProvider.sInstance = this;
+            registerClockUpdate();
+            updateClockLocked();
+        }
         return true;
     }
 
+    @VisibleForTesting
+    protected void onDestroy() {
+        synchronized (this) {
+            mNextAlarmController.removeCallback(this);
+            mZenModeController.removeCallback(this);
+            mMediaWakeLock.setAcquired(false);
+            mAlarmManager.cancel(mUpdateNextAlarm);
+            if (mRegistered) {
+                mRegistered = false;
+                getKeyguardUpdateMonitor().removeCallback(mKeyguardUpdateMonitorCallback);
+                getContext().unregisterReceiver(mIntentReceiver);
+            }
+        }
+    }
+
     @Override
     public void onZenChanged(int zen) {
         notifyChange();
@@ -350,7 +376,8 @@
      * Registers a broadcast receiver for clock updates, include date, time zone and manually
      * changing the date/time via the settings app.
      */
-    private void registerClockUpdate() {
+    @VisibleForTesting
+    protected void registerClockUpdate() {
         synchronized (this) {
             if (mRegistered) {
                 return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 8dd324b..4dfc343 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -23,7 +23,6 @@
 import android.graphics.Rect;
 import android.os.Handler;
 import android.service.notification.StatusBarNotification;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 
@@ -313,8 +312,6 @@
     public void setTranslation(View v, float translate) {
         if (v instanceof ExpandableNotificationRow) {
             ((ExpandableNotificationRow) v).setTranslation(translate);
-        } else {
-            Log.wtf(TAG, "setTranslation should only be called on an ExpandableNotificationRow.");
         }
     }
 
@@ -324,7 +321,6 @@
             return ((ExpandableNotificationRow) v).getTranslation();
         }
         else {
-            Log.wtf(TAG, "getTranslation should only be called on an ExpandableNotificationRow.");
             return 0f;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 7332b03..a6f4ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -61,6 +61,7 @@
     public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
     public static final int ANIMATION_DELAY_HEADS_UP = 120;
     public static final int ANIMATION_DELAY_HEADS_UP_CLICKED= 120;
+    private static final int MAX_STAGGER_COUNT = 5;
 
     private final int mGoToFullShadeAppearingTranslation;
     private final int mPulsingAppearingTranslation;
@@ -78,8 +79,6 @@
     private long mCurrentLength;
     private long mCurrentAdditionalDelay;
 
-    /** The current index for the last child which was not added in this event set. */
-    private int mCurrentLastNotAddedIndex;
     private ValueAnimator mTopOverScrollAnimator;
     private ValueAnimator mBottomOverScrollAnimator;
     private int mHeadsUpAppearHeightBottom;
@@ -137,7 +136,8 @@
         mAnimationFilter.applyCombination(mNewEvents);
         mCurrentAdditionalDelay = additionalDelay;
         mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents);
-        mCurrentLastNotAddedIndex = findLastNotAddedIndex();
+        // Used to stagger concurrent animations' delays and durations for visual effect
+        int animationStaggerCount = 0;
         for (int i = 0; i < childCount; i++) {
             final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
 
@@ -147,7 +147,10 @@
                 continue;
             }
 
-            initAnimationProperties(child, viewState);
+            if (mAnimationProperties.wasAdded(child) && animationStaggerCount < MAX_STAGGER_COUNT) {
+                animationStaggerCount++;
+            }
+            initAnimationProperties(child, viewState, animationStaggerCount);
             viewState.animateTo(child, mAnimationProperties);
         }
         if (!isRunning()) {
@@ -161,10 +164,10 @@
     }
 
     private void initAnimationProperties(ExpandableView child,
-            ExpandableViewState viewState) {
+            ExpandableViewState viewState, int animationStaggerCount) {
         boolean wasAdded = mAnimationProperties.wasAdded(child);
         mAnimationProperties.duration = mCurrentLength;
-        adaptDurationWhenGoingToFullShade(child, viewState, wasAdded);
+        adaptDurationWhenGoingToFullShade(child, viewState, wasAdded, animationStaggerCount);
         mAnimationProperties.delay = 0;
         if (wasAdded || mAnimationFilter.hasDelays
                         && (viewState.yTranslation != child.getTranslationY()
@@ -174,16 +177,15 @@
                         || viewState.clipTopAmount != child.getClipTopAmount()
                         || viewState.dark != child.isDark())) {
             mAnimationProperties.delay = mCurrentAdditionalDelay
-                    + calculateChildAnimationDelay(viewState);
+                    + calculateChildAnimationDelay(viewState, animationStaggerCount);
         }
     }
 
     private void adaptDurationWhenGoingToFullShade(ExpandableView child,
-            ExpandableViewState viewState, boolean wasAdded) {
+            ExpandableViewState viewState, boolean wasAdded, int animationStaggerCount) {
         if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
             child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
-            float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
-            longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
+            float longerDurationFactor = (float) Math.pow(animationStaggerCount, 0.7f);
             mAnimationProperties.duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
                     (long) (100 * longerDurationFactor);
         }
@@ -214,25 +216,10 @@
         return true;
     }
 
-    private int findLastNotAddedIndex() {
-        int childCount = mHostLayout.getChildCount();
-        for (int i = childCount - 1; i >= 0; i--) {
-            final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
-
-            ExpandableViewState viewState = child.getViewState();
-            if (viewState == null || child.getVisibility() == View.GONE) {
-                continue;
-            }
-            if (!mNewAddChildren.contains(child)) {
-                return viewState.notGoneIndex;
-            }
-        }
-        return -1;
-    }
-
-    private long calculateChildAnimationDelay(ExpandableViewState viewState) {
+    private long calculateChildAnimationDelay(ExpandableViewState viewState,
+            int animationStaggerCount) {
         if (mAnimationFilter.hasGoToFullShadeEvent) {
-            return calculateDelayGoToFullShade(viewState);
+            return calculateDelayGoToFullShade(viewState, animationStaggerCount);
         }
         if (mAnimationFilter.customDelay != AnimationFilter.NO_DELAY) {
             return mAnimationFilter.customDelay;
@@ -286,13 +273,13 @@
         return minDelay;
     }
 
-    private long calculateDelayGoToFullShade(ExpandableViewState viewState) {
+    private long calculateDelayGoToFullShade(ExpandableViewState viewState,
+            int animationStaggerCount) {
         int shelfIndex = mShelf.getNotGoneIndex();
         float index = viewState.notGoneIndex;
         long result = 0;
         if (index > shelfIndex) {
-            float diff = index - shelfIndex;
-            diff = (float) Math.pow(diff, 0.7f);
+            float diff = (float) Math.pow(animationStaggerCount, 0.7f);
             result += (long) (diff * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE * 0.25);
             index = shelfIndex;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index cc0bc5f..f9cdde8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -66,6 +66,7 @@
 public class EdgeBackGestureHandler implements DisplayListener {
 
     private static final String TAG = "EdgeBackGestureHandler";
+    private static final int MAX_LONG_PRESS_TIMEOUT = 250;
 
     private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() {
         @Override
@@ -168,7 +169,8 @@
         // before the app starts to react to it.
         // TODO(b/130352502) Tune this value and extract into a constant
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 0.75f;
-        mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
+        mLongPressTimeout = Math.min(MAX_LONG_PRESS_TIMEOUT,
+                ViewConfiguration.getLongPressTimeout());
 
         mNavBarHeight = res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
         mMinArrowPosition = res.getDimensionPixelSize(R.dimen.navigation_edge_arrow_min_y);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index 1124220..4d7cf27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -33,6 +33,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.om.IOverlayManager;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.ApkAssets;
 import android.os.PatternMatcher;
@@ -69,6 +70,8 @@
     private static final String TAG = NavigationModeController.class.getSimpleName();
     private static final boolean DEBUG = false;
 
+    private static final int SYSTEM_APP_MASK =
+            ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
     static final String SHARED_PREFERENCES_NAME = "navigation_mode_controller_preferences";
     static final String PREFS_SWITCHED_FROM_GESTURE_NAV_KEY = "switched_from_gesture_nav";
 
@@ -315,6 +318,10 @@
             return;
         }
 
+        Log.d(TAG, "Switching system navigation to 3-button mode:"
+                + " defaultLauncher=" + getDefaultLauncherPackageName(mCurrentUserContext)
+                + " contextUser=" + mCurrentUserContext.getUserId());
+
         setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT);
         showNotification(mCurrentUserContext, R.string.notification_content_system_nav_changed);
         mCurrentUserContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
@@ -355,9 +362,10 @@
         if (defaultLauncherPackageName == null) {
             return null;
         }
-        ComponentName recentsComponentName = ComponentName.unflattenFromString(
-                context.getString(com.android.internal.R.string.config_recentsComponentName));
-        return recentsComponentName.getPackageName().equals(defaultLauncherPackageName);
+        if (isSystemApp(context, defaultLauncherPackageName)) {
+            return true;
+        }
+        return false;
     }
 
     private String getDefaultLauncherPackageName(Context context) {
@@ -368,6 +376,17 @@
         return cn.getPackageName();
     }
 
+    /** Returns true if the app for the given package name is a system app for this device */
+    private boolean isSystemApp(Context context, String packageName) {
+        try {
+            ApplicationInfo ai = context.getPackageManager().getApplicationInfo(packageName,
+                    PackageManager.GET_META_DATA);
+            return ai != null && ((ai.flags & SYSTEM_APP_MASK) != 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
     private void showNotification(Context context, int resId) {
         final CharSequence message = context.getResources().getString(resId);
         if (DEBUG) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java
new file mode 100644
index 0000000..d011e48
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ClassifierTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier.brightline;
+
+import android.util.DisplayMetrics;
+import android.view.MotionEvent;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClassifierTest extends SysuiTestCase {
+
+    private FalsingDataProvider mDataProvider;
+    private List<MotionEvent> mMotionEvents = new ArrayList<>();
+    private float mOffsetX = 0;
+    private float mOffsetY = 0;
+
+    @Before
+    public void setup() {
+        DisplayMetrics displayMetrics = new DisplayMetrics();
+        displayMetrics.xdpi = 100;
+        displayMetrics.ydpi = 100;
+        displayMetrics.widthPixels = 1000;
+        displayMetrics.heightPixels = 1000;
+        mDataProvider = new FalsingDataProvider(displayMetrics);
+    }
+
+    @After
+    public void tearDown() {
+        resetDataProvider();
+    }
+
+    FalsingDataProvider getDataProvider() {
+        return mDataProvider;
+    }
+
+    void setOffsetX(float offsetX) {
+        mOffsetX = offsetX;
+    }
+
+    void setOffsetY(float offsetY) {
+        mOffsetY = offsetY;
+    }
+
+    void resetDataProvider() {
+        for (MotionEvent motionEvent : mMotionEvents) {
+            motionEvent.recycle();
+        }
+
+        mMotionEvents.clear();
+
+        mDataProvider.onSessionEnd();
+    }
+
+    MotionEvent appendDownEvent(float x, float y) {
+        return appendMotionEvent(MotionEvent.ACTION_DOWN, x, y);
+    }
+
+    MotionEvent appendDownEvent(float x, float y, long eventTime) {
+        return appendMotionEvent(MotionEvent.ACTION_DOWN, x, y, eventTime);
+    }
+
+    MotionEvent appendMoveEvent(float x, float y) {
+        return appendMotionEvent(MotionEvent.ACTION_MOVE, x, y);
+    }
+
+    MotionEvent appendMoveEvent(float x, float y, long eventTime) {
+        return appendMotionEvent(MotionEvent.ACTION_MOVE, x, y, eventTime);
+    }
+
+
+    MotionEvent appendUpEvent(float x, float y) {
+        return appendMotionEvent(MotionEvent.ACTION_UP, x, y);
+    }
+
+    MotionEvent appendUpEvent(float x, float y, long eventTime) {
+        return appendMotionEvent(MotionEvent.ACTION_UP, x, y, eventTime);
+    }
+
+    private MotionEvent appendMotionEvent(int actionType, float x, float y) {
+
+        long eventTime = mMotionEvents.isEmpty() ? 1 : mMotionEvents.get(
+                mMotionEvents.size() - 1).getEventTime() + 1;
+        return appendMotionEvent(actionType, x, y, eventTime);
+    }
+
+    private MotionEvent appendMotionEvent(int actionType, float x, float y, long eventTime) {
+        x += mOffsetX;
+        y += mOffsetY;
+
+        MotionEvent motionEvent = MotionEvent.obtain(1, eventTime, actionType, x, y,
+                0);
+        mMotionEvents.add(motionEvent);
+
+        mDataProvider.onMotionEvent(motionEvent);
+
+        return motionEvent;
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
index ade5f36..b45d3f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
@@ -28,8 +28,7 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.SysuiTestCase;
-
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -39,7 +38,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class DiagonalClassifierTest extends SysuiTestCase {
+public class DiagonalClassifierTest extends ClassifierTest {
 
     // Next variable is not actually five, but is very close. 5 degrees is currently the value
     // used in the diagonal classifier, so we want slightly less than that to deal with
@@ -57,10 +56,16 @@
 
     @Before
     public void setup() {
+        super.setup();
         MockitoAnnotations.initMocks(this);
         mClassifier = new DiagonalClassifier(mDataProvider);
     }
 
+    @After
+    public void tearDown() {
+        super.tearDown();
+    }
+
     @Test
     public void testPass_UnknownAngle() {
         when(mDataProvider.getAngle()).thenReturn(Float.MAX_VALUE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
index 3d0471b..805bb91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
@@ -18,48 +18,37 @@
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.view.MotionEvent;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.SysuiTestCase;
-
+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 java.util.ArrayList;
-import java.util.List;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class DistanceClassifierTest extends SysuiTestCase {
+public class DistanceClassifierTest extends ClassifierTest {
 
-    @Mock
     private FalsingDataProvider mDataProvider;
     private FalsingClassifier mClassifier;
-    private List<MotionEvent> mMotionEvents = new ArrayList<>();
-
-    private static final float DPI = 100;
-    private static final int SCREEN_SIZE = (int) (DPI * 10);
 
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
-        when(mDataProvider.getHeightPixels()).thenReturn(SCREEN_SIZE);
-        when(mDataProvider.getWidthPixels()).thenReturn(SCREEN_SIZE);
-        when(mDataProvider.getXdpi()).thenReturn(DPI);
-        when(mDataProvider.getYdpi()).thenReturn(DPI);
+        super.setup();
+        mDataProvider = getDataProvider();
         mClassifier = new DistanceClassifier(mDataProvider);
     }
 
+    @After
+    public void tearDown() {
+        super.tearDown();
+    }
+
     @Test
     public void testPass_noPointer() {
         assertThat(mClassifier.isFalseTouch(), is(true));
@@ -67,104 +56,54 @@
 
     @Test
     public void testPass_fling() {
-        MotionEvent motionEventA = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 1, 1, 0);
-        MotionEvent motionEventB = MotionEvent.obtain(1, 2, MotionEvent.ACTION_MOVE, 1, 2, 0);
-        MotionEvent motionEventC = MotionEvent.obtain(1, 3, MotionEvent.ACTION_UP, 1, 40, 0);
 
-        appendMotionEvent(motionEventA);
+        mClassifier.onTouchEvent(appendDownEvent(1, 1));
         assertThat(mClassifier.isFalseTouch(), is(true));
 
-        appendMotionEvent(motionEventB);
+        mClassifier.onTouchEvent(appendMoveEvent(1, 2));
         assertThat(mClassifier.isFalseTouch(), is(true));
 
-        appendMotionEvent(motionEventC);
+        mClassifier.onTouchEvent(appendUpEvent(1, 40));
         assertThat(mClassifier.isFalseTouch(), is(false));
-
-        motionEventA.recycle();
-        motionEventB.recycle();
-        motionEventC.recycle();
     }
 
     @Test
     public void testFail_flingShort() {
-        MotionEvent motionEventA = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 1, 1, 0);
-        MotionEvent motionEventB = MotionEvent.obtain(1, 2, MotionEvent.ACTION_MOVE, 1, 2, 0);
-        MotionEvent motionEventC = MotionEvent.obtain(1, 3, MotionEvent.ACTION_UP, 1, 10, 0);
-
-        appendMotionEvent(motionEventA);
+        mClassifier.onTouchEvent(appendDownEvent(1, 1));
         assertThat(mClassifier.isFalseTouch(), is(true));
 
-        appendMotionEvent(motionEventB);
+        mClassifier.onTouchEvent(appendMoveEvent(1, 2));
         assertThat(mClassifier.isFalseTouch(), is(true));
 
-        appendMotionEvent(motionEventC);
+        mClassifier.onTouchEvent(appendUpEvent(1, 10));
         assertThat(mClassifier.isFalseTouch(), is(true));
-
-        motionEventA.recycle();
-        motionEventB.recycle();
-        motionEventC.recycle();
     }
 
     @Test
     public void testFail_flingSlowly() {
         // These events, in testing, result in a fling that falls just short of the threshold.
-        MotionEvent motionEventA = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 1, 1, 0);
-        MotionEvent motionEventB = MotionEvent.obtain(1, 2, MotionEvent.ACTION_MOVE, 1, 15, 0);
-        MotionEvent motionEventC = MotionEvent.obtain(1, 3, MotionEvent.ACTION_MOVE, 1, 16, 0);
-        MotionEvent motionEventD = MotionEvent.obtain(1, 300, MotionEvent.ACTION_MOVE, 1, 17, 0);
-        MotionEvent motionEventE = MotionEvent.obtain(1, 301, MotionEvent.ACTION_MOVE, 1, 18, 0);
-        MotionEvent motionEventF = MotionEvent.obtain(1, 500, MotionEvent.ACTION_UP, 1, 19, 0);
 
-        appendMotionEvent(motionEventA);
+        mClassifier.onTouchEvent(appendDownEvent(1, 1, 1));
         assertThat(mClassifier.isFalseTouch(), is(true));
 
-        appendMotionEvent(motionEventB);
+        mClassifier.onTouchEvent(appendMoveEvent(1, 15, 2));
         assertThat(mClassifier.isFalseTouch(), is(true));
 
-        appendMotionEvent(motionEventC);
-        appendMotionEvent(motionEventD);
-        appendMotionEvent(motionEventE);
-        appendMotionEvent(motionEventF);
+        mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3));
+        mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300));
+        mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301));
+        mClassifier.onTouchEvent(appendUpEvent(1, 19, 501));
         assertThat(mClassifier.isFalseTouch(), is(true));
-
-        motionEventA.recycle();
-        motionEventB.recycle();
-        motionEventC.recycle();
-        motionEventD.recycle();
-        motionEventE.recycle();
-        motionEventF.recycle();
     }
 
     @Test
     public void testPass_swipe() {
-        MotionEvent motionEventA = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 1, 1, 0);
-        MotionEvent motionEventB = MotionEvent.obtain(1, 3, MotionEvent.ACTION_MOVE, 1, DPI * 3, 0);
-        MotionEvent motionEventC = MotionEvent.obtain(1, 1000, MotionEvent.ACTION_UP, 1, DPI * 3,
-                0);
 
-        appendMotionEvent(motionEventA);
+        mClassifier.onTouchEvent(appendDownEvent(1, 1));
         assertThat(mClassifier.isFalseTouch(), is(true));
 
-
-        appendMotionEvent(motionEventB);
-        appendMotionEvent(motionEventC);
+        mClassifier.onTouchEvent(appendMoveEvent(1, mDataProvider.getYdpi() * 3, 3));
+        mClassifier.onTouchEvent(appendUpEvent(1, mDataProvider.getYdpi() * 3, 300));
         assertThat(mClassifier.isFalseTouch(), is(false));
-
-        motionEventA.recycle();
-        motionEventB.recycle();
-        motionEventC.recycle();
-    }
-
-    private void appendMotionEvent(MotionEvent motionEvent) {
-        if (mMotionEvents.isEmpty()) {
-            when(mDataProvider.getFirstRecentMotionEvent()).thenReturn(motionEvent);
-        }
-
-        mMotionEvents.add(motionEvent);
-        when(mDataProvider.getRecentMotionEvents()).thenReturn(mMotionEvents);
-
-        when(mDataProvider.getLastMotionEvent()).thenReturn(motionEvent);
-
-        mClassifier.onTouchEvent(motionEvent);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java
index 1da4206..748c137 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java
@@ -22,12 +22,12 @@
 
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.SysuiTestCase;
-
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,24 +37,32 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class FalsingDataProviderTest extends SysuiTestCase {
+public class FalsingDataProviderTest extends ClassifierTest {
 
     private FalsingDataProvider mDataProvider;
 
     @Before
     public void setup() {
-        mDataProvider = new FalsingDataProvider(getContext());
+        super.setup();
+        DisplayMetrics displayMetrics = new DisplayMetrics();
+        displayMetrics.xdpi = 100;
+        displayMetrics.ydpi = 100;
+        displayMetrics.widthPixels = 1000;
+        displayMetrics.heightPixels = 1000;
+        mDataProvider = new FalsingDataProvider(displayMetrics);
+    }
+
+    @After
+    public void tearDown() {
+        super.tearDown();
+        mDataProvider.onSessionEnd();
     }
 
     @Test
     public void test_trackMotionEvents() {
-        MotionEvent motionEventA = obtainMotionEvent(MotionEvent.ACTION_DOWN, 1, 2, 9);
-        MotionEvent motionEventB = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 4, 7);
-        MotionEvent motionEventC = obtainMotionEvent(MotionEvent.ACTION_UP, 3, 6, 5);
-
-        mDataProvider.onMotionEvent(motionEventA);
-        mDataProvider.onMotionEvent(motionEventB);
-        mDataProvider.onMotionEvent(motionEventC);
+        mDataProvider.onMotionEvent(appendDownEvent(2, 9));
+        mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
+        mDataProvider.onMotionEvent(appendUpEvent(6, 5));
         List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
 
         assertThat(motionEventList.size(), is(3));
@@ -70,20 +78,12 @@
         assertThat(motionEventList.get(0).getY(), is(9f));
         assertThat(motionEventList.get(1).getY(), is(7f));
         assertThat(motionEventList.get(2).getY(), is(5f));
-
-        motionEventA.recycle();
-        motionEventB.recycle();
-        motionEventC.recycle();
     }
 
     @Test
     public void test_trackRecentMotionEvents() {
-        MotionEvent motionEventA = obtainMotionEvent(MotionEvent.ACTION_DOWN, 1, 2, 9);
-        MotionEvent motionEventB = obtainMotionEvent(MotionEvent.ACTION_MOVE, 800, 4, 7);
-        MotionEvent motionEventC = obtainMotionEvent(MotionEvent.ACTION_UP, 1200, 6, 5);
-
-        mDataProvider.onMotionEvent(motionEventA);
-        mDataProvider.onMotionEvent(motionEventB);
+        mDataProvider.onMotionEvent(appendDownEvent(2, 9, 1));
+        mDataProvider.onMotionEvent(appendMoveEvent(4, 7, 800));
         List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
 
         assertThat(motionEventList.size(), is(2));
@@ -96,7 +96,7 @@
         assertThat(motionEventList.get(0).getY(), is(9f));
         assertThat(motionEventList.get(1).getY(), is(7f));
 
-        mDataProvider.onMotionEvent(motionEventC);
+        mDataProvider.onMotionEvent(appendUpEvent(6, 5, 1200));
 
         // Still two events, but event a is gone.
         assertThat(motionEventList.size(), is(2));
@@ -115,18 +115,14 @@
         assertThat(firstRealMotionEvent.getEventTime(), is(1L));
         assertThat(firstRealMotionEvent.getX(), is(2f));
         assertThat(firstRealMotionEvent.getY(), is(9f));
-
-        motionEventA.recycle();
-        motionEventB.recycle();
-        motionEventC.recycle();
     }
 
     @Test
     public void test_unpackMotionEvents() {
         // Batching only works for motion events of the same type.
-        MotionEvent motionEventA = obtainMotionEvent(MotionEvent.ACTION_MOVE, 1, 2, 9);
-        MotionEvent motionEventB = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 4, 7);
-        MotionEvent motionEventC = obtainMotionEvent(MotionEvent.ACTION_MOVE, 3, 6, 5);
+        MotionEvent motionEventA = appendMoveEvent(2, 9);
+        MotionEvent motionEventB = appendMoveEvent(4, 7);
+        MotionEvent motionEventC = appendMoveEvent(6, 5);
         motionEventA.addBatch(motionEventB);
         motionEventA.addBatch(motionEventC);
         // Note that calling addBatch changes properties on the original event, not just it's
@@ -148,114 +144,86 @@
         assertThat(motionEventList.get(0).getY(), is(9f));
         assertThat(motionEventList.get(1).getY(), is(7f));
         assertThat(motionEventList.get(2).getY(), is(5f));
-
-        motionEventA.recycle();
-        motionEventB.recycle();
-        motionEventC.recycle();
     }
 
     @Test
     public void test_getAngle() {
-        MotionEvent motionEventOrigin = obtainMotionEvent(MotionEvent.ACTION_DOWN, 1, 0, 0);
+        MotionEvent motionEventOrigin = appendDownEvent(0, 0);
 
-        MotionEvent motionEventA = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 1, 1);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventA);
+        mDataProvider.onMotionEvent(appendMoveEvent(1, 1));
         assertThat((double) mDataProvider.getAngle(), closeTo(Math.PI / 4, .001));
-        motionEventA.recycle();
         mDataProvider.onSessionEnd();
 
-        MotionEvent motionEventB = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, -1, -1);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventB);
+        mDataProvider.onMotionEvent(appendMoveEvent(-1, -1));
         assertThat((double) mDataProvider.getAngle(), closeTo(5 * Math.PI / 4, .001));
-        motionEventB.recycle();
         mDataProvider.onSessionEnd();
 
 
-        MotionEvent motionEventC = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 2, 0);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventC);
+        mDataProvider.onMotionEvent(appendMoveEvent(2, 0));
         assertThat((double) mDataProvider.getAngle(), closeTo(0, .001));
-        motionEventC.recycle();
         mDataProvider.onSessionEnd();
     }
 
     @Test
     public void test_isHorizontal() {
-        MotionEvent motionEventOrigin = obtainMotionEvent(MotionEvent.ACTION_DOWN, 1, 0, 0);
+        MotionEvent motionEventOrigin = appendDownEvent(0, 0);
 
-        MotionEvent motionEventA = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 1, 1);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventA);
+        mDataProvider.onMotionEvent(appendMoveEvent(1, 1));
         assertThat(mDataProvider.isHorizontal(), is(false));
-        motionEventA.recycle();
         mDataProvider.onSessionEnd();
 
-        MotionEvent motionEventB = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 2, 1);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventB);
+        mDataProvider.onMotionEvent(appendMoveEvent(2, 1));
         assertThat(mDataProvider.isHorizontal(), is(true));
-        motionEventB.recycle();
         mDataProvider.onSessionEnd();
 
-        MotionEvent motionEventC = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, -3, -1);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventC);
+        mDataProvider.onMotionEvent(appendMoveEvent(-3, -1));
         assertThat(mDataProvider.isHorizontal(), is(true));
-        motionEventC.recycle();
         mDataProvider.onSessionEnd();
     }
 
     @Test
     public void test_isVertical() {
-        MotionEvent motionEventOrigin = obtainMotionEvent(MotionEvent.ACTION_DOWN, 1, 0, 0);
+        MotionEvent motionEventOrigin = appendDownEvent(0, 0);
 
-        MotionEvent motionEventA = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 1, 0);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventA);
+        mDataProvider.onMotionEvent(appendMoveEvent(1, 0));
         assertThat(mDataProvider.isVertical(), is(false));
-        motionEventA.recycle();
         mDataProvider.onSessionEnd();
 
-        MotionEvent motionEventB = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 0, 1);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventB);
+        mDataProvider.onMotionEvent(appendMoveEvent(0, 1));
         assertThat(mDataProvider.isVertical(), is(true));
-        motionEventB.recycle();
         mDataProvider.onSessionEnd();
 
-        MotionEvent motionEventC = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, -3, -10);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventC);
+        mDataProvider.onMotionEvent(appendMoveEvent(-3, -10));
         assertThat(mDataProvider.isVertical(), is(true));
-        motionEventC.recycle();
         mDataProvider.onSessionEnd();
     }
 
     @Test
     public void test_isRight() {
-        MotionEvent motionEventOrigin = obtainMotionEvent(MotionEvent.ACTION_DOWN, 1, 0, 0);
+        MotionEvent motionEventOrigin = appendDownEvent(0, 0);
 
-        MotionEvent motionEventA = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 1, 1);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventA);
+        mDataProvider.onMotionEvent(appendMoveEvent(1, 1));
         assertThat(mDataProvider.isRight(), is(true));
-        motionEventA.recycle();
         mDataProvider.onSessionEnd();
 
-        MotionEvent motionEventB = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 0, 1);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventB);
+        mDataProvider.onMotionEvent(appendMoveEvent(0, 1));
         assertThat(mDataProvider.isRight(), is(false));
-        motionEventB.recycle();
         mDataProvider.onSessionEnd();
 
-        MotionEvent motionEventC = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, -3, -10);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventC);
+        mDataProvider.onMotionEvent(appendMoveEvent(-3, -10));
         assertThat(mDataProvider.isRight(), is(false));
-        motionEventC.recycle();
         mDataProvider.onSessionEnd();
     }
 
@@ -263,31 +231,21 @@
     public void test_isUp() {
         // Remember that our y axis is flipped.
 
-        MotionEvent motionEventOrigin = obtainMotionEvent(MotionEvent.ACTION_DOWN, 1, 0, 0);
+        MotionEvent motionEventOrigin = appendDownEvent(0, 0);
 
-        MotionEvent motionEventA = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 1, -1);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventA);
+        mDataProvider.onMotionEvent(appendMoveEvent(1, -1));
         assertThat(mDataProvider.isUp(), is(true));
-        motionEventA.recycle();
         mDataProvider.onSessionEnd();
 
-        MotionEvent motionEventB = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, 0, 0);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventB);
+        mDataProvider.onMotionEvent(appendMoveEvent(0, 0));
         assertThat(mDataProvider.isUp(), is(false));
-        motionEventB.recycle();
         mDataProvider.onSessionEnd();
 
-        MotionEvent motionEventC = obtainMotionEvent(MotionEvent.ACTION_MOVE, 2, -3, 10);
         mDataProvider.onMotionEvent(motionEventOrigin);
-        mDataProvider.onMotionEvent(motionEventC);
+        mDataProvider.onMotionEvent(appendMoveEvent(-3, 10));
         assertThat(mDataProvider.isUp(), is(false));
-        motionEventC.recycle();
         mDataProvider.onSessionEnd();
     }
-
-    private MotionEvent obtainMotionEvent(int action, long eventTimeMs, float x, float y) {
-        return MotionEvent.obtain(1, eventTimeMs, action, x, y, 0);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
index cba9ee38..341b74b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
@@ -25,25 +25,27 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.SysuiTestCase;
-
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class PointerCountClassifierTest extends SysuiTestCase {
+public class PointerCountClassifierTest extends ClassifierTest {
 
-    @Mock
-    private FalsingDataProvider mDataProvider;
     private FalsingClassifier mClassifier;
 
     @Before
     public void setup() {
-        mClassifier = new PointerCountClassifier(mDataProvider);
+        super.setup();
+        mClassifier = new PointerCountClassifier(getDataProvider());
+    }
+
+    @After
+    public void tearDown() {
+        super.tearDown();
     }
 
     @Test
@@ -53,9 +55,7 @@
 
     @Test
     public void testPass_singlePointer() {
-        MotionEvent motionEvent = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 1, 1, 0);
-        mClassifier.onTouchEvent(motionEvent);
-        motionEvent.recycle();
+        mClassifier.onTouchEvent(appendDownEvent(1, 1));
         assertThat(mClassifier.isFalseTouch(), is(false));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
index 2ed7925..a6cabbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
@@ -31,8 +31,7 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.SysuiTestCase;
-
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -45,7 +44,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class ProximityClassifierTest extends SysuiTestCase {
+public class ProximityClassifierTest extends ClassifierTest {
 
     private static final long NS_PER_MS = 1000000;
 
@@ -57,12 +56,18 @@
 
     @Before
     public void setup() {
+        super.setup();
         MockitoAnnotations.initMocks(this);
         when(mDataProvider.getInteractionType()).thenReturn(GENERIC);
         when(mDistanceClassifier.isLongSwipe()).thenReturn(false);
         mClassifier = new ProximityClassifier(mDistanceClassifier, mDataProvider);
     }
 
+    @After
+    public void tearDown() {
+        super.tearDown();
+    }
+
     @Test
     public void testPass_uncovered() {
         touchDown();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
index 4bb3c15..0355dc3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
@@ -34,8 +34,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.SysuiTestCase;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -45,15 +43,15 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class TypeClassifierTest extends SysuiTestCase {
+public class TypeClassifierTest extends ClassifierTest {
 
     @Mock
     private FalsingDataProvider mDataProvider;
-
     private FalsingClassifier mClassifier;
 
     @Before
     public void setup() {
+        super.setup();
         MockitoAnnotations.initMocks(this);
         mClassifier = new TypeClassifier(mDataProvider);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
index 9d09a7e..25a1a75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
@@ -18,128 +18,93 @@
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.view.MotionEvent;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.SysuiTestCase;
-
 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.stubbing.Answer;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Random;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class ZigZagClassifierTest extends SysuiTestCase {
+public class ZigZagClassifierTest extends ClassifierTest {
 
-    private static final long NS_PER_MS = 1000000;
-
-    @Mock
-    private FalsingDataProvider mDataProvider;
     private FalsingClassifier mClassifier;
-    private List<MotionEvent> mMotionEvents = new ArrayList<>();
-    private float mOffsetX = 0;
-    private float mOffsetY = 0;
-    private float mDx;
-    private float mDy;
 
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
-        when(mDataProvider.getXdpi()).thenReturn(100f);
-        when(mDataProvider.getYdpi()).thenReturn(100f);
-        when(mDataProvider.getRecentMotionEvents()).thenReturn(mMotionEvents);
-        mClassifier = new ZigZagClassifier(mDataProvider);
-
-
-        // Calculate the response to these calls on the fly, otherwise Mockito gets bogged down
-        // everytime we call appendMotionEvent.
-        when(mDataProvider.getFirstRecentMotionEvent()).thenAnswer(
-                (Answer<MotionEvent>) invocation -> mMotionEvents.get(0));
-        when(mDataProvider.getLastMotionEvent()).thenAnswer(
-                (Answer<MotionEvent>) invocation -> mMotionEvents.get(mMotionEvents.size() - 1));
-        when(mDataProvider.isHorizontal()).thenAnswer(
-                (Answer<Boolean>) invocation -> Math.abs(mDy) < Math.abs(mDx));
-        when(mDataProvider.isVertical()).thenAnswer(
-                (Answer<Boolean>) invocation -> Math.abs(mDy) > Math.abs(mDx));
-        when(mDataProvider.isRight()).thenAnswer((Answer<Boolean>) invocation -> mDx > 0);
-        when(mDataProvider.isUp()).thenAnswer((Answer<Boolean>) invocation -> mDy < 0);
+        super.setup();
+        mClassifier = new ZigZagClassifier(getDataProvider());
     }
 
     @After
     public void tearDown() {
-        clearMotionEvents();
+        super.tearDown();
     }
 
     @Test
     public void testPass_fewTouchesVertical() {
         assertThat(mClassifier.isFalseTouch(), is(false));
-        appendMotionEvent(0, 0);
+        appendMoveEvent(0, 0);
         assertThat(mClassifier.isFalseTouch(), is(false));
-        appendMotionEvent(0, 100);
+        appendMoveEvent(0, 100);
         assertThat(mClassifier.isFalseTouch(), is(false));
     }
 
     @Test
     public void testPass_vertical() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(0, 100);
-        appendMotionEvent(0, 200);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(0, 100);
+        appendMoveEvent(0, 200);
         assertThat(mClassifier.isFalseTouch(), is(false));
     }
 
     @Test
     public void testPass_fewTouchesHorizontal() {
         assertThat(mClassifier.isFalseTouch(), is(false));
-        appendMotionEvent(0, 0);
+        appendMoveEvent(0, 0);
         assertThat(mClassifier.isFalseTouch(), is(false));
-        appendMotionEvent(100, 0);
+        appendMoveEvent(100, 0);
         assertThat(mClassifier.isFalseTouch(), is(false));
     }
 
     @Test
     public void testPass_horizontal() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(100, 0);
-        appendMotionEvent(200, 0);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(100, 0);
+        appendMoveEvent(200, 0);
         assertThat(mClassifier.isFalseTouch(), is(false));
     }
 
 
     @Test
     public void testFail_minimumTouchesVertical() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(0, 100);
-        appendMotionEvent(0, 1);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(0, 100);
+        appendMoveEvent(0, 1);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void testFail_minimumTouchesHorizontal() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(100, 0);
-        appendMotionEvent(1, 0);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(100, 0);
+        appendMoveEvent(1, 0);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void testPass_fortyFiveDegreesStraight() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(10, 10);
-        appendMotionEvent(20, 20);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(10, 10);
+        appendMoveEvent(20, 20);
         assertThat(mClassifier.isFalseTouch(), is(false));
     }
 
@@ -147,9 +112,9 @@
     public void testPass_horizontalZigZagVerticalStraight() {
         // This test looks just like testFail_horizontalZigZagVerticalStraight but with
         // a longer y range, making it look straighter.
-        appendMotionEvent(0, 0);
-        appendMotionEvent(5, 100);
-        appendMotionEvent(-5, 200);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(5, 100);
+        appendMoveEvent(-5, 200);
         assertThat(mClassifier.isFalseTouch(), is(false));
     }
 
@@ -157,9 +122,9 @@
     public void testPass_horizontalStraightVerticalZigZag() {
         // This test looks just like testFail_horizontalStraightVerticalZigZag but with
         // a longer x range, making it look straighter.
-        appendMotionEvent(0, 0);
-        appendMotionEvent(100, 5);
-        appendMotionEvent(200, -5);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(100, 5);
+        appendMoveEvent(200, -5);
         assertThat(mClassifier.isFalseTouch(), is(false));
     }
 
@@ -167,9 +132,9 @@
     public void testFail_horizontalZigZagVerticalStraight() {
         // This test looks just like testPass_horizontalZigZagVerticalStraight but with
         // a shorter y range, making it look more crooked.
-        appendMotionEvent(0, 0);
-        appendMotionEvent(5, 10);
-        appendMotionEvent(-5, 20);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(5, 10);
+        appendMoveEvent(-5, 20);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
@@ -177,217 +142,217 @@
     public void testFail_horizontalStraightVerticalZigZag() {
         // This test looks just like testPass_horizontalStraightVerticalZigZag but with
         // a shorter x range, making it look more crooked.
-        appendMotionEvent(0, 0);
-        appendMotionEvent(10, 5);
-        appendMotionEvent(20, -5);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(10, 5);
+        appendMoveEvent(20, -5);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void test_between0And45() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(100, 5);
-        appendMotionEvent(200, 10);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(100, 5);
+        appendMoveEvent(200, 10);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(100, 0);
-        appendMotionEvent(200, 10);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(100, 0);
+        appendMoveEvent(200, 10);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(100, -10);
-        appendMotionEvent(200, 10);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(100, -10);
+        appendMoveEvent(200, 10);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(100, -10);
-        appendMotionEvent(200, 50);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(100, -10);
+        appendMoveEvent(200, 50);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void test_between45And90() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(10, 50);
-        appendMotionEvent(8, 100);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(10, 50);
+        appendMoveEvent(8, 100);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(1, 800);
-        appendMotionEvent(2, 900);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(1, 800);
+        appendMoveEvent(2, 900);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-10, 600);
-        appendMotionEvent(30, 700);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-10, 600);
+        appendMoveEvent(30, 700);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(40, 100);
-        appendMotionEvent(0, 101);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(40, 100);
+        appendMoveEvent(0, 101);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void test_between90And135() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-10, 50);
-        appendMotionEvent(-24, 100);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-10, 50);
+        appendMoveEvent(-24, 100);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-20, 800);
-        appendMotionEvent(-20, 900);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-20, 800);
+        appendMoveEvent(-20, 900);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(30, 600);
-        appendMotionEvent(-10, 700);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(30, 600);
+        appendMoveEvent(-10, 700);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-80, 100);
-        appendMotionEvent(-10, 101);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-80, 100);
+        appendMoveEvent(-10, 101);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void test_between135And180() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-120, 10);
-        appendMotionEvent(-200, 20);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-120, 10);
+        appendMoveEvent(-200, 20);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-20, 8);
-        appendMotionEvent(-40, 2);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-20, 8);
+        appendMoveEvent(-40, 2);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-500, -2);
-        appendMotionEvent(-600, 70);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-500, -2);
+        appendMoveEvent(-600, 70);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-80, 100);
-        appendMotionEvent(-100, 1);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-80, 100);
+        appendMoveEvent(-100, 1);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void test_between180And225() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-120, -10);
-        appendMotionEvent(-200, -20);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-120, -10);
+        appendMoveEvent(-200, -20);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-20, -8);
-        appendMotionEvent(-40, -2);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-20, -8);
+        appendMoveEvent(-40, -2);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-500, 2);
-        appendMotionEvent(-600, -70);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-500, 2);
+        appendMoveEvent(-600, -70);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-80, -100);
-        appendMotionEvent(-100, -1);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-80, -100);
+        appendMoveEvent(-100, -1);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void test_between225And270() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-12, -20);
-        appendMotionEvent(-20, -40);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-12, -20);
+        appendMoveEvent(-20, -40);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-20, -130);
-        appendMotionEvent(-40, -260);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-20, -130);
+        appendMoveEvent(-40, -260);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(1, -100);
-        appendMotionEvent(-6, -200);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(1, -100);
+        appendMoveEvent(-6, -200);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-80, -100);
-        appendMotionEvent(-10, -110);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-80, -100);
+        appendMoveEvent(-10, -110);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void test_between270And315() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(12, -20);
-        appendMotionEvent(20, -40);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(12, -20);
+        appendMoveEvent(20, -40);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(20, -130);
-        appendMotionEvent(40, -260);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(20, -130);
+        appendMoveEvent(40, -260);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(-1, -100);
-        appendMotionEvent(6, -200);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(-1, -100);
+        appendMoveEvent(6, -200);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(80, -100);
-        appendMotionEvent(10, -110);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(80, -100);
+        appendMoveEvent(10, -110);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
     @Test
     public void test_between315And360() {
-        appendMotionEvent(0, 0);
-        appendMotionEvent(120, -20);
-        appendMotionEvent(200, -40);
+        appendMoveEvent(0, 0);
+        appendMoveEvent(120, -20);
+        appendMoveEvent(200, -40);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(200, -13);
-        appendMotionEvent(400, -30);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(200, -13);
+        appendMoveEvent(400, -30);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(100, 10);
-        appendMotionEvent(600, -20);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(100, 10);
+        appendMoveEvent(600, -20);
         assertThat(mClassifier.isFalseTouch(), is(false));
 
-        mMotionEvents.clear();
-        appendMotionEvent(0, 0);
-        appendMotionEvent(80, -100);
-        appendMotionEvent(100, -1);
+        resetDataProvider();
+        appendMoveEvent(0, 0);
+        appendMoveEvent(80, -100);
+        appendMoveEvent(100, -1);
         assertThat(mClassifier.isFalseTouch(), is(true));
     }
 
@@ -397,74 +362,50 @@
         // We use a pre-determined seed to make this test repeatable.
         Random rand = new Random(23);
         for (int i = 0; i < 100; i++) {
-            mOffsetX = rand.nextInt(2000) - 1000;
-            mOffsetY = rand.nextInt(2000) - 1000;
+            setOffsetX(rand.nextInt(2000) - 1000);
+            setOffsetY(rand.nextInt(2000) - 1000);
             try {
-                clearMotionEvents();
+                resetDataProvider();
                 testPass_fewTouchesVertical();
-                clearMotionEvents();
+                resetDataProvider();
                 testPass_vertical();
-                clearMotionEvents();
+                resetDataProvider();
                 testFail_horizontalStraightVerticalZigZag();
-                clearMotionEvents();
+                resetDataProvider();
                 testFail_horizontalZigZagVerticalStraight();
-                clearMotionEvents();
+                resetDataProvider();
                 testFail_minimumTouchesHorizontal();
-                clearMotionEvents();
+                resetDataProvider();
                 testFail_minimumTouchesVertical();
-                clearMotionEvents();
+                resetDataProvider();
                 testPass_fewTouchesHorizontal();
-                clearMotionEvents();
+                resetDataProvider();
                 testPass_fortyFiveDegreesStraight();
-                clearMotionEvents();
+                resetDataProvider();
                 testPass_horizontal();
-                clearMotionEvents();
+                resetDataProvider();
                 testPass_horizontalStraightVerticalZigZag();
-                clearMotionEvents();
+                resetDataProvider();
                 testPass_horizontalZigZagVerticalStraight();
-                clearMotionEvents();
+                resetDataProvider();
                 test_between0And45();
-                clearMotionEvents();
+                resetDataProvider();
                 test_between45And90();
-                clearMotionEvents();
+                resetDataProvider();
                 test_between90And135();
-                clearMotionEvents();
+                resetDataProvider();
                 test_between135And180();
-                clearMotionEvents();
+                resetDataProvider();
                 test_between180And225();
-                clearMotionEvents();
+                resetDataProvider();
                 test_between225And270();
-                clearMotionEvents();
+                resetDataProvider();
                 test_between270And315();
-                clearMotionEvents();
+                resetDataProvider();
                 test_between315And360();
             } catch (AssertionError e) {
                 throw new AssertionError("Random origin failure in iteration " + i, e);
             }
         }
     }
-
-    private void clearMotionEvents() {
-        for (MotionEvent motionEvent : mMotionEvents) {
-            motionEvent.recycle();
-        }
-        mMotionEvents.clear();
-    }
-
-    private void appendMotionEvent(float x, float y) {
-        x += mOffsetX;
-        y += mOffsetY;
-
-        long eventTime = mMotionEvents.size() + 1;
-        MotionEvent motionEvent = MotionEvent.obtain(1, eventTime, MotionEvent.ACTION_DOWN, x, y,
-                0);
-        mMotionEvents.add(motionEvent);
-
-        mDx = mDataProvider.getFirstRecentMotionEvent().getX()
-                - mDataProvider.getLastMotionEvent().getX();
-        mDy = mDataProvider.getFirstRecentMotionEvent().getY()
-                - mDataProvider.getLastMotionEvent().getY();
-
-        mClassifier.onTouchEvent(motionEvent);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 355e260..4419114 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -48,6 +48,8 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.util.wakelock.SettableWakeLock;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -73,6 +75,12 @@
     private NotificationMediaManager mNotificationMediaManager;
     @Mock
     private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private ZenModeController mZenModeController;
+    @Mock
+    private SettableWakeLock mMediaWakeLock;
+    @Mock
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private TestableKeyguardSliceProvider mProvider;
     private boolean mIsZenMode;
 
@@ -194,6 +202,20 @@
         verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null));
     }
 
+    @Test
+    public void onDestroy_noCrash() {
+        mProvider.onDestroy();
+    }
+
+    @Test
+    public void onDestroy_unregisterListeners() {
+        mProvider.registerClockUpdate();
+        mProvider.onDestroy();
+        verify(mMediaWakeLock).setAcquired(eq(false));
+        verify(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class));
+        verify(mKeyguardUpdateMonitor).removeCallback(any());
+    }
+
     private class TestableKeyguardSliceProvider extends KeyguardSliceProvider {
         int mCleanDateFormatInvokations;
         private int mCounter;
@@ -207,6 +229,8 @@
             super.onCreateSliceProvider();
             mAlarmManager = KeyguardSliceProviderTest.this.mAlarmManager;
             mContentResolver = KeyguardSliceProviderTest.this.mContentResolver;
+            mZenModeController = KeyguardSliceProviderTest.this.mZenModeController;
+            mMediaWakeLock = KeyguardSliceProviderTest.this.mMediaWakeLock;
             return true;
         }
 
@@ -223,7 +247,7 @@
 
         @Override
         public KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
-            return mock(KeyguardUpdateMonitor.class);
+            return mKeyguardUpdateMonitor;
         }
 
         @Override
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index c58e929..5a4892c 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -5780,7 +5780,7 @@
     // OS: P
     WIFI_SCANNING_NEEDED_DIALOG = 1373;
 
-    // OPEN: Settings > System > Gestures > Swipe up gesture
+    // OPEN: Settings > System > Gestures > System navigation
     // CATEGORY: SETTINGS
     // OS: P
     SETTINGS_GESTURE_SWIPE_UP = 1374;
@@ -7402,6 +7402,18 @@
     // OS: Q
     MODULE_LICENSES_DASHBOARD = 1746;
 
+    // OPEN: Settings > System > Gestures > System navigation > Info icon
+    // CATEGORY: SETTINGS
+    // OS: Q
+    // Note: Info icon is visible only when gesture navigation is not available and disabled
+    SETTINGS_GESTURE_NAV_NOT_AVAILABLE_DLG = 1747;
+
+    // OPEN: Settings > System > Gestures > System navigation > Gear icon
+    // CATEGORY: SETTINGS
+    // OS: Q
+    // Note: Gear icon is shown next to gesture navigation preference and opens sensitivity dialog
+    SETTINGS_GESTURE_NAV_BACK_SENSITIVITY_DLG = 1748;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e81d172..fc67c38 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2616,9 +2616,11 @@
                     final boolean valid = ((msg.arg1 & NETWORK_VALIDATION_RESULT_VALID) != 0);
                     final boolean wasValidated = nai.lastValidated;
                     final boolean wasDefault = isDefaultNetwork(nai);
-                    if (nai.everCaptivePortalDetected && !nai.captivePortalLoginNotified
-                            && valid) {
-                        nai.captivePortalLoginNotified = true;
+                    // Only show a connected notification if the network is pending validation
+                    // after the captive portal app was open, and it has now validated.
+                    if (nai.captivePortalValidationPending && valid) {
+                        // User is now logged in, network validated.
+                        nai.captivePortalValidationPending = false;
                         showNetworkNotification(nai, NotificationType.LOGGED_IN);
                     }
 
@@ -2689,9 +2691,6 @@
                         final int oldScore = nai.getCurrentScore();
                         nai.lastCaptivePortalDetected = visible;
                         nai.everCaptivePortalDetected |= visible;
-                        if (visible) {
-                            nai.captivePortalLoginNotified = false;
-                        }
                         if (nai.lastCaptivePortalDetected &&
                             Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
                             if (DBG) log("Avoiding captive portal network: " + nai.name());
@@ -3500,6 +3499,12 @@
                 new CaptivePortal(new CaptivePortalImpl(network).asBinder()));
         appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
 
+        // This runs on a random binder thread, but getNetworkAgentInfoForNetwork is thread-safe,
+        // and captivePortalValidationPending is volatile.
+        final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+        if (nai != null) {
+            nai.captivePortalValidationPending = true;
+        }
         Binder.withCleanCallingIdentity(() ->
                 mContext.startActivityAsUser(appIntent, UserHandle.CURRENT));
     }
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index 58d9965..95eb2c69 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -26,12 +26,17 @@
 import android.system.Os;
 import android.system.OsConstants;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -76,6 +81,8 @@
 
     private static final Pattern ION_HEAP_SIZE_IN_BYTES =
             Pattern.compile("\n\\s*total\\s*(\\d+)\\s*\n");
+    private static final Pattern PROCESS_ION_HEAP_SIZE_IN_BYTES =
+            Pattern.compile("\n\\s+\\S+\\s+(\\d+)\\s+(\\d+)");
 
     private static final int PGFAULT_INDEX = 9;
     private static final int PGMAJFAULT_INDEX = 11;
@@ -147,6 +154,16 @@
         return parseIonHeapSizeFromDebugfs(readFileContents(DEBUG_SYSTEM_ION_HEAP_FILE));
     }
 
+    /**
+     * Reads process allocation sizes on the system ion heap from debugfs.
+     *
+     * Returns values of allocation sizes in bytes on the system ion heap from
+     * /sys/kernel/debug/ion/heaps/system.
+     */
+    public static List<IonAllocations> readProcessSystemIonHeapSizesFromDebugfs() {
+        return parseProcessIonHeapSizesFromDebugfs(readFileContents(DEBUG_SYSTEM_ION_HEAP_FILE));
+    }
+
     private static String readFileContents(String path) {
         final File file = new File(path);
         if (!file.exists()) {
@@ -263,6 +280,43 @@
     }
 
     /**
+     * Parses per-process allocation sizes on the ion heap from the contents of a file under
+     * /sys/kernel/debug/ion/heaps in debugfs.
+     */
+    @VisibleForTesting
+    static List<IonAllocations> parseProcessIonHeapSizesFromDebugfs(String contents) {
+        if (contents == null || contents.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        final Matcher m = PROCESS_ION_HEAP_SIZE_IN_BYTES.matcher(contents);
+        final SparseArray<IonAllocations> entries = new SparseArray<>();
+        while (m.find()) {
+            try {
+                final int pid = Integer.parseInt(m.group(1));
+                final long sizeInBytes = Long.parseLong(m.group(2));
+                IonAllocations allocations = entries.get(pid);
+                if (allocations == null) {
+                    allocations = new IonAllocations();
+                    entries.put(pid, allocations);
+                }
+                allocations.pid = pid;
+                allocations.totalSizeInBytes += sizeInBytes;
+                allocations.count += 1;
+                allocations.maxSizeInBytes = Math.max(allocations.maxSizeInBytes, sizeInBytes);
+            } catch (NumberFormatException e) {
+                Slog.e(TAG, "Failed to parse value", e);
+            }
+        }
+
+        final List<IonAllocations> result = new ArrayList<>(entries.size());
+        for (int i = 0; i < entries.size(); i++) {
+            result.add(entries.valueAt(i));
+        }
+        return result;
+    }
+
+    /**
      * Returns whether per-app memcg is available on device.
      */
     static boolean hasMemcg() {
@@ -299,4 +353,40 @@
         /** Device time when the processes started. */
         public long startTimeNanos;
     }
+
+    /** Summary information about process ion allocations. */
+    public static final class IonAllocations {
+        /** PID these allocations belong to. */
+        public int pid;
+        /** Size of all individual allocations added together. */
+        public long totalSizeInBytes;
+        /** Number of allocations. */
+        public int count;
+        /** Size of the largest allocation. */
+        public long maxSizeInBytes;
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            IonAllocations that = (IonAllocations) o;
+            return pid == that.pid && totalSizeInBytes == that.totalSizeInBytes
+                    && count == that.count && maxSizeInBytes == that.maxSizeInBytes;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(pid, totalSizeInBytes, count, maxSizeInBytes);
+        }
+
+        @Override
+        public String toString() {
+            return "IonAllocations{"
+                    + "pid=" + pid
+                    + ", totalSizeInBytes=" + totalSizeInBytes
+                    + ", count=" + count
+                    + ", maxSizeInBytes=" + maxSizeInBytes
+                    + '}';
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 864a793..5b04379 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -155,9 +155,9 @@
     // Whether a captive portal was found during the last network validation attempt.
     public boolean lastCaptivePortalDetected;
 
-    // Indicates the user was notified of a successful captive portal login since a portal was
-    // last detected.
-    public boolean captivePortalLoginNotified;
+    // Indicates the captive portal app was opened to show a login UI to the user, but the network
+    // has not validated yet.
+    public volatile boolean captivePortalValidationPending;
 
     // Set to true when partial connectivity was detected.
     public boolean partialConnectivity;
@@ -629,7 +629,7 @@
                 + "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} "
                 + "everCaptivePortalDetected{" + everCaptivePortalDetected + "} "
                 + "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} "
-                + "captivePortalLoginNotified{" + captivePortalLoginNotified + "} "
+                + "captivePortalValidationPending{" + captivePortalValidationPending + "} "
                 + "partialConnectivity{" + partialConnectivity + "} "
                 + "acceptPartialConnectivity{" + networkMisc.acceptPartialConnectivity + "} "
                 + "clat{" + clatd + "} "
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index e7636ae..c312b76 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -222,6 +222,8 @@
     private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
     // Default update duration in milliseconds for REQUEST_LOCATION.
     private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000;
+    // Update duration extension multiplier for emergency REQUEST_LOCATION.
+    private static final int EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER = 3;
 
     /** simpler wrapper for ProviderRequest + Worksource */
     private static class GpsRequest {
@@ -724,15 +726,28 @@
                 Context.LOCATION_SERVICE);
         String provider;
         LocationChangeListener locationListener;
+        LocationRequest locationRequest = new LocationRequest()
+                .setInterval(LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS)
+                .setFastestInterval(LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS);
 
         if (independentFromGnss) {
             // For fast GNSS TTFF
             provider = LocationManager.NETWORK_PROVIDER;
             locationListener = mNetworkLocationListener;
+            locationRequest.setQuality(LocationRequest.POWER_LOW);
         } else {
             // For Device-Based Hybrid (E911)
             provider = LocationManager.FUSED_PROVIDER;
             locationListener = mFusedLocationListener;
+            locationRequest.setQuality(LocationRequest.ACCURACY_FINE);
+        }
+
+        locationRequest.setProvider(provider);
+
+        // Ignore location settings if in emergency mode.
+        if (isUserEmergency && mNIHandler.getInEmergency()) {
+            locationRequest.setLocationSettingsIgnored(true);
+            durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER;
         }
 
         Log.i(TAG,
@@ -740,14 +755,6 @@
                         "GNSS HAL Requesting location updates from %s provider for %d millis.",
                         provider, durationMillis));
 
-        LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(provider,
-                LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /* minDistance= */ 0,
-                /* singleShot= */ false);
-
-        // Ignore location settings if in emergency mode.
-        if (isUserEmergency && mNIHandler.getInEmergency()) {
-            locationRequest.setLocationSettingsIgnored(true);
-        }
         try {
             locationManager.requestLocationUpdates(locationRequest,
                     locationListener, mHandler.getLooper());
@@ -765,6 +772,9 @@
     }
 
     private void injectBestLocation(Location location) {
+        if (DEBUG) {
+            Log.d(TAG, "injectBestLocation: " + location);
+        }
         int gnssLocationFlags = LOCATION_HAS_LAT_LONG |
                 (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) |
                 (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) |
@@ -869,6 +879,9 @@
 
     private void handleUpdateLocation(Location location) {
         if (location.hasAccuracy()) {
+            if (DEBUG) {
+                Log.d(TAG, "injectLocation: " + location);
+            }
             native_inject_location(location.getLatitude(), location.getLongitude(),
                     location.getAccuracy());
         }
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 1658833..d53f685 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -91,8 +91,7 @@
             // Storage uses a special app op to decide the mount state and supports soft restriction
             // where the restricted state allows the permission but only for accessing the medial
             // collections.
-            case READ_EXTERNAL_STORAGE:
-            case WRITE_EXTERNAL_STORAGE: {
+            case READ_EXTERNAL_STORAGE: {
                 final int flags;
                 final boolean applyRestriction;
                 final boolean isWhiteListed;
@@ -148,6 +147,42 @@
                     }
                 };
             }
+            case WRITE_EXTERNAL_STORAGE: {
+                final boolean isWhiteListed;
+                final int targetSDK;
+
+                if (appInfo != null) {
+                    final int flags = context.getPackageManager().getPermissionFlags(permission,
+                            appInfo.packageName, user);
+                    isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
+                    targetSDK = appInfo.targetSdkVersion;
+                } else {
+                    isWhiteListed = false;
+                    targetSDK = 0;
+                }
+
+                return new SoftRestrictedPermissionPolicy() {
+                    @Override
+                    public int resolveAppOp() {
+                        return OP_NONE;
+                    }
+
+                    @Override
+                    public int getDesiredOpMode() {
+                        return MODE_DEFAULT;
+                    }
+
+                    @Override
+                    public boolean shouldSetAppOpIfNotDefault() {
+                        return false;
+                    }
+
+                    @Override
+                    public boolean canBeGranted() {
+                        return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q;
+                    }
+                };
+            }
             default:
                 return DUMMY_POLICY;
         }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 6b74c38..c76bbb0 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -27,6 +27,7 @@
 import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
+import static com.android.server.am.MemoryStatUtil.readProcessSystemIonHeapSizesFromDebugfs;
 import static com.android.server.am.MemoryStatUtil.readRssHighWaterMarkFromProcfs;
 import static com.android.server.am.MemoryStatUtil.readSystemIonHeapSizeFromDebugfs;
 
@@ -137,6 +138,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
+import com.android.server.am.MemoryStatUtil.IonAllocations;
 import com.android.server.am.MemoryStatUtil.MemoryStat;
 import com.android.server.role.RoleManagerInternal;
 import com.android.server.storage.DiskStatsFileLogger;
@@ -1271,6 +1273,21 @@
         pulledData.add(e);
     }
 
+    private void pullProcessSystemIonHeapSize(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs();
+        for (IonAllocations allocations : result) {
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+            e.writeInt(getUidForPid(allocations.pid));
+            e.writeString(readCmdlineFromProcfs(allocations.pid));
+            e.writeInt((int) (allocations.totalSizeInBytes / 1024));
+            e.writeInt(allocations.count);
+            e.writeInt((int) (allocations.maxSizeInBytes / 1024));
+            pulledData.add(e);
+        }
+    }
+
     private void pullBinderCallsStats(
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
@@ -2333,6 +2350,10 @@
                 pullSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+            case StatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE: {
+                pullProcessSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret);
+                break;
+            }
             case StatsLog.BINDER_CALLS: {
                 pullBinderCallsStats(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index d6a9f427..7408dd4 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -199,6 +199,7 @@
         private final Uri LOCK_SCREEN_WHEN_TRUST_LOST =
                 Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST);
 
+        private final boolean mIsAutomotive;
         private final ContentResolver mContentResolver;
         private boolean mTrustAgentsExtendUnlock;
         private boolean mLockWhenTrustLost;
@@ -210,6 +211,10 @@
          */
         SettingsObserver(Handler handler) {
             super(handler);
+
+            PackageManager packageManager = getContext().getPackageManager();
+            mIsAutomotive = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+
             mContentResolver = getContext().getContentResolver();
             updateContentObserver();
         }
@@ -233,11 +238,15 @@
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (TRUST_AGENTS_EXTEND_UNLOCK.equals(uri)) {
+                // Smart lock should only extend unlock. The only exception is for automotive,
+                // where it can actively unlock the head unit.
+                int defaultValue = mIsAutomotive ? 0 : 1;
+
                 mTrustAgentsExtendUnlock =
                         Settings.Secure.getIntForUser(
                                 mContentResolver,
                                 Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
-                                1 /* default */,
+                                defaultValue,
                                 mCurrentUser) != 0;
             } else if (LOCK_SCREEN_WHEN_TRUST_LOST.equals(uri)) {
                 mLockWhenTrustLost =
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index be3b924..4a9a3f7 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -79,7 +79,6 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
-import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 
@@ -541,14 +540,6 @@
                 // If the app was already visible, don't reset the waitingToShow state.
                 if (isHidden()) {
                     waitingToShow = true;
-
-                    // Let's reset the draw state in order to prevent the starting window to be
-                    // immediately dismissed when the app still has the surface.
-                    forAllWindows(w -> {
-                            if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
-                                w.mWinAnimator.resetDrawState();
-                            }
-                        },  true /* traverseTopToBottom */);
                 }
             }
 
@@ -1331,9 +1322,7 @@
         if (prevDc == null || prevDc == mDisplayContent) {
             return;
         }
-
-        prevDc.mOpeningApps.remove(this);
-        if (prevDc.mChangingApps.remove(this)) {
+        if (prevDc.mChangingApps.contains(this)) {
             // This gets called *after* the AppWindowToken has been reparented to the new display.
             // That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN),
             // so this token is now "frozen" while waiting for the animation to start on prevDc
@@ -1342,8 +1331,6 @@
             // so we need to cancel the change transition here.
             clearChangeLeash(getPendingTransaction(), true /* cancel */);
         }
-        prevDc.mClosingApps.remove(this);
-
         if (prevDc.mFocusedApp == this) {
             prevDc.setFocusedApp(null);
             final TaskStack stack = dc.getTopStack();
@@ -3229,6 +3216,16 @@
                 true /* topToBottom */);
     }
 
+    void removeFromPendingTransition() {
+        if (isWaitingForTransitionStart() && mDisplayContent != null) {
+            mDisplayContent.mOpeningApps.remove(this);
+            if (mDisplayContent.mChangingApps.remove(this)) {
+                clearChangeLeash(getPendingTransaction(), true /* cancel */);
+            }
+            mDisplayContent.mClosingApps.remove(this);
+        }
+    }
+
     private void updateColorTransform() {
         if (mSurfaceControl != null && mLastAppSaturationInfo != null) {
             getPendingTransaction().setColorTransform(mSurfaceControl,
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 80848a8f..c3a769b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2377,6 +2377,9 @@
                     + " to its current displayId=" + mDisplayId);
         }
 
+        // Clean up all pending transitions when stack reparent to another display.
+        stack.forAllAppWindows(AppWindowToken::removeFromPendingTransition);
+
         prevDc.mTaskStackContainers.removeChild(stack);
         mTaskStackContainers.addStackToDisplay(stack, onTop);
     }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 7badc7a..cf87203 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -478,8 +478,10 @@
 
                     @Override
                     public void onSwipeFromRight() {
-                        final Region excludedRegion =
-                                mDisplayContent.calculateSystemGestureExclusion();
+                        final Region excludedRegion;
+                        synchronized (mLock) {
+                            excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
+                        }
                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                 || mNavigationBarPosition == NAV_BAR_RIGHT;
                         if (mNavigationBar != null && sideAllowed
@@ -490,8 +492,10 @@
 
                     @Override
                     public void onSwipeFromLeft() {
-                        final Region excludedRegion =
-                                mDisplayContent.calculateSystemGestureExclusion();
+                        final Region excludedRegion;
+                        synchronized (mLock) {
+                            excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
+                        }
                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
                                 || mNavigationBarPosition == NAV_BAR_LEFT;
                         if (mNavigationBar != null && sideAllowed
@@ -1494,8 +1498,6 @@
         }
 
         sTmpRect.setEmpty();
-        sTmpDockedFrame.set(displayFrames.mDock);
-
         final int displayId = displayFrames.mDisplayId;
         final Rect dockFrame = displayFrames.mDock;
         final int displayHeight = displayFrames.mDisplayHeight;
@@ -1508,11 +1510,13 @@
                 continue;
             }
 
-            w.getWindowFrames().setFrames(sTmpDockedFrame /* parentFrame */,
-                    sTmpDockedFrame /* displayFrame */, sTmpDockedFrame /* overscanFrame */,
-                    sTmpDockedFrame /* contentFrame */, sTmpDockedFrame /* visibleFrame */,
-                    sTmpRect /* decorFrame */, sTmpDockedFrame /* stableFrame */,
-                    sTmpDockedFrame /* outsetFrame */);
+            w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
+                    displayFrames.mUnrestricted /* displayFrame */,
+                    displayFrames.mUnrestricted /* overscanFrame */,
+                    displayFrames.mUnrestricted /* contentFrame */,
+                    displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
+                    displayFrames.mUnrestricted /* stableFrame */,
+                    displayFrames.mUnrestricted /* outsetFrame */);
             w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
             w.computeFrameLw();
             final Rect frame = w.getFrameLw();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index a7760a86..c3762d6 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -317,6 +317,11 @@
             throw new IllegalStateException("mSurface does not hold a valid surface.");
         }
         final SurfaceSession session = new SurfaceSession();
+        // We consider nearly matched dimensions as there can be rounding errors and the user won't
+        // notice very minute differences from scaling one dimension more than the other
+        final boolean aspectRatioMismatch = Math.abs(
+                ((float) buffer.getWidth() / buffer.getHeight())
+                - ((float) mFrame.width() / mFrame.height())) > 0.01f;
 
         // Keep a reference to it such that it doesn't get destroyed when finalized.
         mChildSurfaceControl = new SurfaceControl.Builder(session)
@@ -328,16 +333,21 @@
         Surface surface = new Surface();
         surface.copyFrom(mChildSurfaceControl);
 
-        // Clip off ugly navigation bar.
-        final Rect crop = calculateSnapshotCrop();
-        final Rect frame = calculateSnapshotFrame(crop);
+        final Rect frame;
         SurfaceControl.openTransaction();
         try {
             // We can just show the surface here as it will still be hidden as the parent is
             // still hidden.
             mChildSurfaceControl.show();
-            mChildSurfaceControl.setWindowCrop(crop);
-            mChildSurfaceControl.setPosition(frame.left, frame.top);
+            if (aspectRatioMismatch) {
+                // Clip off ugly navigation bar.
+                final Rect crop = calculateSnapshotCrop();
+                frame = calculateSnapshotFrame(crop);
+                mChildSurfaceControl.setWindowCrop(crop);
+                mChildSurfaceControl.setPosition(frame.left, frame.top);
+            } else {
+                frame = null;
+            }
 
             // Scale the mismatch dimensions to fill the task bounds
             final float scale = 1 / mSnapshot.getScale();
@@ -348,10 +358,12 @@
         surface.attachAndQueueBuffer(buffer);
         surface.release();
 
-        final Canvas c = mSurface.lockCanvas(null);
-        drawBackgroundAndBars(c, frame);
-        mSurface.unlockCanvasAndPost(c);
-        mSurface.release();
+        if (aspectRatioMismatch) {
+            final Canvas c = mSurface.lockCanvas(null);
+            drawBackgroundAndBars(c, frame);
+            mSurface.unlockCanvasAndPost(c);
+            mSurface.release();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 481c3ba..114a56f 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1936,8 +1936,12 @@
     public boolean setPinnedStackAlpha(float alpha) {
         // Hold the lock since this is called from the BoundsAnimator running on the UiThread
         synchronized (mWmService.mGlobalLock) {
-            getPendingTransaction().setAlpha(getSurfaceControl(),
-                    mCancelCurrentBoundsAnimation ? 1 : alpha);
+            final SurfaceControl sc = getSurfaceControl();
+            if (sc == null || !sc.isValid()) {
+                // If the stack is already removed, don't bother updating any stack animation
+                return false;
+            }
+            getPendingTransaction().setAlpha(sc, mCancelCurrentBoundsAnimation ? 1 : alpha);
             scheduleAnimation();
             return !mCancelCurrentBoundsAnimation;
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8b61208..e5518d0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11018,7 +11018,11 @@
                 return false;
             }
             mLockPatternUtils.setLockScreenDisabled(disabled, userId);
-            mInjector.getIWindowManager().dismissKeyguard(null /* callback */, null /* message */);
+            if (disabled) {
+                mInjector
+                        .getIWindowManager()
+                        .dismissKeyguard(null /* callback */, null /* message */);
+            }
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.SET_KEYGUARD_DISABLED)
                     .setAdmin(who)
diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java
index 66884c6..6a6a130 100644
--- a/services/net/java/android/net/ip/IpServer.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -433,6 +433,9 @@
                 }
             }
             ifcg.clearFlag("running");
+
+            // TODO: this may throw if the interface is already gone. Do proper handling and
+            // simplify the DHCP server start/stop.
             mNMService.setInterfaceConfig(mIfaceName, ifcg);
 
             if (!configureDhcp(enabled, (Inet4Address) addr, prefixLen)) {
@@ -440,6 +443,14 @@
             }
         } catch (Exception e) {
             mLog.e("Error configuring interface " + e);
+            if (!enabled) {
+                try {
+                    // Calling stopDhcp several times is fine
+                    stopDhcp();
+                } catch (Exception dhcpError) {
+                    mLog.e("Error stopping DHCP", dhcpError);
+                }
+            }
             return false;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 213c939..6678a78 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -23,13 +23,18 @@
 import static com.android.server.am.MemoryStatUtil.parseIonHeapSizeFromDebugfs;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs;
+import static com.android.server.am.MemoryStatUtil.parseProcessIonHeapSizesFromDebugfs;
 import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.am.MemoryStatUtil.IonAllocations;
+
 import org.junit.Test;
 
 import java.io.ByteArrayOutputStream;
@@ -178,32 +183,70 @@
             + "voluntary_ctxt_switches:\t903\n"
             + "nonvoluntary_ctxt_switches:\t104\n";
 
+    // Repeated lines have been removed.
     private static final String DEBUG_SYSTEM_ION_HEAP_CONTENTS = String.join(
-            "          client              pid             size\n",
-            "----------------------------------------------------\n",
-            " audio@2.0-servi              765             4096\n",
-            " audio@2.0-servi              765            61440\n",
-            " audio@2.0-servi              765             4096\n",
-            "     voip_client               96             8192\n",
-            "     voip_client               96             4096\n",
-            "   system_server             1232         16728064\n",
-            "  surfaceflinger              611         50642944\n",
-            "----------------------------------------------------\n",
-            "orphaned allocations (info is from last known client):\n",
-            "----------------------------------------------------\n",
-            "  total orphaned                0\n",
-            "          total          55193600\n",
-            "   deferred free                0\n",
-            "----------------------------------------------------\n",
-            "0 order 4 highmem pages in uncached pool = 0 total\n",
-            "0 order 4 lowmem pages in uncached pool = 0 total\n",
-            "1251 order 4 lowmem pages in cached pool = 81985536 total\n",
-            "VMID 8: 0 order 4 highmem pages in secure pool = 0 total\n",
-            "VMID  8: 0 order 4 lowmem pages in secure pool = 0 total\n",
-            "--------------------------------------------\n",
-            "uncached pool = 4096 cached pool = 83566592 secure pool = 0\n",
-            "pool total (uncached + cached + secure) = 83570688\n",
-            "--------------------------------------------\n");
+            "\n",
+            "          client              pid             size",
+            "----------------------------------------------------",
+            " audio@2.0-servi              765             4096",
+            " audio@2.0-servi              765            61440",
+            " audio@2.0-servi              765             4096",
+            "     voip_client               96             8192",
+            "     voip_client               96             4096",
+            "   system_server             1232         16728064",
+            "  surfaceflinger              611         50642944",
+            "----------------------------------------------------",
+            "orphaned allocations (info is from last known client):",
+            "----------------------------------------------------",
+            "  total orphaned                0",
+            "          total          55193600",
+            "   deferred free                0",
+            "----------------------------------------------------",
+            "0 order 4 highmem pages in uncached pool = 0 total",
+            "0 order 4 lowmem pages in uncached pool = 0 total",
+            "1251 order 4 lowmem pages in cached pool = 81985536 total",
+            "VMID 8: 0 order 4 highmem pages in secure pool = 0 total",
+            "VMID  8: 0 order 4 lowmem pages in secure pool = 0 total",
+            "--------------------------------------------",
+            "uncached pool = 4096 cached pool = 83566592 secure pool = 0",
+            "pool total (uncached + cached + secure) = 83570688",
+            "--------------------------------------------");
+
+    // Repeated lines have been removed.
+    private static final String DEBUG_SYSTEM_ION_HEAP_CONTENTS_SARGO = String.join(
+            "\n",
+            "          client              pid             size      page counts"
+                    + "--------------------------------------------------       4K       8K      "
+                    + "16K      32K      64K     128K     256K     512K       1M       2M       "
+                    + "4M      >=8M",
+            "   system_server             1705         58097664    13120      532        "
+                    + "0        0        0        0        0        0        0        0        "
+                    + "0        0M",
+            " audio@2.0-servi              851            16384        0        2        0        "
+                    + "0        0        0        0        0        0        0        "
+                    + "0        0M",
+            " audio@2.0-servi              851             4096        1        0        0       "
+                    + " 0        0        0        0        0        0        0        0        "
+                    + "0M",
+            " audio@2.0-servi              851             4096        1        0      "
+                    + "  0        0        0        0        0        0        0        0        "
+                    + "0        0M",
+            "----------------------------------------------------",
+            "orphaned allocations (info is from last known client):",
+            "----------------------------------------------------",
+            "  total orphaned                0",
+            "          total         159928320",
+            "   deferred free                0",
+            "----------------------------------------------------",
+            "0 order 4 highmem pages in uncached pool = 0 total",
+            "0 order 4 lowmem pages in uncached pool = 0 total",
+            "1251 order 4 lowmem pages in cached pool = 81985536 total",
+            "VMID 8: 0 order 4 highmem pages in secure pool = 0 total",
+            "VMID  8: 0 order 4 lowmem pages in secure pool = 0 total",
+            "--------------------------------------------",
+            "uncached pool = 4096 cached pool = 83566592 secure pool = 0",
+            "pool total (uncached + cached + secure) = 83570688",
+            "--------------------------------------------");
 
     @Test
     public void testParseMemoryStatFromMemcg_parsesCorrectValues() {
@@ -323,5 +366,47 @@
     @Test
     public void testParseIonHeapSizeFromDebugfs_correctValue() {
         assertEquals(55193600, parseIonHeapSizeFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS));
+
+        assertEquals(159928320, parseIonHeapSizeFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS_SARGO));
+    }
+
+    @Test
+    public void testParseProcessIonHeapSizesFromDebugfs_emptyContents() {
+        assertEquals(0, parseProcessIonHeapSizesFromDebugfs("").size());
+
+        assertEquals(0, parseProcessIonHeapSizesFromDebugfs(null).size());
+    }
+
+    @Test
+    public void testParseProcessIonHeapSizesFromDebugfs_invalidValue() {
+        assertEquals(0, parseProcessIonHeapSizesFromDebugfs("<<no-value>>").size());
+    }
+
+    @Test
+    public void testParseProcessIonHeapSizesFromDebugfs_correctValue1() {
+        assertThat(parseProcessIonHeapSizesFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS))
+                .containsExactly(
+                        createIonAllocations(765, 61440 + 4096 + 4096, 3, 61440),
+                        createIonAllocations(96, 8192 + 4096, 2, 8192),
+                        createIonAllocations(1232, 16728064, 1, 16728064),
+                        createIonAllocations(611, 50642944, 1, 50642944));
+    }
+
+    @Test
+    public void testParseProcessIonHeapSizesFromDebugfs_correctValue2() {
+        assertThat(parseProcessIonHeapSizesFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS_SARGO))
+                .containsExactly(
+                        createIonAllocations(1705, 58097664, 1, 58097664),
+                        createIonAllocations(851, 16384 + 4096 + 4096, 3, 16384));
+    }
+
+    private static IonAllocations createIonAllocations(int pid, long totalSizeInBytes, int count,
+            long maxSizeInBytes) {
+        IonAllocations allocations = new IonAllocations();
+        allocations.pid = pid;
+        allocations.totalSizeInBytes = totalSizeInBytes;
+        allocations.count = count;
+        allocations.maxSizeInBytes = maxSizeInBytes;
+        return allocations;
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 4a87aa4..de184b8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -16,6 +16,10 @@
 
 package com.android.server.wm;
 
+import static android.view.Gravity.BOTTOM;
+import static android.view.Gravity.LEFT;
+import static android.view.Gravity.RIGHT;
+import static android.view.Gravity.TOP;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
@@ -26,9 +30,11 @@
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -66,6 +72,7 @@
     private WindowState mWindow;
     private int mRotation = ROTATION_0;
     private boolean mHasDisplayCutout;
+    private static final int DECOR_WINDOW_INSET = 50;
 
     @Before
     public void setUp() throws Exception {
@@ -520,6 +527,58 @@
         }
     }
 
+    @Test
+    public void testScreenDecorWindows() {
+        synchronized (mWm.mGlobalLock) {
+            final WindowState decorWindow = createWindow(null, TYPE_APPLICATION_OVERLAY,
+                    "decorWindow");
+            decorWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+            decorWindow.mAttrs.privateFlags |= PRIVATE_FLAG_IS_SCREEN_DECOR;
+            addWindow(decorWindow);
+            addWindow(mWindow);
+
+            // Decor on top
+            updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, TOP);
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
+
+            // Decor on bottom
+            updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, BOTTOM);
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT,
+                    DECOR_WINDOW_INSET);
+
+            // Decor on the left
+            updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, LEFT);
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+            assertInsetBy(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
+                    NAV_BAR_HEIGHT);
+
+            // Decor on the right
+            updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, RIGHT);
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+            assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
+                    NAV_BAR_HEIGHT);
+
+            // Decor not allowed as inset
+            updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, DECOR_WINDOW_INSET, TOP);
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        }
+    }
+
+    private void updateDecorWindow(WindowState decorWindow, int width, int height, int gravity) {
+        decorWindow.mAttrs.width = width;
+        decorWindow.mAttrs.height = height;
+        decorWindow.mAttrs.gravity = gravity;
+        decorWindow.setRequestedSize(width, height);
+    }
+
     /**
      * Asserts that {@code actual} is inset by the given amounts from the full display rect.
      *
diff --git a/telecomm/java/android/telecom/ConferenceParticipant.java b/telecomm/java/android/telecom/ConferenceParticipant.java
index 2f1505c..5e4818a 100644
--- a/telecomm/java/android/telecom/ConferenceParticipant.java
+++ b/telecomm/java/android/telecom/ConferenceParticipant.java
@@ -19,6 +19,7 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -69,18 +70,28 @@
     private long mConnectElapsedTime;
 
     /**
+     * The direction of the call;
+     * {@link Call.Details#DIRECTION_INCOMING} for incoming calls, or
+     * {@link Call.Details#DIRECTION_OUTGOING} for outgoing calls.
+     */
+    private int mCallDirection;
+
+    /**
      * Creates an instance of {@code ConferenceParticipant}.
      *
      * @param handle      The conference participant's handle (e.g., phone number).
      * @param displayName The display name for the participant.
      * @param endpoint    The enpoint Uri which uniquely identifies this conference participant.
      * @param state       The state of the participant in the conference.
+     * @param callDirection The direction of the call (incoming/outgoing).
      */
-    public ConferenceParticipant(Uri handle, String displayName, Uri endpoint, int state) {
+    public ConferenceParticipant(Uri handle, String displayName, Uri endpoint, int state,
+            int callDirection) {
         mHandle = handle;
         mDisplayName = displayName;
         mEndpoint = endpoint;
         mState = state;
+        mCallDirection = callDirection;
     }
 
     /**
@@ -96,7 +107,16 @@
                     String displayName = source.readString();
                     Uri endpoint = source.readParcelable(classLoader);
                     int state = source.readInt();
-                    return new ConferenceParticipant(handle, displayName, endpoint, state);
+                    long connectTime = source.readLong();
+                    long elapsedRealTime = source.readLong();
+                    int callDirection = source.readInt();
+                    ConferenceParticipant participant =
+                            new ConferenceParticipant(handle, displayName, endpoint, state,
+                                    callDirection);
+                    participant.setConnectTime(connectTime);
+                    participant.setConnectElapsedTime(elapsedRealTime);
+                    participant.setCallDirection(callDirection);
+                    return participant;
                 }
 
                 @Override
@@ -170,6 +190,9 @@
         dest.writeString(mDisplayName);
         dest.writeParcelable(mEndpoint, 0);
         dest.writeInt(mState);
+        dest.writeLong(mConnectTime);
+        dest.writeLong(mConnectElapsedTime);
+        dest.writeInt(mCallDirection);
     }
 
     /**
@@ -192,6 +215,8 @@
         sb.append(getConnectTime());
         sb.append(" ConnectElapsedTime: ");
         sb.append(getConnectElapsedTime());
+        sb.append(" Direction: ");
+        sb.append(getCallDirection() == Call.Details.DIRECTION_INCOMING ? "Incoming" : "Outgoing");
         sb.append("]");
         return sb.toString();
     }
@@ -239,7 +264,7 @@
     }
 
     /**
-     * The connect elpased time of the participant to the conference.
+     * The connect elapsed time of the participant to the conference.
      */
     public long getConnectElapsedTime() {
         return mConnectElapsedTime;
@@ -248,4 +273,76 @@
     public void setConnectElapsedTime(long connectElapsedTime) {
         mConnectElapsedTime = connectElapsedTime;
     }
+
+    /**
+     * @return The direction of the call (incoming/outgoing).
+     */
+    public @Call.Details.CallDirection int getCallDirection() {
+        return mCallDirection;
+    }
+
+    /**
+     * Sets the direction of the call.
+     * @param callDirection Whether the call is incoming or outgoing.
+     */
+    public void setCallDirection(@Call.Details.CallDirection int callDirection) {
+        mCallDirection = callDirection;
+    }
+
+    /**
+     * Attempts to build a tel: style URI from a conference participant.
+     * Conference event package data contains SIP URIs, so we try to extract the phone number and
+     * format into a typical tel: style URI.
+     *
+     * @param address The conference participant's address.
+     * @param countryIso The country ISO of the current subscription; used when formatting the
+     *                   participant phone number to E.164 format.
+     * @return The participant's address URI.
+     * @hide
+     */
+    @VisibleForTesting
+    public static Uri getParticipantAddress(Uri address, String countryIso) {
+        if (address == null) {
+            return address;
+        }
+        // Even if address is already in tel: format, still parse it and rebuild.
+        // This is to recognize tel URIs such as:
+        // tel:6505551212;phone-context=ims.mnc012.mcc034.3gppnetwork.org
+
+        // Conference event package participants are identified using SIP URIs (see RFC3261).
+        // A valid SIP uri has the format: sip:user:password@host:port;uri-parameters?headers
+        // Per RFC3261, the "user" can be a telephone number.
+        // For example: sip:1650555121;phone-context=blah.com@host.com
+        // In this case, the phone number is in the user field of the URI, and the parameters can be
+        // ignored.
+        //
+        // A SIP URI can also specify a phone number in a format similar to:
+        // sip:+1-212-555-1212@something.com;user=phone
+        // In this case, the phone number is again in user field and the parameters can be ignored.
+        // We can get the user field in these instances by splitting the string on the @, ;, or :
+        // and looking at the first found item.
+        String number = address.getSchemeSpecificPart();
+        if (TextUtils.isEmpty(number)) {
+            return address;
+        }
+
+        String numberParts[] = number.split("[@;:]");
+        if (numberParts.length == 0) {
+            return address;
+        }
+        number = numberParts[0];
+
+        // Attempt to format the number in E.164 format and use that as part of the TEL URI.
+        // RFC2806 recommends to format telephone numbers using E.164 since it is independent of
+        // how the dialing of said numbers takes place.
+        // If conversion to E.164 fails, the returned value is null.  In that case, fallback to the
+        // number which was in the CEP data.
+        String formattedNumber = null;
+        if (!TextUtils.isEmpty(countryIso)) {
+            formattedNumber = PhoneNumberUtils.formatNumberToE164(number, countryIso);
+        }
+
+        return Uri.fromParts(PhoneAccount.SCHEME_TEL,
+                formattedNumber != null ? formattedNumber : number, null);
+    }
 }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 47587c5..0983eea 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1793,6 +1793,11 @@
     private ConnectionService mConnectionService;
     private Bundle mExtras;
     private final Object mExtrasLock = new Object();
+    /**
+     * The direction of the connection; used where an existing connection is created and we need to
+     * communicate to Telecom whether its incoming or outgoing.
+     */
+    private @Call.Details.CallDirection int mCallDirection = Call.Details.DIRECTION_UNKNOWN;
 
     /**
      * Tracks the key set for the extras bundle provided on the last invocation of
@@ -3357,4 +3362,21 @@
             l.onConnectionEvent(this, event, extras);
         }
     }
+
+    /**
+     * @return The direction of the call.
+     * @hide
+     */
+    public final @Call.Details.CallDirection int getCallDirection() {
+        return mCallDirection;
+    }
+
+    /**
+     * Sets the direction of this connection.
+     * @param callDirection The direction of this connection.
+     * @hide
+     */
+    public void setCallDirection(@Call.Details.CallDirection int callDirection) {
+        mCallDirection = callDirection;
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 626fcc4..3548810 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2144,7 +2144,8 @@
                     connection.getDisconnectCause(),
                     emptyList,
                     connection.getExtras(),
-                    conferenceId);
+                    conferenceId,
+                    connection.getCallDirection());
             mAdapter.addExistingConnection(id, parcelableConnection);
         }
     }
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index dab1c6e..4734af6 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -53,6 +53,7 @@
     private final List<String> mConferenceableConnectionIds;
     private final Bundle mExtras;
     private String mParentCallId;
+    private @Call.Details.CallDirection int mCallDirection;
 
     /** @hide */
     public ParcelableConnection(
@@ -75,13 +76,15 @@
             DisconnectCause disconnectCause,
             List<String> conferenceableConnectionIds,
             Bundle extras,
-            String parentCallId) {
+            String parentCallId,
+            @Call.Details.CallDirection int callDirection) {
         this(phoneAccount, state, capabilities, properties, supportedAudioRoutes, address,
                 addressPresentation, callerDisplayName, callerDisplayNamePresentation,
                 videoProvider, videoState, ringbackRequested, isVoipAudioMode, connectTimeMillis,
                 connectElapsedTimeMillis, statusHints, disconnectCause, conferenceableConnectionIds,
                 extras);
         mParentCallId = parentCallId;
+        mCallDirection = callDirection;
     }
 
     /** @hide */
@@ -125,6 +128,7 @@
         mConferenceableConnectionIds = conferenceableConnectionIds;
         mExtras = extras;
         mParentCallId = null;
+        mCallDirection = Call.Details.DIRECTION_UNKNOWN;
     }
 
     public PhoneAccountHandle getPhoneAccount() {
@@ -219,6 +223,10 @@
         return mParentCallId;
     }
 
+    public @Call.Details.CallDirection int getCallDirection() {
+        return mCallDirection;
+    }
+
     @Override
     public String toString() {
         return new StringBuilder()
@@ -234,6 +242,8 @@
                 .append(mExtras)
                 .append(", parent:")
                 .append(mParentCallId)
+                .append(", callDirection:")
+                .append(mCallDirection)
                 .toString();
     }
 
@@ -265,6 +275,7 @@
             int supportedAudioRoutes = source.readInt();
             String parentCallId = source.readString();
             long connectElapsedTimeMillis = source.readLong();
+            int callDirection = source.readInt();
 
             return new ParcelableConnection(
                     phoneAccount,
@@ -286,7 +297,8 @@
                     disconnectCause,
                     conferenceableConnectionIds,
                     extras,
-                    parentCallId);
+                    parentCallId,
+                    callDirection);
         }
 
         @Override
@@ -325,5 +337,6 @@
         destination.writeInt(mSupportedAudioRoutes);
         destination.writeString(mParentCallId);
         destination.writeLong(mConnectElapsedTimeMillis);
+        destination.writeInt(mCallDirection);
     }
 }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 518da74..5d39a2c 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -16,8 +16,6 @@
 
 package android.telephony;
 
-import static android.telephony.TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN;
-
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -1607,12 +1605,6 @@
         }
     }
 
-    /** @hide */
-    public static int networkTypeToAccessNetworkType(@TelephonyManager.NetworkType
-            int networkType) {
-        return rilRadioTechnologyToAccessNetworkType(networkTypeToRilRadioTechnology(networkType));
-    }
-
     /**
      * Get current data network type.
      *
@@ -1738,36 +1730,6 @@
         return false;
     }
 
-    /**
-     *
-     * Returns whether the bearerBitmask includes a networkType that matches the accessNetworkType.
-     *
-     * The NetworkType refers to NetworkType in TelephonyManager. For example
-     * {@link TelephonyManager#NETWORK_TYPE_GPRS}.
-     *
-     * The accessNetworkType refers to {@link AccessNetworkType}.
-     *
-     * @hide
-     * */
-    public static boolean networkBitmaskHasAccessNetworkType(
-            @TelephonyManager.NetworkTypeBitMask int networkBitmask, int accessNetworkType) {
-        if (networkBitmask == NETWORK_TYPE_BITMASK_UNKNOWN) return true;
-        if (accessNetworkType == AccessNetworkType.UNKNOWN) return false;
-
-        int networkType = 1;
-        while (networkBitmask != 0) {
-            if ((networkBitmask & 1) != 0) {
-                if (networkTypeToAccessNetworkType(networkType) == accessNetworkType) {
-                    return true;
-                }
-            }
-            networkBitmask = networkBitmask >> 1;
-            networkType++;
-        }
-
-        return false;
-    }
-
     /** @hide */
     public static int getBitmaskForTech(int radioTech) {
         if (radioTech >= 1) {
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 165be64..116c051 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1417,6 +1417,28 @@
         return port == UNSPECIFIED_INT ? null : Integer.toString(port);
     }
 
+    /**
+     * Check if this APN setting can support the given network
+     *
+     * @param networkType The network type
+     * @return {@code true} if this APN setting can support the given network.
+     *
+     * @hide
+     */
+    public boolean canSupportNetworkType(@TelephonyManager.NetworkType int networkType) {
+        // Do a special checking for GSM. In reality, GSM is a voice only network type and can never
+        // be used for data. We allow it here because in some DSDS corner cases, on the non-DDS
+        // sub, modem reports data rat unknown. In that case if voice is GSM and this APN supports
+        // GPRS or EDGE, this APN setting should be selected.
+        if (networkType == TelephonyManager.NETWORK_TYPE_GSM
+                && (mNetworkTypeBitmask & (TelephonyManager.NETWORK_TYPE_BITMASK_GPRS
+                | TelephonyManager.NETWORK_TYPE_BITMASK_EDGE)) != 0) {
+            return true;
+        }
+
+        return ServiceState.bitmaskHasTech(mNetworkTypeBitmask, networkType);
+    }
+
     // Implement Parcelable.
     @Override
     /** @hide */
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 8c024a5..73ee7f5 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.NETID_UNSET;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
@@ -80,13 +81,13 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -141,6 +142,7 @@
 import android.net.NetworkMisc;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.NetworkStack;
 import android.net.NetworkStackClient;
 import android.net.NetworkState;
 import android.net.NetworkUtils;
@@ -154,6 +156,7 @@
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -191,6 +194,7 @@
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.connectivity.Nat464Xlat;
+import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
@@ -282,6 +286,7 @@
     @Mock NetworkStackClient mNetworkStack;
     @Mock PackageManager mPackageManager;
     @Mock UserManager mUserManager;
+    @Mock NotificationManager mNotificationManager;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
             ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -351,7 +356,7 @@
         @Override
         public Object getSystemService(String name) {
             if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
-            if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
+            if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
             if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
             if (Context.USER_SERVICE.equals(name)) return mUserManager;
             return super.getSystemService(name);
@@ -371,7 +376,17 @@
         public PackageManager getPackageManager() {
             return mPackageManager;
         }
-   }
+
+        @Override
+        public void enforceCallingOrSelfPermission(String permission, String message) {
+            // The mainline permission can only be held if signed with the network stack certificate
+            // Skip testing for this permission.
+            if (NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK.equals(permission)) return;
+            // All other permissions should be held by the test or unnecessary: check as normal to
+            // make sure the code does not rely on unexpected permissions.
+            super.enforceCallingOrSelfPermission(permission, message);
+        }
+    }
 
     public void waitForIdle(int timeoutMsAsInt) {
         long timeoutMs = timeoutMsAsInt;
@@ -2856,6 +2871,9 @@
 
         // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
         validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+        // Expect no notification to be shown when captive portal disappears by itself
+        verify(mNotificationManager, never()).notifyAsUser(
+                anyString(), eq(NotificationType.LOGGED_IN.eventId), any(), any());
 
         // Break network connectivity.
         // Expect NET_CAPABILITY_VALIDATED onLost callback.
@@ -2885,6 +2903,8 @@
         // Check that calling startCaptivePortalApp does nothing.
         final int fastTimeoutMs = 100;
         mCm.startCaptivePortalApp(wifiNetwork);
+        waitForIdle();
+        verify(mWiFiNetworkAgent.mNetworkMonitor, never()).launchCaptivePortalApp();
         mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
 
         // Turn into a captive portal.
@@ -2895,14 +2915,26 @@
 
         // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
         mCm.startCaptivePortalApp(wifiNetwork);
-        verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1))
-                .launchCaptivePortalApp();
+        waitForIdle();
+        verify(mWiFiNetworkAgent.mNetworkMonitor).launchCaptivePortalApp();
+
+        // NetworkMonitor uses startCaptivePortal(Network, Bundle) (startCaptivePortalAppInternal)
+        final Bundle testBundle = new Bundle();
+        final String testKey = "testkey";
+        final String testValue = "testvalue";
+        testBundle.putString(testKey, testValue);
+        mCm.startCaptivePortalApp(wifiNetwork, testBundle);
+        final Intent signInIntent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
+        assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, signInIntent.getAction());
+        assertEquals(testValue, signInIntent.getStringExtra(testKey));
 
         // Report that the captive portal is dismissed, and check that callbacks are fired
         mWiFiNetworkAgent.setNetworkValid();
         mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
         validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
         captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+        verify(mNotificationManager, times(1)).notifyAsUser(anyString(),
+                eq(NotificationType.LOGGED_IN.eventId), any(), eq(UserHandle.ALL));
 
         mCm.unregisterNetworkCallback(validatedCallback);
         mCm.unregisterNetworkCallback(captivePortalCallback);
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index daea601..0511f24 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -31,11 +31,8 @@
 import java.util.Objects;
 
 /**
- * Network specifier object used to request a Wi-Fi Aware network. Apps do not create these objects
- * directly but obtain them using
- * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} or
- * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)} or their secure (Passphrase)
- * versions.
+ * Network specifier object used to request a Wi-Fi Aware network. Apps should use the
+ * {@link WifiAwareNetworkSpecifier.Builder} class to create an instance.
  */
 public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable {
     /**