Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
index 3258514c..0ccd951 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7533747"
+    build_id: "7552332"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShimPriv.apk"
   }
@@ -10,4 +10,6 @@
   git_project: "platform/frameworks/base"
   git_branch: "sc-dev"
   transform: TRANSFORM_NONE
+  transform_options {
+  }
 }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
index 4fb50e2..7e85c8f 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7533747"
+    build_id: "7552332"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShim.apk"
   }
@@ -10,4 +10,6 @@
   git_project: "platform/frameworks/base"
   git_branch: "sc-dev"
   transform: TRANSFORM_NONE
+  transform_options {
+  }
 }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
index 1a0e318..20c2785 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7533747"
+    build_id: "7552332"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShimPriv.apk"
   }
@@ -10,4 +10,6 @@
   git_project: "platform/frameworks/base"
   git_branch: "sc-dev"
   transform: TRANSFORM_NONE
+  transform_options {
+  }
 }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
index d72f62e..13e3ae5 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7533747"
+    build_id: "7552332"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShim.apk"
   }
@@ -10,4 +10,6 @@
   git_project: "platform/frameworks/base"
   git_branch: "sc-dev"
   transform: TRANSFORM_NONE
+  transform_options {
+  }
 }
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index d90e129..b4930fa 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2599,11 +2599,11 @@
     public static native long getIonPoolsSizeKb();
 
     /**
-     * Return GPU DMA buffer usage in kB or -1 on error.
+     * Returns the global total GPU-private memory in kB or -1 on error.
      *
      * @hide
      */
-    public static native long getGpuDmaBufUsageKb();
+    public static native long getGpuPrivateMemoryKb();
 
     /**
      * Return DMA-BUF memory mapped by processes in kB.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b191dfc..ac520e8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9660,13 +9660,6 @@
         public static final String QS_AUTO_ADDED_TILES = "qs_auto_tiles";
 
         /**
-         * Whether the Lockdown button should be shown in the power menu.
-         * @hide
-         */
-        @Readable
-        public static final String LOCKDOWN_IN_POWER_MENU = "lockdown_in_power_menu";
-
-        /**
          * Backup manager behavioral parameters.
          * This is encoded as a key=value list, separated by commas. Ex:
          *
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index a6ec399..362ea8c 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -115,18 +115,14 @@
             @NonNull AttributionSource attributionSource) {
         try {
             if (mCurrentCallback == null) {
-                Context attributionContext = createContext(new ContextParams.Builder()
-                        .setNextAttributionSource(attributionSource)
-                        .build());
                 boolean preflightPermissionCheckPassed = checkPermissionForPreflight(
-                        attributionContext.getAttributionSource());
+                        attributionSource);
                 if (preflightPermissionCheckPassed) {
                     if (DBG) {
                         Log.d(TAG, "created new mCurrentCallback, listener = "
                                 + listener.asBinder());
                     }
-                    mCurrentCallback = new Callback(listener, attributionSource,
-                            attributionContext);
+                    mCurrentCallback = new Callback(listener, attributionSource);
                     RecognitionService.this.onStartListening(intent, mCurrentCallback);
                 }
 
@@ -293,15 +289,8 @@
 
         private Callback(IRecognitionListener listener,
                 @NonNull AttributionSource attributionSource) {
-            this(listener, attributionSource, null);
-        }
-
-        private Callback(IRecognitionListener listener,
-                @NonNull AttributionSource attributionSource,
-                @Nullable Context attributionContext) {
             mListener = listener;
             mCallingAttributionSource = attributionSource;
-            mAttributionContext = attributionContext;
         }
 
         /**
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 125182c..91a19e0 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -237,7 +237,6 @@
             ],
 
             shared_libs: [
-                "android.hardware.memtrack-V1-ndk_platform",
                 "audioclient-types-aidl-cpp",
                 "audioflinger-aidl-cpp",
                 "av-types-aidl-cpp",
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 4180448..4c2b114 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -33,7 +33,6 @@
 #include <string>
 #include <vector>
 
-#include <aidl/android/hardware/memtrack/DeviceInfo.h>
 #include <android-base/logging.h>
 #include <bionic/malloc.h>
 #include <debuggerd/client.h>
@@ -46,7 +45,6 @@
 #include "jni.h"
 #include <dmabufinfo/dmabuf_sysfs_stats.h>
 #include <dmabufinfo/dmabufinfo.h>
-#include <dmabufinfo/dmabuf_sysfs_stats.h>
 #include <meminfo/procmeminfo.h>
 #include <meminfo/sysmeminfo.h>
 #include <memtrack/memtrack.h>
@@ -861,29 +859,24 @@
     return poolsSizeKb;
 }
 
-static jlong android_os_Debug_getGpuDmaBufUsageKb(JNIEnv* env, jobject clazz) {
-    std::vector<aidl::android::hardware::memtrack::DeviceInfo> gpu_device_info;
-    if (!memtrack_gpu_device_info(&gpu_device_info)) {
+static jlong android_os_Debug_getGpuPrivateMemoryKb(JNIEnv* env, jobject clazz) {
+    struct memtrack_proc* p = memtrack_proc_new();
+    if (p == nullptr) {
+        LOG(ERROR) << "getGpuPrivateMemoryKb: Failed to create memtrack_proc";
         return -1;
     }
 
-    dmabufinfo::DmabufSysfsStats stats;
-    if (!GetDmabufSysfsStats(&stats)) {
+    // Memtrack hal defines PID 0 as global total for GPU-private (GL) memory.
+    if (memtrack_proc_get(p, 0) != 0) {
+        // The memtrack HAL may not be available, avoid flooding the log.
+        memtrack_proc_destroy(p);
         return -1;
     }
 
-    jlong sizeKb = 0;
-    const auto& importer_stats = stats.importer_info();
-    for (const auto& dev_info : gpu_device_info) {
-        const auto& importer_info = importer_stats.find(dev_info.name);
-        if (importer_info == importer_stats.end()) {
-            continue;
-        }
+    ssize_t gpuPrivateMem = memtrack_proc_gl_pss(p);
 
-        sizeKb += importer_info->second.size / 1024;
-    }
-
-    return sizeKb;
+    memtrack_proc_destroy(p);
+    return gpuPrivateMem / 1024;
 }
 
 static jlong android_os_Debug_getDmabufMappedSizeKb(JNIEnv* env, jobject clazz) {
@@ -994,8 +987,8 @@
             (void*)android_os_Debug_getIonHeapsSizeKb },
     { "getDmabufTotalExportedKb", "()J",
             (void*)android_os_Debug_getDmabufTotalExportedKb },
-    { "getGpuDmaBufUsageKb", "()J",
-            (void*)android_os_Debug_getGpuDmaBufUsageKb },
+    { "getGpuPrivateMemoryKb", "()J",
+            (void*)android_os_Debug_getGpuPrivateMemoryKb },
     { "getDmabufHeapTotalExportedKb", "()J",
             (void*)android_os_Debug_getDmabufHeapTotalExportedKb },
     { "getIonPoolsSizeKb", "()J",
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 088495e..542387f 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2012,7 +2012,7 @@
     <string name="app_category_productivity" msgid="1844422703029557883">"Effizienz"</string>
     <string name="app_category_accessibility" msgid="6643521607848547683">"Bedienungshilfen"</string>
     <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Gerätespeicher"</string>
-    <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-Fehlerbehebung"</string>
+    <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-Debugging"</string>
     <string name="time_picker_hour_label" msgid="4208590187662336864">"Stunde"</string>
     <string name="time_picker_minute_label" msgid="8307452311269824553">"Minute"</string>
     <string name="time_picker_header_text" msgid="9073802285051516688">"Uhrzeit einstellen"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index a922637..30a62e3 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -437,7 +437,7 @@
     <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"位置情報提供者の追加コマンドアクセス"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"位置情報提供元の追加のコマンドにアクセスすることをアプリに許可します。許可すると、アプリがGPSなどの位置情報源の動作を妨害する恐れがあります。"</string>
     <string name="permlab_accessFineLocation" msgid="6426318438195622966">"フォアグラウンドでのみ正確な位置情報にアクセス"</string>
-    <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"このアプリは、使用中に、位置情報サービスからデバイスの正確な位置情報を取得できます。アプリが位置情報を取得するには、デバイスで位置情報サービスがオンになっている必要があります。この場合、バッテリー使用量が増えることがあります。"</string>
+    <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"このアプリは、使用中に、位置情報サービスからデバイスの正確な位置情報を取得できます。アプリが位置情報を取得するには、デバイスで位置情報サービスが ON になっている必要があります。この場合、バッテリー使用量が増えることがあります。"</string>
     <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"フォアグラウンドでのみおおよその位置情報にアクセス"</string>
     <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"このアプリは、使用中に、位置情報サービスからデバイスのおおよその位置情報を取得できます。アプリが位置情報を取得するには、デバイスで位置情報サービスがオンになっている必要があります。"</string>
     <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"バックグラウンドでの位置情報へのアクセス"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 209c6a1..86a9c3f 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -815,7 +815,7 @@
     <string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
     <string name="phoneTypeWorkMobile" msgid="7522314392003565121">"ਕੰਮ ਦਾ ਮੋਬਾਈਲ"</string>
     <string name="phoneTypeWorkPager" msgid="3748332310638505234">"ਦਫ਼ਤਰ ਦਾ ਪੇਜਰ"</string>
-    <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
+    <string name="phoneTypeAssistant" msgid="757550783842231039">"ਸਹਾਇਕ"</string>
     <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
     <string name="eventTypeCustom" msgid="3257367158986466481">"ਵਿਉਂਂਤੀ"</string>
     <string name="eventTypeBirthday" msgid="7770026752793912283">"ਜਨਮਦਿਨ"</string>
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index ef3a11c..c4cdb7d 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -762,9 +762,11 @@
 
     // Create an ImageReader wired up to a BufferItemConsumer
     AImageReader* rawReader;
+    constexpr auto usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+                           AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
+                           AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY;
     media_status_t result =
-            AImageReader_newWithUsage(width, height, AIMAGE_FORMAT_RGBA_8888,
-                                      AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE, 2, &rawReader);
+            AImageReader_newWithUsage(width, height, AIMAGE_FORMAT_RGBA_8888, usage, 2, &rawReader);
     std::unique_ptr<AImageReader, decltype(&AImageReader_delete)> reader(rawReader,
                                                                          AImageReader_delete);
 
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 59ef4b8..8b69d33 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -148,6 +148,7 @@
     LnbCallback mCallback;
     Executor mExecutor;
     Tuner mTuner;
+    private final Object mCallbackLock = new Object();
 
 
     private native int nativeSetVoltage(int voltage);
@@ -164,20 +165,26 @@
     private Lnb() {}
 
     void setCallback(Executor executor, @Nullable LnbCallback callback, Tuner tuner) {
-        mCallback = callback;
-        mExecutor = executor;
-        mTuner = tuner;
+        synchronized (mCallbackLock) {
+            mCallback = callback;
+            mExecutor = executor;
+            mTuner = tuner;
+        }
     }
 
     private void onEvent(int eventType) {
-        if (mExecutor != null && mCallback != null) {
-            mExecutor.execute(() -> mCallback.onEvent(eventType));
+        synchronized (mCallbackLock) {
+            if (mExecutor != null && mCallback != null) {
+                mExecutor.execute(() -> mCallback.onEvent(eventType));
+            }
         }
     }
 
     private void onDiseqcMessage(byte[] diseqcMessage) {
-        if (mExecutor != null && mCallback != null) {
-            mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage));
+        synchronized (mCallbackLock) {
+            if (mExecutor != null && mCallback != null) {
+                mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage));
+            }
         }
     }
 
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 2ea745b..3254366 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -291,7 +291,7 @@
     @Nullable
     private OnTuneEventListener mOnTuneEventListener;
     @Nullable
-    private Executor mOnTunerEventExecutor;
+    private Executor mOnTuneEventExecutor;
     @Nullable
     private ScanCallback mScanCallback;
     @Nullable
@@ -301,6 +301,10 @@
     @Nullable
     private Executor mOnResourceLostListenerExecutor;
 
+    private final Object mOnTuneEventLock = new Object();
+    private final Object mScanCallbackLock = new Object();
+    private final Object mOnResourceLostListenerLock = new Object();
+
     private Integer mDemuxHandle;
     private Integer mFrontendCiCamHandle;
     private Integer mFrontendCiCamId;
@@ -398,18 +402,22 @@
      */
     public void setResourceLostListener(@NonNull @CallbackExecutor Executor executor,
             @NonNull OnResourceLostListener listener) {
-        Objects.requireNonNull(executor, "OnResourceLostListener must not be null");
-        Objects.requireNonNull(listener, "executor must not be null");
-        mOnResourceLostListener = listener;
-        mOnResourceLostListenerExecutor = executor;
+        synchronized (mOnResourceLostListenerLock) {
+            Objects.requireNonNull(executor, "OnResourceLostListener must not be null");
+            Objects.requireNonNull(listener, "executor must not be null");
+            mOnResourceLostListener = listener;
+            mOnResourceLostListenerExecutor = executor;
+        }
     }
 
     /**
      * Removes the listener for resource lost.
      */
     public void clearResourceLostListener() {
-        mOnResourceLostListener = null;
-        mOnResourceLostListenerExecutor = null;
+        synchronized (mOnResourceLostListenerLock) {
+            mOnResourceLostListener = null;
+            mOnResourceLostListenerExecutor = null;
+        }
     }
 
     /**
@@ -618,10 +626,12 @@
                     break;
                 }
                 case MSG_RESOURCE_LOST: {
-                    if (mOnResourceLostListener != null
+                    synchronized (mOnResourceLostListenerLock) {
+                        if (mOnResourceLostListener != null
                                 && mOnResourceLostListenerExecutor != null) {
-                        mOnResourceLostListenerExecutor.execute(
-                                () -> mOnResourceLostListener.onResourceLost(Tuner.this));
+                            mOnResourceLostListenerExecutor.execute(
+                                    () -> mOnResourceLostListener.onResourceLost(Tuner.this));
+                        }
                     }
                     break;
                 }
@@ -652,8 +662,10 @@
      */
     public void setOnTuneEventListener(@NonNull @CallbackExecutor Executor executor,
             @NonNull OnTuneEventListener eventListener) {
-        mOnTuneEventListener = eventListener;
-        mOnTunerEventExecutor = executor;
+        synchronized (mOnTuneEventLock) {
+            mOnTuneEventListener = eventListener;
+            mOnTuneEventExecutor = executor;
+        }
     }
 
     /**
@@ -663,9 +675,10 @@
      * @see #setOnTuneEventListener(Executor, OnTuneEventListener)
      */
     public void clearOnTuneEventListener() {
-        mOnTuneEventListener = null;
-        mOnTunerEventExecutor = null;
-
+        synchronized (mOnTuneEventLock) {
+            mOnTuneEventListener = null;
+            mOnTuneEventExecutor = null;
+        }
     }
 
     /**
@@ -747,32 +760,34 @@
     @Result
     public int scan(@NonNull FrontendSettings settings, @ScanType int scanType,
             @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) {
-        /**
-         * Scan can be called again for blink scan if scanCallback and executor are same as before.
-         */
-        if (((mScanCallback != null) && (mScanCallback != scanCallback))
+        synchronized (mScanCallbackLock) {
+            // Scan can be called again for blink scan if scanCallback and executor are same as
+            //before.
+            if (((mScanCallback != null) && (mScanCallback != scanCallback))
                 || ((mScanCallbackExecutor != null) && (mScanCallbackExecutor != executor))) {
-            throw new IllegalStateException(
+                throw new IllegalStateException(
                     "Different Scan session already in progress.  stopScan must be called "
                         + "before a new scan session can be " + "started.");
-        }
-        mFrontendType = settings.getType();
-        if (mFrontendType == FrontendSettings.TYPE_DTMB) {
-            if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
-                    TunerVersionChecker.TUNER_VERSION_1_1, "Scan with DTMB Frontend")) {
-                return RESULT_UNAVAILABLE;
             }
-        }
-        if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
-            mScanCallback = scanCallback;
-            mScanCallbackExecutor = executor;
-            mFrontendInfo = null;
-            FrameworkStatsLog
+            mFrontendType = settings.getType();
+            if (mFrontendType == FrontendSettings.TYPE_DTMB) {
+                if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                        TunerVersionChecker.TUNER_VERSION_1_1,
+                        "Scan with DTMB Frontend")) {
+                    return RESULT_UNAVAILABLE;
+                }
+            }
+            if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
+                mScanCallback = scanCallback;
+                mScanCallbackExecutor = executor;
+                mFrontendInfo = null;
+                FrameworkStatsLog
                     .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
                         FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCANNING);
-            return nativeScan(settings.getType(), settings, scanType);
+                return nativeScan(settings.getType(), settings, scanType);
+            }
+            return RESULT_UNAVAILABLE;
         }
-        return RESULT_UNAVAILABLE;
     }
 
     /**
@@ -788,14 +803,15 @@
      */
     @Result
     public int cancelScanning() {
-        FrameworkStatsLog
-                .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+        synchronized (mScanCallbackLock) {
+            FrameworkStatsLog.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
                     FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCAN_STOPPED);
 
-        int retVal = nativeStopScan();
-        mScanCallback = null;
-        mScanCallbackExecutor = null;
-        return retVal;
+            int retVal = nativeStopScan();
+            mScanCallback = null;
+            mScanCallbackExecutor = null;
+            return retVal;
+        }
     }
 
     private boolean requestFrontend() {
@@ -1050,8 +1066,10 @@
 
     private void onFrontendEvent(int eventType) {
         Log.d(TAG, "Got event from tuning. Event type: " + eventType);
-        if (mOnTunerEventExecutor != null && mOnTuneEventListener != null) {
-            mOnTunerEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType));
+        synchronized (mOnTuneEventLock) {
+            if (mOnTuneEventExecutor != null && mOnTuneEventListener != null) {
+                mOnTuneEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType));
+            }
         }
 
         Log.d(TAG, "Wrote Stats Log for the events from tuning.");
@@ -1072,114 +1090,149 @@
 
     private void onLocked() {
         Log.d(TAG, "Wrote Stats Log for locked event from scanning.");
-        FrameworkStatsLog
-                .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
-                    FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
+        FrameworkStatsLog.write(
+                FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+                FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
 
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onLocked());
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onLocked());
+            }
         }
     }
 
     private void onScanStopped() {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped());
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped());
+            }
         }
     }
 
     private void onProgress(int percent) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent));
+            }
         }
     }
 
     private void onFrequenciesReport(int[] frequency) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency));
+            }
         }
     }
 
     private void onSymbolRates(int[] rate) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate));
+            }
         }
     }
 
     private void onHierarchy(int hierarchy) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy));
+            }
         }
     }
 
     private void onSignalType(int signalType) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType));
+            }
         }
     }
 
     private void onPlpIds(int[] plpIds) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds));
+            }
         }
     }
 
     private void onGroupIds(int[] groupIds) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds));
+            }
         }
     }
 
     private void onInputStreamIds(int[] inputStreamIds) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(
-                    () -> mScanCallback.onInputStreamIdsReported(inputStreamIds));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(
+                        () -> mScanCallback.onInputStreamIdsReported(inputStreamIds));
+            }
         }
     }
 
     private void onDvbsStandard(int dvbsStandandard) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(
-                    () -> mScanCallback.onDvbsStandardReported(dvbsStandandard));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(
+                        () -> mScanCallback.onDvbsStandardReported(dvbsStandandard));
+            }
         }
     }
 
     private void onDvbtStandard(int dvbtStandard) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onDvbtStandardReported(dvbtStandard));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(
+                        () -> mScanCallback.onDvbtStandardReported(dvbtStandard));
+            }
         }
     }
 
     private void onAnalogSifStandard(int sif) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif));
+            }
         }
     }
 
     private void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(
-                    () -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(
+                        () -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos));
+            }
         }
     }
 
     private void onModulationReported(int modulation) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(
-                    () -> mScanCallback.onModulationReported(modulation));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(
+                        () -> mScanCallback.onModulationReported(modulation));
+            }
         }
     }
 
     private void onPriorityReported(boolean isHighPriority) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(
-                    () -> mScanCallback.onPriorityReported(isHighPriority));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(
+                        () -> mScanCallback.onPriorityReported(isHighPriority));
+            }
         }
     }
 
     private void onDvbcAnnexReported(int dvbcAnnex) {
-        if (mScanCallbackExecutor != null && mScanCallback != null) {
-            mScanCallbackExecutor.execute(
-                    () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex));
+        synchronized (mScanCallbackLock) {
+            if (mScanCallbackExecutor != null && mScanCallback != null) {
+                mScanCallbackExecutor.execute(
+                        () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex));
+            }
         }
     }
 
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index d70b8c2..1f805d7 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -85,6 +85,7 @@
     private static int sInstantId = 0;
     private int mSegmentId = 0;
     private int mUnderflow;
+    private final Object mListenerLock = new Object();
 
     private native int nativeAttachFilter(Filter filter);
     private native int nativeDetachFilter(Filter filter);
@@ -106,16 +107,20 @@
     /** @hide */
     public void setListener(
             @NonNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener) {
-        mExecutor = executor;
-        mListener = listener;
+        synchronized (mListenerLock) {
+            mExecutor = executor;
+            mListener = listener;
+        }
     }
 
     private void onPlaybackStatusChanged(int status) {
         if (status == PLAYBACK_STATUS_EMPTY) {
             mUnderflow++;
         }
-        if (mExecutor != null && mListener != null) {
-            mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
+        synchronized (mListenerLock) {
+            if (mExecutor != null && mListener != null) {
+                mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
+            }
         }
     }
 
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 0f9f2e7..2b69466 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -48,6 +48,7 @@
     private int mSegmentId = 0;
     private int mOverflow;
     private Boolean mIsStopped = true;
+    private final Object mListenerLock = new Object();
 
     private native int nativeAttachFilter(Filter filter);
     private native int nativeDetachFilter(Filter filter);
@@ -69,16 +70,20 @@
     /** @hide */
     public void setListener(
             @NonNull Executor executor, @NonNull OnRecordStatusChangedListener listener) {
-        mExecutor = executor;
-        mListener = listener;
+        synchronized (mListenerLock) {
+            mExecutor = executor;
+            mListener = listener;
+        }
     }
 
     private void onRecordStatusChanged(int status) {
         if (status == Filter.STATUS_OVERFLOW) {
             mOverflow++;
         }
-        if (mExecutor != null && mListener != null) {
-            mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
+        synchronized (mListenerLock) {
+            if (mExecutor != null && mListener != null) {
+                mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
+            }
         }
     }
 
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 2f3e2d8..33742ff 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -227,6 +227,7 @@
     private long mNativeContext;
     private FilterCallback mCallback;
     private Executor mExecutor;
+    private final Object mCallbackLock = new Object();
     private final long mId;
     private int mMainType;
     private int mSubtype;
@@ -253,14 +254,18 @@
     }
 
     private void onFilterStatus(int status) {
-        if (mCallback != null && mExecutor != null) {
-            mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status));
+        synchronized (mCallbackLock) {
+            if (mCallback != null && mExecutor != null) {
+                mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status));
+            }
         }
     }
 
     private void onFilterEvent(FilterEvent[] events) {
-        if (mCallback != null && mExecutor != null) {
-            mExecutor.execute(() -> mCallback.onFilterEvent(this, events));
+        synchronized (mCallbackLock) {
+            if (mCallback != null && mExecutor != null) {
+                mExecutor.execute(() -> mCallback.onFilterEvent(this, events));
+            }
         }
     }
 
@@ -272,13 +277,17 @@
 
     /** @hide */
     public void setCallback(FilterCallback cb, Executor executor) {
-        mCallback = cb;
-        mExecutor = executor;
+        synchronized (mCallbackLock) {
+            mCallback = cb;
+            mExecutor = executor;
+        }
     }
 
     /** @hide */
     public FilterCallback getCallback() {
-        return mCallback;
+        synchronized (mCallbackLock) {
+            return mCallback;
+        }
     }
 
     /**
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index e88e1ba..0c3c4bb 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index f35732c..ee42d08 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index e88e1ba..0c3c4bb 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index 3d9f749..2bb3750 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index ae6165b..6022608 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -123,7 +123,6 @@
         Settings.Secure.SCREENSAVER_COMPONENTS,
         Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
         Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
-        Settings.Secure.LOCKDOWN_IN_POWER_MENU,
         Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
         Settings.Secure.VOLUME_HUSH_GESTURE,
         Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index e09d420..6d7fb02 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -177,7 +177,6 @@
         VALIDATORS.put(Secure.SCREENSAVER_COMPONENTS, COMMA_SEPARATED_COMPONENT_LIST_VALIDATOR);
         VALIDATORS.put(Secure.SCREENSAVER_ACTIVATE_ON_DOCK, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(Secure.LOCKDOWN_IN_POWER_MENU, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.VOLUME_HUSH_GESTURE, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e5eecb2..073b4d0 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2224,9 +2224,6 @@
                 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
                 SecureSettingsProto.LOCK_TO_APP_EXIT_LOCKED);
         dumpSetting(s, p,
-                Settings.Secure.LOCKDOWN_IN_POWER_MENU,
-                SecureSettingsProto.LOCKDOWN_IN_POWER_MENU);
-        dumpSetting(s, p,
                 Settings.Secure.LONG_PRESS_TIMEOUT,
                 SecureSettingsProto.LONG_PRESS_TIMEOUT);
 
diff --git a/packages/Shell/res/values-ta/strings.xml b/packages/Shell/res/values-ta/strings.xml
index 30d0873..72698ba 100644
--- a/packages/Shell/res/values-ta/strings.xml
+++ b/packages/Shell/res/values-ta/strings.xml
@@ -28,7 +28,7 @@
     <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"ஸ்கிரீன்ஷாட் இன்றி பிழை அறிக்கையை பகிர தேர்ந்தெடுக்கவும்/ஸ்கிரீன்ஷாட் முடியும்வரை காத்திருக்கவும்"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"ஸ்கிரீன்ஷாட் இல்லாமல் பிழை அறிக்கையைப் பகிர, தட்டவும் அல்லது ஸ்கிரீன்ஷாட் முடியும்வரை காத்திருக்கவும்"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"ஸ்கிரீன்ஷாட் இல்லாமல் பிழை அறிக்கையைப் பகிர, தட்டவும் அல்லது ஸ்கிரீன்ஷாட் முடியும்வரை காத்திருக்கவும்"</string>
-    <string name="bugreport_confirm" msgid="5917407234515812495">"பிழை அறிக்கைகளில் முறைமையின் பல்வேறு பதிவுக் கோப்புகளின் தரவு (இதில் முக்கியமானவை என நீங்கள் கருதும் பயன்பாடின் உபயோகம், இருப்பிடத் தரவு போன்றவை அடங்கும்) இருக்கும். நீங்கள் நம்பும் நபர்கள் மற்றும் பயன்பாடுகளுடன் மட்டும் பிழை அறிக்கைகளைப் பகிரவும்."</string>
+    <string name="bugreport_confirm" msgid="5917407234515812495">"பிழை அறிக்கைகளில் முறைமையின் பல்வேறு பதிவு ஃபைல்களின் தரவு (இதில் முக்கியமானவை என நீங்கள் கருதும் பயன்பாடின் உபயோகம், இருப்பிடத் தரவு போன்றவை அடங்கும்) இருக்கும். நீங்கள் நம்பும் நபர்கள் மற்றும் பயன்பாடுகளுடன் மட்டும் பிழை அறிக்கைகளைப் பகிரவும்."</string>
     <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"மீண்டும் காட்டாதே"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"பிழை அறிக்கைகள்"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"பிழை அறிக்கையைப் படிக்க முடியவில்லை"</string>
diff --git a/packages/SystemUI/res/drawable/fingerprint_bg.xml b/packages/SystemUI/res/drawable/fingerprint_bg.xml
index 558ec08..2b0ab6f 100644
--- a/packages/SystemUI/res/drawable/fingerprint_bg.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_bg.xml
@@ -14,11 +14,10 @@
 -->
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:shape="oval">
 
     <solid
-      android:color="?androidprv:attr/colorSurface"/>
+      android:color="?android:attr/colorBackground"/>
 
     <size
         android:width="64dp"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index b0f1f48..1a91202 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -55,23 +55,9 @@
         android:id="@+id/lock_icon_view"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center">
-        <!-- Background protection -->
-        <ImageView
-            android:id="@+id/lock_icon_bg"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="@drawable/fingerprint_bg"
-            android:visibility="invisible"/>
-
-        <ImageView
-            android:id="@+id/lock_icon"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:padding="48px"
-            android:layout_gravity="center"
-            android:scaleType="centerCrop"/>
-    </com.android.keyguard.LockIconView>
+        android:padding="48px"
+        android:layout_gravity="center"
+        android:scaleType="centerCrop"/>
 
     <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 2fe583a6a..46aea06 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1149,8 +1149,7 @@
     <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> একটি মেসেজ পাঠিয়েছেন: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> একটি ছবি পাঠিয়েছেন"</string>
     <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> একটি স্ট্যাটাস আপডেট করেছেন: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
-    <!-- no translation found for person_available (2318599327472755472) -->
-    <skip />
+    <string name="person_available" msgid="2318599327472755472">"উপস্থিত আছেন"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ব্যাটারির মিটারের রিডিং নেওয়ার সময় সমস্যা হয়েছে"</string>
     <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"আরও তথ্যের জন্য ট্যাপ করুন"</string>
     <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"কোনও অ্যালার্ম সেট করা নেই"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 59eceb7..b29a528 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1149,8 +1149,7 @@
     <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ સંદેશ મોકલવામાં આવ્યો: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ છબી મોકલવામાં આવી"</string>
     <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા નવી સ્ટેટસ અપડેટ પોસ્ટ કરવામાં આવી: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
-    <!-- no translation found for person_available (2318599327472755472) -->
-    <skip />
+    <string name="person_available" msgid="2318599327472755472">"ઉપલબ્ધ છે"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"તમારું બૅટરી મીટર વાંચવામાં સમસ્યા આવી"</string>
     <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"વધુ માહિતી માટે ટૅપ કરો"</string>
     <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"કોઈ અલાર્મ સેટ નથી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index abbb46a..1d56cd6 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1149,7 +1149,7 @@
     <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ने एक मैसेज भेजा है: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ने एक इमेज भेजी है"</string>
     <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ने स्टेटस अपडेट किया है: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
-    <string name="person_available" msgid="2318599327472755472">"ऑनलाइन हैं"</string>
+    <string name="person_available" msgid="2318599327472755472">"ऑनलाइन है"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"आपके डिवाइस के बैटरी मीटर की रीडिंग लेने में समस्या आ रही है"</string>
     <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ज़्यादा जानकारी के लिए टैप करें"</string>
     <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"कोई अलार्म सेट नहीं है"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index cd3966d..9578370 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -272,9 +272,9 @@
     <string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"ब्लूटूथ कनेक्‍ट केले."</string>
     <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"ब्लूटूथ बंद केले."</string>
     <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"ब्लूटूथ सुरू केले."</string>
-    <string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"स्थान अहवाल बंद."</string>
-    <string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"स्थान अहवाल सुरू."</string>
-    <string name="accessibility_quick_settings_location_changed_off" msgid="5132776369388699133">"स्थान अहवाल बंद केला."</string>
+    <string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"स्थान अहवाल देणे बंद."</string>
+    <string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"स्थान अहवाल देणे सुरू."</string>
+    <string name="accessibility_quick_settings_location_changed_off" msgid="5132776369388699133">"स्थान अहवाल देणे बंद केले."</string>
     <string name="accessibility_quick_settings_location_changed_on" msgid="7159115433070112154">"स्थान अहवाल देणे सुरू केले."</string>
     <string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g> साठी अलार्म सेट केला."</string>
     <string name="accessibility_quick_settings_close" msgid="2974895537860082341">"पॅनल बंद करा."</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 708462f..45c4f0f 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1149,8 +1149,7 @@
     <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਸੁਨੇਹਾ ਭੇਜਿਆ: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
     <string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਇੱਕ ਚਿੱਤਰ ਭੇਜਿਆ ਹੈ"</string>
     <string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> ਨੇ ਸਥਿਤੀ ਅੱਪਡੇਟ ਕੀਤੀ ਹੈ: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
-    <!-- no translation found for person_available (2318599327472755472) -->
-    <skip />
+    <string name="person_available" msgid="2318599327472755472">"ਉਪਲਬਧ"</string>
     <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ਤੁਹਾਡੇ ਬੈਟਰੀ ਮੀਟਰ ਨੂੰ ਪੜ੍ਹਨ ਵਿੱਚ ਸਮੱਸਿਆ ਹੋ ਰਹੀ ਹੈ"</string>
     <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"ਕੋਈ ਅਲਾਰਮ ਸੈੱਟ ਨਹੀਂ"</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index 867e3ae..c1d448d 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -16,29 +16,16 @@
 
 package com.android.keyguard;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ArgbEvaluator;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.graphics.PointF;
 import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.view.View;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
 import androidx.annotation.NonNull;
 
-import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
-import com.android.systemui.R;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -46,96 +33,16 @@
 /**
  * A view positioned under the notification shade.
  */
-public class LockIconView extends FrameLayout implements Dumpable {
+public class LockIconView extends ImageView implements Dumpable {
     @NonNull private final RectF mSensorRect;
     @NonNull private PointF mLockIconCenter = new PointF(0f, 0f);
     private int mRadius;
 
-    private ImageView mLockIcon;
-    private ImageView mUnlockBgView;
-
-    private AnimatorSet mBgAnimator;
-    private int mLockIconColor;
-    private int mUnlockStartColor;
-    private int mUnlockEndColor;
-
     public LockIconView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mSensorRect = new RectF();
     }
 
-    @Override
-    public void onFinishInflate() {
-        super.onFinishInflate();
-        mLockIcon = findViewById(R.id.lock_icon);
-        mUnlockBgView = findViewById(R.id.lock_icon_bg);
-    }
-
-    void updateColor() {
-        mLockIconColor = Utils.getColorAttrDefaultColor(getContext(),
-            R.attr.wallpaperTextColorAccent);
-        mUnlockStartColor = mLockIconColor;
-        mUnlockEndColor = Utils.getColorAttrDefaultColor(getContext(),
-            android.R.attr.textColorPrimary);
-        mUnlockBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
-    }
-
-    void setImageDrawable(Drawable drawable) {
-        mLockIcon.setImageDrawable(drawable);
-    }
-
-    void hideBg() {
-        mUnlockBgView.setVisibility(View.INVISIBLE);
-        mLockIcon.setImageTintList(ColorStateList.valueOf(mLockIconColor));
-    }
-
-    void animateBg() {
-        ValueAnimator bgAlphaAnimator = ObjectAnimator.ofFloat(mUnlockBgView, View.ALPHA, 0f, 1f);
-        bgAlphaAnimator.setDuration(133);
-
-        Interpolator interpolator = new PathInterpolator(0f, 0f, 0f, 1f);
-        Animator scaleXAnimator = ObjectAnimator.ofFloat(mUnlockBgView, View.SCALE_X, .9f, 1f);
-        scaleXAnimator.setInterpolator(interpolator);
-        scaleXAnimator.setDuration(300);
-        Animator scaleYAnimator = ObjectAnimator.ofFloat(mUnlockBgView, View.SCALE_Y, .9f, 1f);
-        scaleYAnimator.setDuration(300);
-        scaleYAnimator.setInterpolator(interpolator);
-
-        ValueAnimator lockIconColorAnimator =
-                ValueAnimator.ofObject(new ArgbEvaluator(), mUnlockStartColor, mUnlockEndColor);
-        lockIconColorAnimator.addUpdateListener(
-                animation -> mLockIcon.setImageTintList(
-                    ColorStateList.valueOf((int) animation.getAnimatedValue())));
-        lockIconColorAnimator.setDuration(150);
-
-        if (mBgAnimator != null) {
-            if (mBgAnimator.isRunning()) {
-                return;
-            }
-            mBgAnimator.cancel();
-        }
-        mBgAnimator = new AnimatorSet();
-        mBgAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                mBgAnimator = null;
-            }
-        });
-        mBgAnimator.playTogether(
-                bgAlphaAnimator,
-                scaleYAnimator,
-                scaleXAnimator,
-                lockIconColorAnimator);
-        mBgAnimator.setStartDelay(167);
-        mUnlockBgView.setAlpha(0f);
-        mUnlockBgView.setScaleX(0);
-        mUnlockBgView.setScaleY(0);
-        mUnlockBgView.setVisibility(View.VISIBLE);
-
-        mBgAnimator.start();
-    }
-
     void setCenterLocation(@NonNull PointF center, int radius) {
         mLockIconCenter = center;
         mRadius = radius;
@@ -163,6 +70,7 @@
         return mLockIconCenter.y - mRadius;
     }
 
+
     @Override
     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("Center in px (x, y)= (" + mLockIconCenter.x + ", " + mLockIconCenter.y + ")");
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index a7bd4c8..373d4df 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -28,6 +28,9 @@
 import android.graphics.drawable.Drawable;
 import android.hardware.biometrics.BiometricSourceType;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.media.AudioAttributes;
+import android.os.Process;
+import android.os.Vibrator;
 import android.util.DisplayMetrics;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
@@ -40,9 +43,11 @@
 import androidx.annotation.Nullable;
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.UdfpsController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.FalsingManager;
@@ -67,6 +72,13 @@
  */
 @StatusBarComponent.StatusBarScope
 public class LockIconViewController extends ViewController<LockIconView> implements Dumpable {
+
+    private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
+            new AudioAttributes.Builder()
+                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                .build();
+
     @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @NonNull private final KeyguardViewController mKeyguardViewController;
     @NonNull private final StatusBarStateController mStatusBarStateController;
@@ -83,6 +95,7 @@
     @NonNull private final Drawable mLockIcon;
     @NonNull private final CharSequence mUnlockedLabel;
     @NonNull private final CharSequence mLockedLabel;
+    @Nullable private final Vibrator mVibrator;
 
     private boolean mIsDozing;
     private boolean mIsBouncerShowing;
@@ -119,7 +132,8 @@
             @NonNull DumpManager dumpManager,
             @NonNull AccessibilityManager accessibilityManager,
             @NonNull ConfigurationController configurationController,
-            @NonNull @Main DelayableExecutor executor
+            @NonNull @Main DelayableExecutor executor,
+            @Nullable Vibrator vibrator
     ) {
         super(view);
         mStatusBarStateController = statusBarStateController;
@@ -131,6 +145,7 @@
         mAccessibilityManager = accessibilityManager;
         mConfigurationController = configurationController;
         mExecutor = executor;
+        mVibrator = vibrator;
 
         final Context context = view.getContext();
         mLockIcon = mView.getContext().getResources().getDrawable(
@@ -144,7 +159,6 @@
         mUnlockedLabel = context.getResources().getString(R.string.accessibility_unlock_button);
         mLockedLabel = context.getResources().getString(R.string.accessibility_lock_icon);
         dumpManager.registerDumpable("LockIconViewController", this);
-
     }
 
     @Override
@@ -224,7 +238,6 @@
             mView.setImageDrawable(mLockIcon);
             mView.setVisibility(View.VISIBLE);
             mView.setContentDescription(mLockedLabel);
-            mView.hideBg();
         } else if (mShowUnlockIcon) {
             if (wasShowingFpIcon) {
                 mView.setImageDrawable(mFpToUnlockIcon);
@@ -235,11 +248,9 @@
                 mLockToUnlockIcon.forceAnimationOnUI();
                 mLockToUnlockIcon.start();
             }
-            mView.animateBg();
             mView.setVisibility(View.VISIBLE);
             mView.setContentDescription(mUnlockedLabel);
         } else {
-            mView.hideBg();
             mView.setVisibility(View.INVISIBLE);
             mView.setContentDescription(null);
         }
@@ -284,7 +295,11 @@
     }
 
     private void updateColors() {
-        mView.updateColor();
+        final int color = Utils.getColorAttrDefaultColor(mView.getContext(),
+                R.attr.wallpaperTextColorAccent);
+        mFpToUnlockIcon.setTint(color);
+        mLockToUnlockIcon.setTint(color);
+        mLockIcon.setTint(color);
     }
 
     private void updateConfiguration() {
@@ -444,7 +459,6 @@
         @Override
         public void onConfigChanged(Configuration newConfig) {
             updateConfiguration();
-            updateColors();
         }
     };
 
@@ -459,6 +473,14 @@
                     // intercept all following touches until we see MotionEvent.ACTION_CANCEL UP or
                     // MotionEvent.ACTION_UP (see #onTouchEvent)
                     mDownDetected = true;
+                    if (mVibrator != null) {
+                        mVibrator.vibrate(
+                                Process.myUid(),
+                                getContext().getOpPackageName(),
+                                UdfpsController.EFFECT_CLICK,
+                                "lockIcon-onDown",
+                                VIBRATION_SONIFICATION_ATTRIBUTES);
+                    }
                     return true;
                 }
 
@@ -467,6 +489,14 @@
                         return;
                     }
 
+                    if (mVibrator != null) {
+                        mVibrator.vibrate(
+                                Process.myUid(),
+                                getContext().getOpPackageName(),
+                                UdfpsController.EFFECT_CLICK,
+                                "lockIcon-onLongPress",
+                                VIBRATION_SONIFICATION_ATTRIBUTES);
+                    }
                     onAffordanceClick();
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index ab3e042e..6ddf248 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -40,6 +40,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
@@ -69,6 +70,7 @@
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.Execution;
 
@@ -106,6 +108,7 @@
     private final DelayableExecutor mFgExecutor;
     @NonNull private final StatusBar mStatusBar;
     @NonNull private final StatusBarStateController mStatusBarStateController;
+    @NonNull private final KeyguardStateController mKeyguardStateController;
     @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
     @NonNull private final DumpManager mDumpManager;
     @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -148,6 +151,7 @@
     private boolean mScreenOn;
     private Runnable mAodInterruptRunnable;
     private boolean mOnFingerDown;
+    private boolean mAttemptedToDismissKeyguard;
 
     @VisibleForTesting
     public static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
@@ -379,8 +383,12 @@
                     // ACTION_DOWN, in that case we should just reuse the old instance.
                     mVelocityTracker.clear();
                 }
-                if (isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView)) {
+
+                boolean withinSensorArea =
+                        isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView);
+                if (withinSensorArea) {
                     Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0);
+                    Log.v(TAG, "onTouch | action down");
                     // The pointer that causes ACTION_DOWN is always at index 0.
                     // We need to persist its ID to track it during ACTION_MOVE that could include
                     // data for many other pointers because of multi-touch support.
@@ -388,6 +396,11 @@
                     mVelocityTracker.addMovement(event);
                     handled = true;
                 }
+                if ((withinSensorArea || fromUdfpsView) && shouldTryToDismissKeyguard()) {
+                    Log.v(TAG, "onTouch | dismiss keyguard from ACTION_DOWN");
+                    mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
+                    mAttemptedToDismissKeyguard = true;
+                }
                 Trace.endSection();
                 break;
 
@@ -398,8 +411,10 @@
                         ? event.getPointerId(0)
                         : event.findPointerIndex(mActivePointerId);
                 if (idx == event.getActionIndex()) {
-                    if (isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx),
-                            fromUdfpsView)) {
+                    boolean actionMoveWithinSensorArea =
+                            isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx),
+                                fromUdfpsView);
+                    if (actionMoveWithinSensorArea) {
                         if (mVelocityTracker == null) {
                             // touches could be injected, so the velocity tracker may not have
                             // been initialized (via ACTION_DOWN).
@@ -434,6 +449,12 @@
                         Log.v(TAG, "onTouch | finger outside");
                         onFingerUp();
                     }
+                    if ((fromUdfpsView || actionMoveWithinSensorArea)
+                            && shouldTryToDismissKeyguard()) {
+                        Log.v(TAG, "onTouch | dismiss keyguard from ACTION_MOVE");
+                        mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
+                        mAttemptedToDismissKeyguard = true;
+                    }
                 }
                 Trace.endSection();
                 break;
@@ -448,6 +469,7 @@
                     mVelocityTracker = null;
                 }
                 Log.v(TAG, "onTouch | finger up");
+                mAttemptedToDismissKeyguard = false;
                 onFingerUp();
                 mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
                 Trace.endSection();
@@ -459,6 +481,13 @@
         return handled;
     }
 
+    private boolean shouldTryToDismissKeyguard() {
+        return mView.getAnimationViewController() != null
+            && mView.getAnimationViewController() instanceof UdfpsKeyguardViewController
+            && mKeyguardStateController.canDismissLockScreen()
+            && !mAttemptedToDismissKeyguard;
+    }
+
     @Inject
     public UdfpsController(@NonNull Context context,
             @NonNull Execution execution,
@@ -479,7 +508,8 @@
             @NonNull ScreenLifecycle screenLifecycle,
             @Nullable Vibrator vibrator,
             @NonNull UdfpsHapticsSimulator udfpsHapticsSimulator,
-            @NonNull Optional<UdfpsHbmProvider> hbmProvider) {
+            @NonNull Optional<UdfpsHbmProvider> hbmProvider,
+            @NonNull KeyguardStateController keyguardStateController) {
         mContext = context;
         mExecution = execution;
         // TODO (b/185124905): inject main handler and vibrator once done prototyping
@@ -493,6 +523,7 @@
         mFgExecutor = fgExecutor;
         mStatusBar = statusBar;
         mStatusBarStateController = statusBarStateController;
+        mKeyguardStateController = keyguardStateController;
         mKeyguardViewManager = statusBarKeyguardViewManager;
         mDumpManager = dumpManager;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -539,7 +570,12 @@
     @VisibleForTesting
     public void playStartHaptic() {
         if (mVibrator != null) {
-            mVibrator.vibrate(EFFECT_CLICK, VIBRATION_SONIFICATION_ATTRIBUTES);
+            mVibrator.vibrate(
+                    Process.myUid(),
+                    mContext.getOpPackageName(),
+                    EFFECT_CLICK,
+                    "udfps-onStart",
+                    VIBRATION_SONIFICATION_ATTRIBUTES);
         }
     }
 
@@ -667,6 +703,7 @@
                 mView.setSensorProperties(mSensorProps);
                 mView.setHbmProvider(mHbmProvider);
                 UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason);
+                mAttemptedToDismissKeyguard = false;
                 animation.init();
                 mView.setAnimationViewController(animation);
                 mOrientationListener.enable();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 5acb303..06e7482 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -669,11 +669,6 @@
 
         int userId = user.id;
 
-        // No lockdown option if it's not turned on in Settings
-        if (mSecureSettings.getIntForUser(Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, userId) == 0) {
-            return false;
-        }
-
         // Lockdown is meaningless without a place to go.
         if (!mKeyguardStateController.isMethodSecure()) {
             return false;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 1d791f5..d262412 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -40,6 +40,7 @@
 
 import com.android.systemui.broadcast.BroadcastDispatcher;
 
+import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -204,9 +205,14 @@
             if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent + " " + mUser);
             // Give it another chance next time it needs to be bound, out of kindness.
             mBindTryCount = 0;
-            mWrapper = null;
+            freeWrapper();
             if (mIsBound) {
-                mContext.unbindService(this);
+                try {
+                    mContext.unbindService(this);
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to unbind service "
+                            + mIntent.getComponent().flattenToShortString(), e);
+                }
                 mIsBound = false;
             }
         }
@@ -290,7 +296,9 @@
 
     private void handleDeath() {
         if (mWrapper == null) return;
-        mWrapper = null;
+        freeWrapper();
+        // Clearly not bound anymore
+        mIsBound = false;
         if (!mBound) return;
         if (DEBUG) Log.d(TAG, "handleDeath");
         if (checkComponentState()) {
@@ -472,6 +480,18 @@
         return mToken;
     }
 
+    private void freeWrapper() {
+        if (mWrapper != null) {
+            try {
+                mWrapper.asBinder().unlinkToDeath(this, 0);
+            } catch (NoSuchElementException e) {
+                Log.w(TAG, "Trying to unlink not linked recipient for component"
+                        + mIntent.getComponent().flattenToShortString());
+            }
+            mWrapper = null;
+        }
+    }
+
     public interface TileChangeListener {
         void onTileChanged(ComponentName tile);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index 45c7174..fa2d444 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles;
 
 import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.os.UserManager.DISALLOW_CAMERA_TOGGLE;
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
@@ -86,4 +87,9 @@
     public @Sensor int getSensorId() {
         return CAMERA;
     }
+
+    @Override
+    public String getRestriction() {
+        return DISALLOW_CAMERA_TOGGLE;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index 48a1ad6..f4f0b2c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles;
 
 import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
+import static android.os.UserManager.DISALLOW_MICROPHONE_TOGGLE;
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
@@ -86,4 +87,9 @@
     public @Sensor int getSensorId() {
         return MICROPHONE;
     }
+
+    @Override
+    public String getRestriction() {
+        return DISALLOW_MICROPHONE_TOGGLE;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
index bf72b77..b0a1b18 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -22,6 +22,7 @@
 import android.hardware.SensorPrivacyManager.Sensors.Sensor;
 import android.os.Handler;
 import android.os.Looper;
+import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.view.View;
 import android.widget.Switch;
@@ -63,6 +64,11 @@
      */
     public abstract @DrawableRes int getIconRes(boolean isBlocked);
 
+    /**
+     * @return the user restriction name
+     */
+    public abstract String getRestriction();
+
     protected SensorPrivacyToggleTile(QSHost host,
             @Background Looper backgroundLooper,
             @Main Handler mainHandler,
@@ -103,6 +109,8 @@
         boolean isBlocked = arg == null ? mSensorPrivacyController.isSensorBlocked(getSensorId())
                 : (boolean) arg;
 
+        checkIfRestrictionEnforcedByAdminOnly(state, getRestriction());
+
         state.icon = ResourceIcon.get(getIconRes(isBlocked));
         state.state = isBlocked ? Tile.STATE_INACTIVE : Tile.STATE_ACTIVE;
         state.value = !isBlocked;
@@ -112,7 +120,6 @@
         } else {
             state.secondaryLabel = mContext.getString(R.string.quick_settings_camera_mic_available);
         }
-        state.handlesLongClick = false;
         state.contentDescription = state.label;
         state.expandedAccessibilityClassName = Switch.class.getName();
     }
@@ -124,7 +131,7 @@
 
     @Override
     public Intent getLongClickIntent() {
-        return null;
+        return new Intent(Settings.ACTION_PRIVACY_SETTINGS);
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index d8d3676..397341b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -21,7 +21,10 @@
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -58,6 +61,7 @@
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.Execution;
 import com.android.systemui.util.concurrency.FakeExecution;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -130,6 +134,8 @@
     private Vibrator mVibrator;
     @Mock
     private UdfpsHapticsSimulator mUdfpsHapticsSimulator;
+    @Mock
+    private KeyguardStateController mKeyguardStateController;
 
     private FakeExecutor mFgExecutor;
 
@@ -137,6 +143,8 @@
     @Mock
     private UdfpsView mUdfpsView;
     @Mock
+    private UdfpsKeyguardViewController mUdfpsKeyguardViewController;
+    @Mock
     private TypedArray mBrightnessValues;
     @Mock
     private TypedArray mBrightnessBacklight;
@@ -149,6 +157,8 @@
     @Captor private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
     private ScreenLifecycle.Observer mScreenObserver;
 
+    @Captor private ArgumentCaptor<UdfpsAnimationViewController> mAnimViewControllerCaptor;
+
     @Before
     public void setUp() {
         setUpResources();
@@ -193,7 +203,8 @@
                 mScreenLifecycle,
                 mVibrator,
                 mUdfpsHapticsSimulator,
-                Optional.of(mHbmProvider));
+                Optional.of(mHbmProvider),
+                mKeyguardStateController);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
         verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -221,6 +232,76 @@
     }
 
     @Test
+    public void onActionDownTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
+        // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
+        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+        when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+
+        // GIVEN that the overlay is showing
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        // WHEN ACTION_DOWN is received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+        downEvent.recycle();
+
+        // THEN notify keyguard authenticate to dismiss the keyguard
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+    }
+
+    @Test
+    public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
+        // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
+        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+        when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+
+        // GIVEN that the overlay is showing
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        // WHEN ACTION_MOVE is received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        moveEvent.recycle();
+
+        // THEN notify keyguard authenticate to dismiss the keyguard
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+    }
+
+    @Test
+    public void onMultipleTouch_whenCanDismissLockScreen_entersDeviceOnce() throws RemoteException {
+        // GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
+        when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+        when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+
+        // GIVEN that the overlay is showing
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        // WHEN multiple touches are received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+        downEvent.recycle();
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        moveEvent.recycle();
+
+        // THEN notify keyguard authenticate to dismiss the keyguard
+        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+    }
+
+    @Test
     public void showUdfpsOverlay_addsViewToWindow() throws RemoteException {
         mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
                 IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
@@ -365,7 +446,11 @@
         moveEvent.recycle();
 
         // THEN click haptic is played
-        verify(mVibrator).vibrate(mUdfpsController.EFFECT_CLICK,
-                UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES);
+        verify(mVibrator).vibrate(
+                anyInt(),
+                anyString(),
+                eq(mUdfpsController.EFFECT_CLICK),
+                eq("udfps-onStart"),
+                eq(UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index 42fd288..0a42865 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -77,10 +77,10 @@
 
         // Stub.asInterface will just return itself.
         when(mMockTileService.queryLocalInterface(anyString())).thenReturn(mMockTileService);
+        when(mMockTileService.asBinder()).thenReturn(mMockTileService);
 
         mContext.addMockService(mTileServiceComponentName, mMockTileService);
 
-
         mTileServiceIntent = new Intent().setComponent(mTileServiceComponentName);
         mUser = new UserHandle(UserHandle.myUserId());
         mThread = new HandlerThread("TestThread");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2057a7e4..99ae52c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -11048,9 +11048,9 @@
             }
             final long gpuUsage = Debug.getGpuTotalUsageKb();
             if (gpuUsage >= 0) {
-                final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
-                if (gpuDmaBufUsage >= 0) {
-                    final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+                final long gpuPrivateUsage = Debug.getGpuPrivateMemoryKb();
+                if (gpuPrivateUsage >= 0) {
+                    final long gpuDmaBufUsage = gpuUsage - gpuPrivateUsage;
                     pw.print("      GPU: ");
                     pw.print(stringifyKBSize(gpuUsage));
                     pw.print(" (");
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index 74094e5..36c0de9 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1561,9 +1561,9 @@
 
         final long gpuUsage = Debug.getGpuTotalUsageKb();
         if (gpuUsage >= 0) {
-            final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
-            if (gpuDmaBufUsage >= 0) {
-                final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+            final long gpuPrivateUsage = Debug.getGpuPrivateMemoryKb();
+            if (gpuPrivateUsage >= 0) {
+                final long gpuDmaBufUsage = gpuUsage - gpuPrivateUsage;
                 memInfoBuilder.append("      GPU: ");
                 memInfoBuilder.append(stringifyKBSize(gpuUsage));
                 memInfoBuilder.append(" (");
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index e0b4d47..645131c 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -72,7 +72,7 @@
     private final Injector mInjector;
     private final BrightnessSettingListener mBrightnessSettingListener = this::onBrightnessChanged;
 
-    private SurfaceControlHdrLayerInfoListener mHdrListener;
+    private HdrListener mHdrListener;
     private HighBrightnessModeData mHbmData;
     private IBinder mRegisteredDisplayToken;
 
@@ -251,6 +251,11 @@
         mHandler.runWithScissors(() -> dumpLocal(pw), 1000);
     }
 
+    @VisibleForTesting
+    HdrListener getHdrListener() {
+        return mHdrListener;
+    }
+
     private void dumpLocal(PrintWriter pw) {
         pw.println("HighBrightnessModeController:");
         pw.println("  mBrightness=" + mBrightness);
@@ -487,7 +492,8 @@
         }
     }
 
-    private class HdrListener extends SurfaceControlHdrLayerInfoListener {
+    @VisibleForTesting
+    class HdrListener extends SurfaceControlHdrLayerInfoListener {
         @Override
         public void onHdrInfoChanged(IBinder displayToken, int numberOfHdrLayers,
                 int maxW, int maxH, int flags) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6adde9a..00ef97d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1265,12 +1265,13 @@
 
     @GuardedBy("mProgressLock")
     private void computeProgressLocked(boolean forcePublish) {
-        if (!mCommitted) {
+        if (!isIncrementalInstallation() || !mCommitted) {
             mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
                     + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
         } else {
-            // For incremental install, continue to publish incremental progress during committing.
-            if (isIncrementalInstallation() && (mIncrementalProgress - mProgress) >= 0.01) {
+            // For incremental, publish regular install progress before the session is committed,
+            // but publish incremental progress afterwards.
+            if (mIncrementalProgress - mProgress >= 0.01) {
                 // It takes some time for data loader to write to incremental file system, so at the
                 // beginning of the commit, the incremental progress might be very small.
                 // Wait till the incremental progress is larger than what's already displayed.
@@ -1279,7 +1280,7 @@
             }
         }
 
-        // Only publish when meaningful change
+        // Only publish meaningful progress changes.
         if (forcePublish || (mProgress - mReportedProgress) >= 0.01) {
             mReportedProgress = mProgress;
             mCallback.onSessionProgressChanged(this, mProgress);
diff --git a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
index 9f8b27f..30b6e68 100644
--- a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
@@ -28,7 +28,7 @@
     static Metrics getMetrics() {
         int totalIonKb = (int) Debug.getDmabufHeapTotalExportedKb();
         int gpuTotalUsageKb = (int) Debug.getGpuTotalUsageKb();
-        int gpuDmaBufUsageKb = (int) Debug.getGpuDmaBufUsageKb();
+        int gpuPrivateAllocationsKb = (int) Debug.getGpuPrivateMemoryKb();
         int dmaBufTotalExportedKb = (int) Debug.getDmabufTotalExportedKb();
 
         long[] mInfos = new long[Debug.MEMINFO_COUNT];
@@ -58,10 +58,6 @@
             accountedKb += mInfos[Debug.MEMINFO_KERNEL_STACK];
         }
 
-        int gpuPrivateAllocationsKb = -1;
-        if (gpuTotalUsageKb >= 0 && gpuDmaBufUsageKb >= 0) {
-            gpuPrivateAllocationsKb = gpuTotalUsageKb - gpuDmaBufUsageKb;
-        }
         // If we can distinguish gpu private allocs it means the dmabuf metrics
         // are supported already.
         if (dmaBufTotalExportedKb >= 0 && gpuPrivateAllocationsKb >= 0) {
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 7243947..1ad8850 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR;
 import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
 import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;
 
@@ -38,6 +39,7 @@
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 import android.test.mock.MockContentResolver;
+import android.util.MathUtils;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.SmallTest;
@@ -90,11 +92,10 @@
 
     @Mock IThermalService mThermalServiceMock;
     @Mock Injector mInjectorMock;
+    @Mock BrightnessSetting mBrightnessSetting;
 
     @Captor ArgumentCaptor<IThermalEventListener> mThermalEventListenerCaptor;
 
-    @Mock private BrightnessSetting mBrightnessSetting;
-
     private static final HighBrightnessModeData DEFAULT_HBM_DATA =
             new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS,
                     TIME_ALLOWED_IN_WINDOW_MILLIS, TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS,
@@ -348,6 +349,105 @@
         assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
     }
 
+    @Test
+    public void testHdrRequires50PercentOfScreen() {
+        final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
+
+        final int layerWidth = DISPLAY_WIDTH;
+        final int smallLayerHeight = DISPLAY_HEIGHT / 2 - 1; // height to use for <50%
+        final int largeLayerHeight = DISPLAY_HEIGHT / 2 + 1; // height to use for >50%
+
+        // ensure hdr doesn't turn on if layer is too small
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                layerWidth, smallLayerHeight, 0 /*flags*/);
+        advanceTime(0);
+        assertEquals(HIGH_BRIGHTNESS_MODE_OFF, hbmc.getHighBrightnessMode());
+
+        // Now check with layer larger than 50%
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                layerWidth, largeLayerHeight, 0 /*flags*/);
+        advanceTime(0);
+        assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
+    }
+
+    @Test
+    public void testHdrTrumpsSunlight() {
+        final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
+
+        // Turn on sunlight
+        hbmc.setAutoBrightnessEnabled(true);
+        hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
+        advanceTime(0);
+        assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
+        assertEquals(DEFAULT_MAX, hbmc.getCurrentBrightnessMax(), EPSILON);
+
+        // turn on hdr
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+        advanceTime(0);
+        assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
+        assertEquals(TRANSITION_POINT, hbmc.getCurrentBrightnessMax(), EPSILON);
+    }
+
+    @Test
+    public void testHdrBrightnessLimitSameAsNormalLimit() {
+        final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
+
+        // Check limit when HBM is off
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+        advanceTime(0);
+        assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
+        assertEquals(TRANSITION_POINT, hbmc.getCurrentBrightnessMax(), EPSILON);
+
+        // Check limit with HBM is set to HDR
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 0 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+        advanceTime(0);
+        assertEquals(HIGH_BRIGHTNESS_MODE_OFF, hbmc.getHighBrightnessMode());
+        assertEquals(TRANSITION_POINT, hbmc.getCurrentBrightnessMax(), EPSILON);
+    }
+
+    @Test
+    public void testHdrBrightnessScaledNormalBrightness() {
+        final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
+
+        hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+                DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+        advanceTime(0);
+        assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
+
+        // verify things are scaled for 0.5f
+        float brightness = 0.5f;
+        float expectedHdrBrightness = MathUtils.map(DEFAULT_MIN, TRANSITION_POINT,
+                DEFAULT_MIN, DEFAULT_MAX, brightness); // map value from normal range to hdr range
+        hbmc.onBrightnessChanged(brightness);
+        advanceTime(0);
+        assertEquals(expectedHdrBrightness, hbmc.getHdrBrightnessValue(), EPSILON);
+
+        // Try another value
+        brightness = 0.33f;
+        expectedHdrBrightness = MathUtils.map(DEFAULT_MIN, TRANSITION_POINT,
+                DEFAULT_MIN, DEFAULT_MAX, brightness); // map value from normal range to hdr range
+        hbmc.onBrightnessChanged(brightness);
+        advanceTime(0);
+        assertEquals(expectedHdrBrightness, hbmc.getHdrBrightnessValue(), EPSILON);
+
+        // Try the min value
+        brightness = DEFAULT_MIN;
+        expectedHdrBrightness = DEFAULT_MIN;
+        hbmc.onBrightnessChanged(brightness);
+        advanceTime(0);
+        assertEquals(expectedHdrBrightness, hbmc.getHdrBrightnessValue(), EPSILON);
+
+        // Try the max value
+        brightness = TRANSITION_POINT;
+        expectedHdrBrightness = DEFAULT_MAX;
+        hbmc.onBrightnessChanged(brightness);
+        advanceTime(0);
+        assertEquals(expectedHdrBrightness, hbmc.getHdrBrightnessValue(), EPSILON);
+    }
+
     private void assertState(HighBrightnessModeController hbmc,
             float brightnessMin, float brightnessMax, int hbmMode) {
         assertEquals(brightnessMin, hbmc.getCurrentBrightnessMin(), EPSILON);