Merge "haptics: remove unused haptics_customization_enabled" into main
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index fa9346e..4bf8879 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -607,9 +607,9 @@
         Configuration createdConfig;
         Configuration overrideConfig;
         @NonNull
-        private ActivityWindowInfo mActivityWindowInfo;
-        @Nullable
-        private ActivityWindowInfo mLastReportedActivityWindowInfo;
+        private final ActivityWindowInfo mActivityWindowInfo = new ActivityWindowInfo();
+        @NonNull
+        private final ActivityWindowInfo mLastReportedActivityWindowInfo = new ActivityWindowInfo();
 
         // Used for consolidating configs before sending on to Activity.
         private final Configuration tmpConfig = new Configuration();
@@ -700,7 +700,7 @@
             mSceneTransitionInfo = sceneTransitionInfo;
             mLaunchedFromBubble = launchedFromBubble;
             mTaskFragmentToken = taskFragmentToken;
-            mActivityWindowInfo = activityWindowInfo;
+            mActivityWindowInfo.set(activityWindowInfo);
             init();
         }
 
@@ -720,7 +720,7 @@
                         throw new IllegalStateException(
                                 "Received config update for non-existing activity");
                     }
-                    if (activityWindowInfoFlag() && activityWindowInfo == null) {
+                    if (activityWindowInfo == null) {
                         Log.w(TAG, "Received empty ActivityWindowInfo update for r=" + activity);
                         activityWindowInfo = mActivityWindowInfo;
                     }
@@ -6063,7 +6063,7 @@
             target.createdConfig = config.getGlobalConfiguration();
             target.overrideConfig = config.getOverrideConfiguration();
             target.pendingConfigChanges |= configChanges;
-            target.mActivityWindowInfo = activityWindowInfo;
+            target.mActivityWindowInfo.set(activityWindowInfo);
         }
 
         return scheduleRelaunch ? target : null;
@@ -6257,7 +6257,7 @@
         }
         r.startsNotResumed = startsNotResumed;
         r.overrideConfig = overrideConfig;
-        r.mActivityWindowInfo = activityWindowInfo;
+        r.mActivityWindowInfo.set(activityWindowInfo);
 
         handleLaunchActivity(r, pendingActions, mLastReportedDeviceId, customIntent);
     }
@@ -6759,7 +6759,7 @@
 
         // Perform updates.
         r.overrideConfig = overrideConfig;
-        r.mActivityWindowInfo = activityWindowInfo;
+        r.mActivityWindowInfo.set(activityWindowInfo);
 
         final ViewRootImpl viewRoot = r.activity.mDecor != null
             ? r.activity.mDecor.getViewRootImpl() : null;
@@ -6792,11 +6792,10 @@
         if (!activityWindowInfoFlag()) {
             return;
         }
-        if (r.mActivityWindowInfo == null
-                || r.mActivityWindowInfo.equals(r.mLastReportedActivityWindowInfo)) {
+        if (r.mActivityWindowInfo.equals(r.mLastReportedActivityWindowInfo)) {
             return;
         }
-        r.mLastReportedActivityWindowInfo = r.mActivityWindowInfo;
+        r.mLastReportedActivityWindowInfo.set(r.mActivityWindowInfo);
         ClientTransactionListenerController.getInstance().onActivityWindowInfoChanged(r.token,
                 r.mActivityWindowInfo);
     }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7337a7c..d7b9a2c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -24,6 +24,7 @@
 import static android.graphics.drawable.Icon.TYPE_URI;
 import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
 import static android.app.Flags.evenlyDividedCallStyleActionLayout;
+import static android.app.Flags.updateRankingTime;
 
 import static java.util.Objects.requireNonNull;
 
@@ -339,8 +340,9 @@
 
     /**
      * The creation time of the notification
+     * @hide
      */
-    private long creationTime;
+    public long creationTime;
 
     /**
      * The resource id of a drawable to use as the icon in the status bar.
@@ -2578,7 +2580,11 @@
     public Notification()
     {
         this.when = System.currentTimeMillis();
-        this.creationTime = System.currentTimeMillis();
+        if (updateRankingTime()) {
+            creationTime = when;
+        } else {
+            this.creationTime = System.currentTimeMillis();
+        }
         this.priority = PRIORITY_DEFAULT;
     }
 
@@ -2589,6 +2595,9 @@
     public Notification(Context context, int icon, CharSequence tickerText, long when,
             CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
     {
+        if (updateRankingTime()) {
+            creationTime = when;
+        }
         new Builder(context)
                 .setWhen(when)
                 .setSmallIcon(icon)
@@ -2618,7 +2627,11 @@
         this.icon = icon;
         this.tickerText = tickerText;
         this.when = when;
-        this.creationTime = System.currentTimeMillis();
+        if (updateRankingTime()) {
+            creationTime = when;
+        } else {
+            this.creationTime = System.currentTimeMillis();
+        }
     }
 
     /**
@@ -6843,7 +6856,9 @@
                 }
             }
 
-            mN.creationTime = System.currentTimeMillis();
+            if (!updateRankingTime()) {
+                mN.creationTime = System.currentTimeMillis();
+            }
 
             // lazy stuff from mContext; see comment in Builder(Context, Notification)
             Notification.addFieldsFromContext(mContext, mN);
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index e9a7460..29ffdc5 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -71,4 +71,14 @@
   metadata {
     purpose: PURPOSE_BUGFIX
   }
+}
+
+flag {
+  name: "update_ranking_time"
+  namespace: "systemui"
+  description: "Updates notification sorting criteria to highlight new content while maintaining stability"
+  bug: "326016985"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
 }
\ No newline at end of file
diff --git a/core/java/android/app/servertransaction/ClientTransactionListenerController.java b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
index 7383d07..c55b0f1 100644
--- a/core/java/android/app/servertransaction/ClientTransactionListenerController.java
+++ b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
@@ -122,7 +122,7 @@
         }
         for (Object activityWindowInfoChangedListener : activityWindowInfoChangedListeners) {
             ((BiConsumer<IBinder, ActivityWindowInfo>) activityWindowInfoChangedListener)
-                    .accept(activityToken, activityWindowInfo);
+                    .accept(activityToken, new ActivityWindowInfo(activityWindowInfo));
         }
     }
 
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index b6066ba..9c63d0d 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -1297,6 +1297,17 @@
      */
     @Nullable
     private Drawable resolveAvatarImageForOneToOne(Icon conversationIcon) {
+        final Drawable conversationIconDrawable =
+                tryLoadingSizeRestrictedIconForOneToOne(conversationIcon);
+        if (conversationIconDrawable != null) {
+            return conversationIconDrawable;
+        }
+        // when size restricted icon loading fails, we fallback to icons load drawable.
+        return loadDrawableFromIcon(conversationIcon);
+    }
+
+    @Nullable
+    private Drawable tryLoadingSizeRestrictedIconForOneToOne(Icon conversationIcon) {
         try {
             return mConversationIconView.loadSizeRestrictedIcon(conversationIcon);
         } catch (Exception ex) {
@@ -1309,6 +1320,11 @@
      */
     @Nullable
     private Drawable resolveAvatarImageForFacePile(Icon conversationIcon) {
+        return loadDrawableFromIcon(conversationIcon);
+    }
+
+    @Nullable
+    private Drawable loadDrawableFromIcon(Icon conversationIcon) {
         try {
             return conversationIcon.loadDrawable(getContext());
         } catch (Exception ex) {
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 488f017..ff28055 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -1258,7 +1258,8 @@
     @Test
     public void testTriggerFromMainProfile_inSingleUserMode_withWorkProfilePresent() {
         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
-                android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE);
+                android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE,
+                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
         markWorkProfileUserAvailable();
         setTabOwnerUserHandleForLaunch(PERSONAL_USER_HANDLE);
         Intent sendIntent = createSendImageIntent();
@@ -1281,7 +1282,8 @@
     @Test
     public void testTriggerFromWorkProfile_inSingleUserMode() {
         mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
-                android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE);
+                android.multiuser.Flags.FLAG_ALLOW_RESOLVER_SHEET_FOR_PRIVATE_SPACE,
+                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
         markWorkProfileUserAvailable();
         setTabOwnerUserHandleForLaunch(sOverrides.workProfileUserHandle);
         Intent sendIntent = createSendImageIntent();
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 014b841..341c3e8c 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -345,6 +345,7 @@
         "jni/android_nio_utils.cpp",
         "jni/android_util_PathParser.cpp",
 
+        "jni/AnimatedImageDrawable.cpp",
         "jni/Bitmap.cpp",
         "jni/BitmapRegionDecoder.cpp",
         "jni/BufferUtils.cpp",
@@ -418,7 +419,6 @@
     target: {
         android: {
             srcs: [ // sources that depend on android only libraries
-                "jni/AnimatedImageDrawable.cpp",
                 "jni/android_graphics_TextureLayer.cpp",
                 "jni/android_graphics_HardwareRenderer.cpp",
                 "jni/android_graphics_HardwareBufferRenderer.cpp",
@@ -539,6 +539,7 @@
         "renderthread/RenderTask.cpp",
         "renderthread/TimeLord.cpp",
         "hwui/AnimatedImageDrawable.cpp",
+        "hwui/AnimatedImageThread.cpp",
         "hwui/Bitmap.cpp",
         "hwui/BlurDrawLooper.cpp",
         "hwui/Canvas.cpp",
@@ -599,7 +600,6 @@
             local_include_dirs: ["platform/android"],
 
             srcs: [
-                "hwui/AnimatedImageThread.cpp",
                 "pipeline/skia/ATraceMemoryDump.cpp",
                 "pipeline/skia/GLFunctorDrawable.cpp",
                 "pipeline/skia/LayerDrawable.cpp",
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 27773a6..69613c7 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -15,18 +15,16 @@
  */
 
 #include "AnimatedImageDrawable.h"
-#ifdef __ANDROID__ // Layoutlib does not support AnimatedImageThread
-#include "AnimatedImageThread.h"
-#endif
-
-#include <gui/TraceUtils.h>
-#include "pipeline/skia/SkiaUtils.h"
 
 #include <SkPicture.h>
 #include <SkRefCnt.h>
+#include <gui/TraceUtils.h>
 
 #include <optional>
 
+#include "AnimatedImageThread.h"
+#include "pipeline/skia/SkiaUtils.h"
+
 namespace android {
 
 AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed,
@@ -185,10 +183,8 @@
     } else if (starting) {
         // The image has animated, and now is being reset. Queue up the first
         // frame, but keep showing the current frame until the first is ready.
-#ifdef __ANDROID__ // Layoutlib does not support AnimatedImageThread
         auto& thread = uirenderer::AnimatedImageThread::getInstance();
         mNextSnapshot = thread.reset(sk_ref_sp(this));
-#endif
     }
 
     bool finalFrame = false;
@@ -214,10 +210,8 @@
     }
 
     if (mRunning && !mNextSnapshot.valid()) {
-#ifdef __ANDROID__ // Layoutlib does not support AnimatedImageThread
         auto& thread = uirenderer::AnimatedImageThread::getInstance();
         mNextSnapshot = thread.decodeNextFrame(sk_ref_sp(this));
-#endif
     }
 
     if (!drawDirectly) {
diff --git a/libs/hwui/hwui/AnimatedImageThread.cpp b/libs/hwui/hwui/AnimatedImageThread.cpp
index 825dd4c..e39c8d5 100644
--- a/libs/hwui/hwui/AnimatedImageThread.cpp
+++ b/libs/hwui/hwui/AnimatedImageThread.cpp
@@ -16,7 +16,9 @@
 
 #include "AnimatedImageThread.h"
 
+#ifdef __ANDROID__
 #include <sys/resource.h>
+#endif
 
 namespace android {
 namespace uirenderer {
@@ -31,7 +33,9 @@
 }
 
 AnimatedImageThread::AnimatedImageThread() {
+#ifdef __ANDROID__
     setpriority(PRIO_PROCESS, 0, PRIORITY_NORMAL + PRIORITY_MORE_FAVORABLE);
+#endif
 }
 
 std::future<AnimatedImageDrawable::Snapshot> AnimatedImageThread::decodeNextFrame(
diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp
index 90b1da8..0f80c55 100644
--- a/libs/hwui/jni/AnimatedImageDrawable.cpp
+++ b/libs/hwui/jni/AnimatedImageDrawable.cpp
@@ -25,7 +25,9 @@
 #include <hwui/AnimatedImageDrawable.h>
 #include <hwui/Canvas.h>
 #include <hwui/ImageDecoder.h>
+#ifdef __ANDROID__
 #include <utils/Looper.h>
+#endif
 
 #include "ColorFilter.h"
 #include "GraphicsJNI.h"
@@ -180,6 +182,23 @@
     drawable->setRepetitionCount(loopCount);
 }
 
+#ifndef __ANDROID__
+struct Message {
+    Message(int w) {}
+};
+
+class MessageHandler : public virtual RefBase {
+protected:
+    virtual ~MessageHandler() override {}
+
+public:
+    /**
+     * Handles a message.
+     */
+    virtual void handleMessage(const Message& message) = 0;
+};
+#endif
+
 class InvokeListener : public MessageHandler {
 public:
     InvokeListener(JNIEnv* env, jobject javaObject) {
@@ -204,6 +223,7 @@
 };
 
 class JniAnimationEndListener : public OnAnimationEndListener {
+#ifdef __ANDROID__
 public:
     JniAnimationEndListener(sp<Looper>&& looper, JNIEnv* env, jobject javaObject) {
         mListener = new InvokeListener(env, javaObject);
@@ -215,6 +235,17 @@
 private:
     sp<InvokeListener> mListener;
     sp<Looper> mLooper;
+#else
+public:
+    JniAnimationEndListener(JNIEnv* env, jobject javaObject) {
+        mListener = new InvokeListener(env, javaObject);
+    }
+
+    void onAnimationEnd() override { mListener->handleMessage(0); }
+
+private:
+    sp<InvokeListener> mListener;
+#endif
 };
 
 static void AnimatedImageDrawable_nSetOnAnimationEndListener(JNIEnv* env, jobject /*clazz*/,
@@ -223,6 +254,7 @@
     if (!jdrawable) {
         drawable->setOnAnimationEndListener(nullptr);
     } else {
+#ifdef __ANDROID__
         sp<Looper> looper = Looper::getForThread();
         if (!looper.get()) {
             doThrowISE(env,
@@ -233,6 +265,10 @@
 
         drawable->setOnAnimationEndListener(
                 std::make_unique<JniAnimationEndListener>(std::move(looper), env, jdrawable));
+#else
+        drawable->setOnAnimationEndListener(
+                std::make_unique<JniAnimationEndListener>(env, jdrawable));
+#endif
     }
 }
 
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
index 9111e61..68c2244 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
@@ -23,6 +23,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.style.Hyphens
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextOverflow
 import com.android.compose.theme.LocalAndroidColorScheme
@@ -39,7 +40,7 @@
         text = text,
         color = LocalAndroidColorScheme.current.onSurface,
         textAlign = TextAlign.Center,
-        style = MaterialTheme.typography.headlineSmall,
+        style = MaterialTheme.typography.headlineSmall.copy(hyphens = Hyphens.Auto),
     )
 }
 
@@ -52,7 +53,7 @@
         modifier = modifier.wrapContentSize(),
         text = text,
         color = LocalAndroidColorScheme.current.onSurfaceVariant,
-        style = MaterialTheme.typography.bodyMedium,
+        style = MaterialTheme.typography.bodyMedium.copy(hyphens = Hyphens.Auto),
     )
 }
 
@@ -70,7 +71,7 @@
         modifier = modifier.wrapContentSize(),
         text = text,
         color = LocalAndroidColorScheme.current.onSurfaceVariant,
-        style = MaterialTheme.typography.bodySmall,
+        style = MaterialTheme.typography.bodySmall.copy(hyphens = Hyphens.Auto),
         overflow = TextOverflow.Ellipsis,
         maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE,
         onTextLayout = onTextLayout,
@@ -86,7 +87,7 @@
         modifier = modifier.wrapContentSize(),
         text = text,
         color = LocalAndroidColorScheme.current.onSurface,
-        style = MaterialTheme.typography.titleLarge,
+        style = MaterialTheme.typography.titleLarge.copy(hyphens = Hyphens.Auto),
     )
 }
 
@@ -104,7 +105,7 @@
         modifier = modifier.wrapContentSize(),
         text = text,
         color = LocalAndroidColorScheme.current.onSurface,
-        style = MaterialTheme.typography.titleSmall,
+        style = MaterialTheme.typography.titleSmall.copy(hyphens = Hyphens.Auto),
         overflow = TextOverflow.Ellipsis,
         maxLines = if (enforceOneLine) 1 else Int.MAX_VALUE,
         onTextLayout = onTextLayout,
@@ -120,7 +121,7 @@
         modifier = modifier.wrapContentSize(),
         text = text,
         color = color,
-        style = MaterialTheme.typography.titleSmall,
+        style = MaterialTheme.typography.titleSmall.copy(hyphens = Hyphens.Auto),
     )
 }
 
@@ -133,7 +134,7 @@
         modifier = modifier.wrapContentSize(),
         text = text,
         color = MaterialTheme.colorScheme.inverseOnSurface,
-        style = MaterialTheme.typography.bodyMedium,
+        style = MaterialTheme.typography.bodyMedium.copy(hyphens = Hyphens.Auto),
     )
 }
 
@@ -146,7 +147,7 @@
         modifier = modifier.wrapContentSize(),
         text = text,
         color = MaterialTheme.colorScheme.inversePrimary,
-        style = MaterialTheme.typography.labelLarge,
+        style = MaterialTheme.typography.labelLarge.copy(hyphens = Hyphens.Auto),
     )
 }
 
@@ -160,7 +161,7 @@
         text = text,
         textAlign = TextAlign.Center,
         color = LocalAndroidColorScheme.current.onSurfaceVariant,
-        style = MaterialTheme.typography.labelLarge,
+        style = MaterialTheme.typography.labelLarge.copy(hyphens = Hyphens.Auto),
     )
 }
 
@@ -173,6 +174,6 @@
         modifier = modifier.wrapContentSize(),
         text = text,
         textAlign = TextAlign.Center,
-        style = MaterialTheme.typography.labelLarge,
+        style = MaterialTheme.typography.labelLarge.copy(hyphens = Hyphens.Auto),
     )
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
similarity index 91%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index c308a98..2a2b2f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -85,7 +85,7 @@
     }
 
     @Test
-    fun testIsImportantForAccessibility_falseWhenNoNotifs() =
+    fun isImportantForAccessibility_falseWhenNoNotifs() =
         testScope.runTest {
             val important by collectLastValue(underTest.isImportantForAccessibility)
 
@@ -100,7 +100,7 @@
         }
 
     @Test
-    fun testIsImportantForAccessibility_trueWhenNotifs() =
+    fun isImportantForAccessibility_trueWhenNotifs() =
         testScope.runTest {
             val important by collectLastValue(underTest.isImportantForAccessibility)
 
@@ -115,7 +115,7 @@
         }
 
     @Test
-    fun testIsImportantForAccessibility_trueWhenNotKeyguard() =
+    fun isImportantForAccessibility_trueWhenNotKeyguard() =
         testScope.runTest {
             val important by collectLastValue(underTest.isImportantForAccessibility)
 
@@ -130,7 +130,7 @@
         }
 
     @Test
-    fun testShouldIncludeEmptyShadeView_trueWhenNoNotifs() =
+    fun shouldIncludeEmptyShadeView_trueWhenNoNotifs() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
@@ -143,7 +143,7 @@
         }
 
     @Test
-    fun testShouldIncludeEmptyShadeView_falseWhenNotifs() =
+    fun shouldIncludeEmptyShadeView_falseWhenNotifs() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
@@ -156,7 +156,7 @@
         }
 
     @Test
-    fun testShouldIncludeEmptyShadeView_falseWhenQsExpandedDefault() =
+    fun shouldIncludeEmptyShadeView_falseWhenQsExpandedDefault() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
@@ -171,7 +171,7 @@
         }
 
     @Test
-    fun testShouldIncludeEmptyShadeView_trueWhenQsExpandedInSplitShade() =
+    fun shouldIncludeEmptyShadeView_trueWhenQsExpandedInSplitShade() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
@@ -189,7 +189,7 @@
         }
 
     @Test
-    fun testShouldIncludeEmptyShadeView_trueWhenLockedShade() =
+    fun shouldIncludeEmptyShadeView_trueWhenLockedShade() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
@@ -204,7 +204,7 @@
         }
 
     @Test
-    fun testShouldIncludeEmptyShadeView_falseWhenKeyguard() =
+    fun shouldIncludeEmptyShadeView_falseWhenKeyguard() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
@@ -219,7 +219,7 @@
         }
 
     @Test
-    fun testShouldIncludeEmptyShadeView_falseWhenStartingToSleep() =
+    fun shouldIncludeEmptyShadeView_falseWhenStartingToSleep() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldShowEmptyShadeView)
 
@@ -236,7 +236,7 @@
         }
 
     @Test
-    fun testAreNotificationsHiddenInShade_true() =
+    fun areNotificationsHiddenInShade_true() =
         testScope.runTest {
             val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
 
@@ -248,7 +248,7 @@
         }
 
     @Test
-    fun testAreNotificationsHiddenInShade_false() =
+    fun areNotificationsHiddenInShade_false() =
         testScope.runTest {
             val hidden by collectLastValue(underTest.areNotificationsHiddenInShade)
 
@@ -260,7 +260,7 @@
         }
 
     @Test
-    fun testHasFilteredOutSeenNotifications_true() =
+    fun hasFilteredOutSeenNotifications_true() =
         testScope.runTest {
             val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)
 
@@ -271,7 +271,7 @@
         }
 
     @Test
-    fun testHasFilteredOutSeenNotifications_false() =
+    fun hasFilteredOutSeenNotifications_false() =
         testScope.runTest {
             val hasFilteredNotifs by collectLastValue(underTest.hasFilteredOutSeenNotifications)
 
@@ -282,7 +282,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_trueWhenShade() =
+    fun shouldIncludeFooterView_trueWhenShade() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -298,7 +298,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_trueWhenLockedShade() =
+    fun shouldIncludeFooterView_trueWhenLockedShade() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -314,7 +314,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_falseWhenKeyguard() =
+    fun shouldIncludeFooterView_falseWhenKeyguard() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -329,7 +329,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_falseWhenUserNotSetUp() =
+    fun shouldIncludeFooterView_falseWhenUserNotSetUp() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -347,7 +347,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_falseWhenStartingToSleep() =
+    fun shouldIncludeFooterView_falseWhenStartingToSleep() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -365,7 +365,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_falseWhenQsExpandedDefault() =
+    fun shouldIncludeFooterView_falseWhenQsExpandedDefault() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -384,7 +384,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_trueWhenQsExpandedSplitShade() =
+    fun shouldIncludeFooterView_trueWhenQsExpandedSplitShade() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -405,7 +405,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_falseWhenRemoteInputActive() =
+    fun shouldIncludeFooterView_falseWhenRemoteInputActive() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -423,7 +423,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_animatesWhenShade() =
+    fun shouldIncludeFooterView_animatesWhenShade() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -439,7 +439,7 @@
         }
 
     @Test
-    fun testShouldIncludeFooterView_notAnimatingOnKeyguard() =
+    fun shouldIncludeFooterView_notAnimatingOnKeyguard() =
         testScope.runTest {
             val shouldInclude by collectLastValue(underTest.shouldIncludeFooterView)
 
@@ -455,7 +455,7 @@
         }
 
     @Test
-    fun testShouldHideFooterView_trueWhenShadeIsClosed() =
+    fun shouldHideFooterView_trueWhenShadeIsClosed() =
         testScope.runTest {
             val shouldHide by collectLastValue(underTest.shouldHideFooterView)
 
@@ -469,7 +469,7 @@
         }
 
     @Test
-    fun testShouldHideFooterView_falseWhenShadeIsOpen() =
+    fun shouldHideFooterView_falseWhenShadeIsOpen() =
         testScope.runTest {
             val shouldHide by collectLastValue(underTest.shouldHideFooterView)
 
@@ -484,7 +484,7 @@
 
     @Test
     @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
-    fun testPinnedHeadsUpRows_filtersForPinnedItems() =
+    fun pinnedHeadsUpRows_filtersForPinnedItems() =
         testScope.runTest {
             val pinnedHeadsUpRows by collectLastValue(underTest.pinnedHeadsUpRows)
 
@@ -527,7 +527,7 @@
 
     @Test
     @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
-    fun testHasPinnedHeadsUpRows_true() =
+    fun hasPinnedHeadsUpRows_true() =
         testScope.runTest {
             val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
 
@@ -542,7 +542,7 @@
 
     @Test
     @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
-    fun testHasPinnedHeadsUpRows_false() =
+    fun hasPinnedHeadsUpRows_false() =
         testScope.runTest {
             val hasPinnedHeadsUpRow by collectLastValue(underTest.hasPinnedHeadsUpRow)
 
@@ -557,7 +557,7 @@
 
     @Test
     @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
-    fun testTopHeadsUpRow_emptyList_null() =
+    fun topHeadsUpRow_emptyList_null() =
         testScope.runTest {
             val topHeadsUpRow by collectLastValue(underTest.topHeadsUpRow)
 
@@ -569,7 +569,7 @@
 
     @Test
     @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
-    fun testHeadsUpAnimationsEnabled_true() =
+    fun headsUpAnimationsEnabled_true() =
         testScope.runTest {
             val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
 
@@ -582,7 +582,7 @@
 
     @Test
     @EnableFlags(NotificationsHeadsUpRefactor.FLAG_NAME)
-    fun testHeadsUpAnimationsEnabled_keyguardShowing_false() =
+    fun headsUpAnimationsEnabled_keyguardShowing_false() =
         testScope.runTest {
             val animationsEnabled by collectLastValue(underTest.headsUpAnimationsEnabled)
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index a293afc..182798e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -139,6 +139,7 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dreams.ui.viewmodel.DreamViewModel;
 import com.android.systemui.dump.DumpManager;
@@ -3404,7 +3405,8 @@
 
         // Ensure that keyguard becomes visible if the going away animation is canceled
         if (showKeyguard && !KeyguardWmStateRefactor.isEnabled()
-                && MigrateClocksToBlueprint.isEnabled()) {
+                && (MigrateClocksToBlueprint.isEnabled()
+                    || DeviceEntryUdfpsRefactor.isEnabled())) {
             mKeyguardInteractor.showKeyguard();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 18bb5119..5544f93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -173,7 +173,6 @@
                 footerView,
                 footerViewModel,
                 clearAllNotifications = {
-                    metricsLogger.action(MetricsProto.MetricsEvent.ACTION_DISMISS_ALL_NOTES)
                     clearAllNotifications(
                         parentView,
                         // Hide the silent section header (if present) if there will be
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 97fc35a..8b7b348 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -51,6 +51,9 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.domain.interactor.BiometricUnlockInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
@@ -59,6 +62,7 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
+import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.SystemClock;
 
 import dagger.Lazy;
@@ -286,7 +290,9 @@
             VibratorHelper vibrator,
             SystemClock systemClock,
             Lazy<SelectedUserInteractor> selectedUserInteractor,
-            BiometricUnlockInteractor biometricUnlockInteractor
+            BiometricUnlockInteractor biometricUnlockInteractor,
+            JavaAdapter javaAdapter,
+            KeyguardTransitionInteractor keyguardTransitionInteractor
     ) {
         mPowerManager = powerManager;
         mUpdateMonitor = keyguardUpdateMonitor;
@@ -317,10 +323,19 @@
         mOrderUnlockAndWake = resources.getBoolean(
                 com.android.internal.R.bool.config_orderUnlockAndWake);
         mSelectedUserInteractor = selectedUserInteractor;
-
+        javaAdapter.alwaysCollectFlow(
+                keyguardTransitionInteractor.getStartedKeyguardTransitionStep(),
+                this::consumeTransitionStepOnStartedKeyguardState);
         dumpManager.registerDumpable(this);
     }
 
+    @VisibleForTesting
+    protected void consumeTransitionStepOnStartedKeyguardState(TransitionStep transitionStep) {
+        if (transitionStep.getFrom() == KeyguardState.GONE) {
+            mBiometricUnlockInteractor.setBiometricUnlockState(MODE_NONE);
+        }
+    }
+
     public void setKeyguardViewController(KeyguardViewController keyguardViewController) {
         mKeyguardViewController = keyguardViewController;
     }
@@ -773,7 +788,6 @@
         for (BiometricUnlockEventsListener listener : mBiometricUnlockEventsListeners) {
             listener.onResetMode();
         }
-        mBiometricUnlockInteractor.setBiometricUnlockState(MODE_NONE);
         mNumConsecutiveFpFailures = 0;
         mLastFpFailureUptimeMillis = 0;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 6f65eb4..50f81ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_NONE;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -26,6 +27,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
@@ -51,6 +53,10 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.domain.interactor.BiometricUnlockInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
+import com.android.systemui.keyguard.shared.model.TransitionState;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -58,6 +64,7 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
+import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
@@ -158,7 +165,9 @@
                 mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper,
                 mSystemClock,
                 () -> mSelectedUserInteractor,
-                mBiometricUnlockInteractor
+                mBiometricUnlockInteractor,
+                mock(JavaAdapter.class),
+                mock(KeyguardTransitionInteractor.class)
         );
         biometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
         biometricUnlockController.addListener(mBiometricUnlockEventsListener);
@@ -462,6 +471,29 @@
     }
 
     @Test
+    public void biometricUnlockStateResetOnTransitionFromGone() {
+        mBiometricUnlockController.consumeTransitionStepOnStartedKeyguardState(
+                new TransitionStep(
+                        KeyguardState.AOD,
+                        KeyguardState.GONE,
+                        .1f /* value */,
+                        TransitionState.STARTED
+                )
+        );
+        verify(mBiometricUnlockInteractor, never()).setBiometricUnlockState(anyInt());
+
+        mBiometricUnlockController.consumeTransitionStepOnStartedKeyguardState(
+                new TransitionStep(
+                        KeyguardState.GONE,
+                        KeyguardState.AOD,
+                        .1f /* value */,
+                        TransitionState.STARTED
+                )
+        );
+        verify(mBiometricUnlockInteractor).setBiometricUnlockState(eq(MODE_NONE));
+    }
+
+    @Test
     public void onFingerprintDetect_showBouncer() {
         // WHEN fingerprint detect occurs
         mBiometricUnlockController.onBiometricDetected(UserHandle.USER_CURRENT,
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 9950d8f..da26209 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -1097,13 +1097,34 @@
         return mBrightnessToBacklightSpline.interpolate(brightness);
     }
 
-    private float getBrightnessFromBacklight(float brightness) {
+    /**
+     * Calculates the screen brightness value - as used among the system from the HAL backlight
+     * level
+     * @param backlight value from 0-1 HAL scale
+     * @return brightness value from 0-1 framework scale
+     */
+    public float getBrightnessFromBacklight(float backlight) {
         if (mLowBrightnessData != null) {
-            return mLowBrightnessData.mBacklightToBrightness.interpolate(brightness);
+            return mLowBrightnessData.mBacklightToBrightness.interpolate(backlight);
         }
-        return mBacklightToBrightnessSpline.interpolate(brightness);
+        return mBacklightToBrightnessSpline.interpolate(backlight);
     }
 
+    /**
+     *
+     * @return low brightness mode transition point
+     */
+    public float getLowBrightnessTransitionPoint() {
+        if (mLowBrightnessData == null) {
+            return PowerManager.BRIGHTNESS_MIN;
+        }
+        return mLowBrightnessData.mTransitionPoint;
+    }
+
+    /**
+     *
+     * @return HAL backlight mapping to framework brightness
+     */
     private Spline getBacklightToBrightnessSpline() {
         if (mLowBrightnessData != null) {
             return mLowBrightnessData.mBacklightToBrightness;
@@ -1133,7 +1154,12 @@
         return mBacklightToNitsSpline.interpolate(backlight);
     }
 
-    private float getBacklightFromNits(float nits) {
+    /**
+     *
+     * @param nits - display brightness
+     * @return corresponding HAL backlight value
+     */
+    public float getBacklightFromNits(float nits) {
         if (mLowBrightnessData != null) {
             return mLowBrightnessData.mNitsToBacklight.interpolate(nits);
         }
@@ -1148,6 +1174,18 @@
     }
 
     /**
+     *
+     * @param lux - ambient brightness
+     * @return minimum allowed nits, given the lux.
+     */
+    public float getMinNitsFromLux(float lux) {
+        if (mLowBrightnessData == null) {
+            return INVALID_NITS;
+        }
+        return mLowBrightnessData.mMinLuxToNits.interpolate(lux);
+    }
+
+    /**
      * @return true if there is sdrHdrRatioMap, false otherwise.
      */
     public boolean hasSdrToHdrRatioSpline() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 0807cc0..d99f712 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1336,12 +1336,14 @@
                 && (mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged()
                 || userSetBrightnessChanged);
 
-        mBrightnessRangeController.setAutoBrightnessEnabled(
-                mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()
+        final int autoBrightnessState = mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()
                 ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
                 : mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff()
                         ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE
-                        : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED);
+                        : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
+
+        mBrightnessRangeController.setAutoBrightnessEnabled(autoBrightnessState);
+        mBrightnessClamperController.setAutoBrightnessState(autoBrightnessState);
 
         boolean updateScreenBrightnessSetting =
                 displayBrightnessState.shouldUpdateScreenBrightnessSetting();
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
index d8a4500..9c7504d 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
@@ -66,6 +66,7 @@
     private float mCustomAnimationRate = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET;
     @Nullable
     private Type mClamperType = null;
+    private int mAutoBrightnessState = -1;
 
     private boolean mClamperApplied = false;
 
@@ -94,7 +95,8 @@
 
         mClampers = injector.getClampers(handler, clamperChangeListenerInternal, data, flags,
                 context);
-        mModifiers = injector.getModifiers(flags, context, handler, clamperChangeListener);
+        mModifiers = injector.getModifiers(flags, context, handler, clamperChangeListener,
+                data.mDisplayDeviceConfig);
         mOnPropertiesChangedListener =
                 properties -> mClampers.forEach(BrightnessClamper::onDeviceConfigChanged);
         start();
@@ -197,6 +199,19 @@
         mModifiers.forEach(modifier -> modifier.onAmbientLuxChange(ambientLux));
     }
 
+    /**
+     * Sets the autobrightness state for clampers that need to be aware of the state.
+     * @param state autobrightness state
+     */
+    public void setAutoBrightnessState(int state) {
+        if (state == mAutoBrightnessState) {
+            return;
+        }
+        mModifiers.forEach(modifier -> modifier.setAutoBrightnessState(state));
+        mAutoBrightnessState = state;
+        recalculateBrightnessCap();
+    }
+
     // Called in DisplayControllerHandler
     private void recalculateBrightnessCap() {
         float brightnessCap = PowerManager.BRIGHTNESS_MAX;
@@ -265,12 +280,14 @@
         }
 
         List<BrightnessStateModifier> getModifiers(DisplayManagerFlags flags, Context context,
-                Handler handler, ClamperChangeListener listener) {
+                Handler handler, ClamperChangeListener listener,
+                DisplayDeviceConfig displayDeviceConfig) {
             List<BrightnessStateModifier> modifiers = new ArrayList<>();
             modifiers.add(new DisplayDimModifier(context));
             modifiers.add(new BrightnessLowPowerModeModifier());
             if (flags.isEvenDimmerEnabled()) {
-                modifiers.add(new BrightnessLowLuxModifier(handler, listener, context));
+                modifiers.add(new BrightnessLowLuxModifier(handler, listener, context,
+                        displayDeviceConfig));
             }
             return modifiers;
         }
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
index a91bb59..7f88c30 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
@@ -16,13 +16,14 @@
 
 package com.android.server.display.brightness.clamper;
 
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
+
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManagerInternal;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.PowerManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
@@ -30,6 +31,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.display.BrightnessSynchronizer;
 import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.DisplayDeviceConfig;
 import com.android.server.display.brightness.BrightnessReason;
 import com.android.server.display.utils.DebugUtils;
 
@@ -45,19 +47,23 @@
     // 'adb shell setprop persist.log.tag.BrightnessLowLuxModifier DEBUG && adb reboot'
     private static final String TAG = "BrightnessLowLuxModifier";
     private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
-    private static final float MIN_NITS = 2.0f;
+    private static final float MIN_NITS_DEFAULT = 0.2f;
     private final SettingsObserver mSettingsObserver;
     private final ContentResolver mContentResolver;
     private final Handler mHandler;
     private final BrightnessClamperController.ClamperChangeListener mChangeListener;
     private int mReason;
     private float mBrightnessLowerBound;
+    private float mMinNitsAllowed;
     private boolean mIsActive;
+    private boolean mAutoBrightnessEnabled;
     private float mAmbientLux;
+    private final DisplayDeviceConfig mDisplayDeviceConfig;
 
     @VisibleForTesting
     BrightnessLowLuxModifier(Handler handler,
-            BrightnessClamperController.ClamperChangeListener listener, Context context) {
+            BrightnessClamperController.ClamperChangeListener listener, Context context,
+            DisplayDeviceConfig displayDeviceConfig) {
         super();
 
         mChangeListener = listener;
@@ -67,6 +73,8 @@
         mHandler.post(() -> {
             start();
         });
+
+        mDisplayDeviceConfig = displayDeviceConfig;
     }
 
     /**
@@ -78,41 +86,45 @@
         int userId = UserHandle.USER_CURRENT;
         float settingNitsLowerBound = Settings.Secure.getFloatForUser(
                 mContentResolver, Settings.Secure.EVEN_DIMMER_MIN_NITS,
-                /* def= */ MIN_NITS, userId);
+                /* def= */ MIN_NITS_DEFAULT, userId);
 
         boolean isActive = Settings.Secure.getFloatForUser(mContentResolver,
                 Settings.Secure.EVEN_DIMMER_ACTIVATED,
-                /* def= */ 0, userId) == 1.0f;
+                /* def= */ 0, userId) == 1.0f && mAutoBrightnessEnabled;
 
-        // TODO: luxBasedNitsLowerBound = mMinLuxToNitsSpline(currentLux);
-        float luxBasedNitsLowerBound = 2.0f;
+        float luxBasedNitsLowerBound = mDisplayDeviceConfig.getMinNitsFromLux(mAmbientLux);
 
-        final float nitsLowerBound = isActive ? Math.max(settingNitsLowerBound,
-                 luxBasedNitsLowerBound) : MIN_NITS;
+        final int reason;
+        float minNitsAllowed = -1f; // undefined, if setting is off.
+        final float minBrightnessAllowed;
 
-        final int reason = settingNitsLowerBound > luxBasedNitsLowerBound
-                ? BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND
-                : BrightnessReason.MODIFIER_MIN_LUX;
+        if (isActive) {
+            minNitsAllowed = Math.max(settingNitsLowerBound,
+                    luxBasedNitsLowerBound);
+            minBrightnessAllowed = getBrightnessFromNits(minNitsAllowed);
+            reason = settingNitsLowerBound > luxBasedNitsLowerBound
+                    ? BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND
+                    : BrightnessReason.MODIFIER_MIN_LUX;
+        } else {
+            minBrightnessAllowed = mDisplayDeviceConfig.getLowBrightnessTransitionPoint();
+            reason = 0;
+        }
 
-        // TODO: brightnessLowerBound = nitsToBrightnessSpline(nitsLowerBound);
-        final float brightnessLowerBound = PowerManager.BRIGHTNESS_MIN;
-
-        if (mBrightnessLowerBound != brightnessLowerBound
+        if (mBrightnessLowerBound != minBrightnessAllowed
                 || mReason != reason
                 || mIsActive != isActive) {
             mIsActive = isActive;
             mReason = reason;
             if (DEBUG) {
                 Slog.i(TAG, "isActive: " + isActive
-                        + ", brightnessLowerBound: " + brightnessLowerBound
+                        + ", minBrightnessAllowed: " + minBrightnessAllowed
                         + ", mAmbientLux: " + mAmbientLux
-                        + ", mReason: " + (
-                        mReason == BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND ? "minSetting"
-                                : "lux")
-                        + ", nitsLowerBound: " + nitsLowerBound
+                        + ", mReason: " + (mReason)
+                        + ", minNitsAllowed: " + minNitsAllowed
                 );
             }
-            mBrightnessLowerBound = brightnessLowerBound;
+            mMinNitsAllowed = minNitsAllowed;
+            mBrightnessLowerBound = minBrightnessAllowed;
             mChangeListener.onChanged();
         }
     }
@@ -177,11 +189,23 @@
     }
 
     @Override
+    public void setAutoBrightnessState(int state) {
+        mAutoBrightnessEnabled = state == AUTO_BRIGHTNESS_ENABLED;
+    }
+
+    @Override
     public void dump(PrintWriter pw) {
         pw.println("BrightnessLowLuxModifier:");
         pw.println("  mIsActive=" + mIsActive);
         pw.println("  mBrightnessLowerBound=" + mBrightnessLowerBound);
         pw.println("  mReason=" + mReason);
+        pw.println("  mAmbientLux=" + mAmbientLux);
+        pw.println("  mMinNitsAllowed=" + mMinNitsAllowed);
+    }
+
+    private float getBrightnessFromNits(float nits) {
+        return mDisplayDeviceConfig.getBrightnessFromBacklight(
+                mDisplayDeviceConfig.getBacklightFromNits(nits));
     }
 
     private final class SettingsObserver extends ContentObserver {
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessModifier.java
index 2a3dd87..db5a524d 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessModifier.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessModifier.java
@@ -73,4 +73,9 @@
     public void onAmbientLuxChange(float ambientLux) {
         // do nothing
     }
+
+    @Override
+    public void setAutoBrightnessState(int state) {
+        // do nothing
+    }
 }
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessStateModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessStateModifier.java
index 2234258..1606159c 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessStateModifier.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessStateModifier.java
@@ -48,4 +48,10 @@
      * @param ambientLux current debounced lux.
      */
     void onAmbientLuxChange(float ambientLux);
+
+    /**
+     * Sets the autobrightness state for clampers that need to be aware of the state.
+     * @param state autobrightness state
+     */
+    void setAutoBrightnessState(int state);
 }
diff --git a/services/core/java/com/android/server/display/config/LowBrightnessData.java b/services/core/java/com/android/server/display/config/LowBrightnessData.java
index aa82533..1a4e807 100644
--- a/services/core/java/com/android/server/display/config/LowBrightnessData.java
+++ b/services/core/java/com/android/server/display/config/LowBrightnessData.java
@@ -66,11 +66,13 @@
      * Spline, mapping between backlight and brightness
      */
     public final Spline mBacklightToBrightness;
+    public final Spline mMinLuxToNits;
 
     @VisibleForTesting
     public LowBrightnessData(float transitionPoint, float[] nits,
             float[] backlight, float[] brightness, Spline backlightToNits,
-            Spline nitsToBacklight, Spline brightnessToBacklight, Spline backlightToBrightness) {
+            Spline nitsToBacklight, Spline brightnessToBacklight, Spline backlightToBrightness,
+            Spline minLuxToNits) {
         mTransitionPoint = transitionPoint;
         mNits = nits;
         mBacklight = backlight;
@@ -79,6 +81,7 @@
         mNitsToBacklight = nitsToBacklight;
         mBrightnessToBacklight = brightnessToBacklight;
         mBacklightToBrightness = backlightToBrightness;
+        mMinLuxToNits = minLuxToNits;
     }
 
     @Override
@@ -92,6 +95,7 @@
                 + ", mNitsToBacklight: " + mNitsToBacklight
                 + ", mBrightnessToBacklight: " + mBrightnessToBacklight
                 + ", mBacklightToBrightness: " + mBacklightToBrightness
+                + ", mMinLuxToNits: " + mMinLuxToNits
                 + "} ";
     }
 
@@ -132,11 +136,40 @@
             brightness[i] = brightnessList.get(i);
         }
 
+        final NitsMap map = lbm.getLuxToMinimumNitsMap();
+        if (map == null) {
+            Slog.e(TAG, "Invalid min lux to nits mapping");
+            return null;
+        }
+        final List<Point> points = map.getPoint();
+        final int size = points.size();
+
+        float[] minLux = new float[size];
+        float[] minNits = new float[size];
+
+        int i = 0;
+        for (Point point : points) {
+            minLux[i] = point.getValue().floatValue();
+            minNits[i] = point.getNits().floatValue();
+            if (i > 0) {
+                if (minLux[i] < minLux[i - 1]) {
+                    Slog.e(TAG, "minLuxToNitsSpline must be non-decreasing, ignoring rest "
+                            + " of configuration. Value: " + minLux[i] + " < " + minLux[i - 1]);
+                }
+                if (minNits[i] < minNits[i - 1]) {
+                    Slog.e(TAG, "minLuxToNitsSpline must be non-decreasing, ignoring rest "
+                            + " of configuration. Nits: " + minNits[i] + " < " + minNits[i - 1]);
+                }
+            }
+            ++i;
+        }
+
         return new LowBrightnessData(transitionPoints, nits, backlight, brightness,
                 Spline.createSpline(backlight, nits),
                 Spline.createSpline(nits, backlight),
                 Spline.createSpline(brightness, backlight),
-                Spline.createSpline(backlight, brightness)
-                );
+                Spline.createSpline(backlight, brightness),
+                Spline.createSpline(minLux, minNits)
+        );
     }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
index 097daf2..5563cae 100644
--- a/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
+++ b/services/core/java/com/android/server/notification/NotificationAttentionHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import static android.app.Flags.updateRankingTime;
 import static android.app.Notification.FLAG_INSISTENT;
 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
@@ -496,6 +497,11 @@
                     Slog.v(TAG, "INTERRUPTIVENESS: "
                             + record.getKey() + " is interruptive: alerted");
                 }
+                if (updateRankingTime()) {
+                    if (buzz || beep) {
+                        record.resetRankingTime();
+                    }
+                }
             }
         }
         final int buzzBeepBlinkLoggingCode =
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9fcdfdd..ca3db2c 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -142,6 +142,7 @@
 import static android.view.contentprotection.flags.Flags.rapidClearNotificationsByListenerAppOpEnabled;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
+import static android.app.Flags.updateRankingTime;
 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
@@ -238,9 +239,6 @@
 import android.database.ContentObserver;
 import android.graphics.drawable.Icon;
 import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.AudioManagerInternal;
-import android.media.IRingtonePlayer;
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Binder;
@@ -612,8 +610,7 @@
     PackageManagerInternal mPackageManagerInternal;
     private PermissionManager mPermissionManager;
     private PermissionPolicyInternal mPermissionPolicyInternal;
-    AudioManager mAudioManager;
-    AudioManagerInternal mAudioManagerInternal;
+
     // Can be null for wear
     @Nullable StatusBarManagerInternal mStatusBar;
     private WindowManagerInternal mWindowManagerInternal;
@@ -641,34 +638,12 @@
     private final HandlerThread mRankingThread = new HandlerThread("ranker",
             Process.THREAD_PRIORITY_BACKGROUND);
 
-    private LogicalLight mNotificationLight;
-    LogicalLight mAttentionLight;
-
-    private boolean mUseAttentionLight;
-    boolean mHasLight = true;
-    boolean mSystemReady;
-
-    private boolean mDisableNotificationEffects;
-    private int mCallState;
-    private String mSoundNotificationKey;
-    private String mVibrateNotificationKey;
-
     private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
             new SparseArray<>();
     private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
     private int mListenerHints;  // right now, all hints are global
     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
 
-    // for enabling and disabling notification pulse behavior
-    boolean mScreenOn = true;
-    protected boolean mInCallStateOffHook = false;
-    boolean mNotificationPulseEnabled;
-
-    private Uri mInCallNotificationUri;
-    private AudioAttributes mInCallNotificationAudioAttributes;
-    private float mInCallNotificationVolume;
-    private Binder mCallNotificationToken = null;
-
     private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver;
 
     // used as a mutex for access to all active notifications & listeners
@@ -696,11 +671,6 @@
     // Used for rate limiting toasts by package.
     private MultiRateLimiter mToastRateLimiter;
 
-    private KeyguardManager mKeyguardManager;
-
-    // The last key in this list owns the hardware.
-    ArrayList<String> mLights = new ArrayList<>();
-
     private AppOpsManager mAppOps;
     private UsageStatsManagerInternal mAppUsageStats;
     private DevicePolicyManagerInternal mDpm;
@@ -725,7 +695,6 @@
     RankingHelper mRankingHelper;
     @VisibleForTesting
     PreferencesHelper mPreferencesHelper;
-    private VibratorHelper mVibratorHelper;
 
     private final UserProfiles mUserProfiles = new UserProfiles();
     private NotificationListeners mListeners;
@@ -751,8 +720,6 @@
     private GroupHelper mGroupHelper;
     private int mAutoGroupAtCount;
     private boolean mIsTelevision;
-    private boolean mIsAutomotive;
-    private boolean mNotificationEffectsEnabledForAutomotive;
     private DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener;
     protected NotificationAttentionHelper mAttentionHelper;
 
@@ -1270,17 +1237,7 @@
         @Override
         public void onSetDisabled(int status) {
             synchronized (mNotificationLock) {
-                if (Flags.refactorAttentionHelper()) {
-                    mAttentionHelper.updateDisableNotificationEffectsLocked(status);
-                } else {
-                    mDisableNotificationEffects =
-                            (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
-                    if (disableNotificationEffects(null) != null) {
-                        // cancel whatever's going on
-                        clearSoundLocked();
-                        clearVibrateLocked();
-                    }
-                }
+                mAttentionHelper.updateDisableNotificationEffectsLocked(status);
             }
         }
 
@@ -1421,13 +1378,7 @@
         public void clearEffects() {
             synchronized (mNotificationLock) {
                 if (DBG) Slog.d(TAG, "clearEffects");
-                if (Flags.refactorAttentionHelper()) {
-                    mAttentionHelper.clearAttentionEffects();
-                } else {
-                    clearSoundLocked();
-                    clearVibrateLocked();
-                    clearLightsLocked();
-                }
+                mAttentionHelper.clearAttentionEffects();
             }
         }
 
@@ -1695,11 +1646,7 @@
                         int changedFlags = data.getFlags() ^ flags;
                         if ((changedFlags & FLAG_SUPPRESS_NOTIFICATION) != 0) {
                             // Suppress notification flag changed, clear any effects
-                            if (Flags.refactorAttentionHelper()) {
-                                mAttentionHelper.clearEffectsLocked(key);
-                            } else {
-                                clearEffectsLocked(key);
-                            }
+                            mAttentionHelper.clearEffectsLocked(key);
                         }
                         data.setFlags(flags);
                         // Shouldn't alert again just because of a flag change.
@@ -1832,53 +1779,6 @@
                 hasSensitiveContent, lifespanMs);
     }
 
-    @GuardedBy("mNotificationLock")
-    void clearSoundLocked() {
-        mSoundNotificationKey = null;
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
-            if (player != null) {
-                player.stopAsync();
-            }
-        } catch (RemoteException e) {
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @GuardedBy("mNotificationLock")
-    void clearVibrateLocked() {
-        mVibrateNotificationKey = null;
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            mVibratorHelper.cancelVibration();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @GuardedBy("mNotificationLock")
-    private void clearLightsLocked() {
-        // light
-        mLights.clear();
-        updateLightsLocked();
-    }
-
-    @GuardedBy("mNotificationLock")
-    private void clearEffectsLocked(String key) {
-        if (key.equals(mSoundNotificationKey)) {
-            clearSoundLocked();
-        }
-        if (key.equals(mVibrateNotificationKey)) {
-            clearVibrateLocked();
-        }
-        boolean removed = mLights.remove(key);
-        if (removed) {
-            updateLightsLocked();
-        }
-    }
-
     protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -2068,27 +1968,6 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
 
-            if (!Flags.refactorAttentionHelper()) {
-                if (action.equals(Intent.ACTION_SCREEN_ON)) {
-                    // Keep track of screen on/off state, but do not turn off the notification light
-                    // until user passes through the lock screen or views the notification.
-                    mScreenOn = true;
-                    updateNotificationPulse();
-                } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
-                    mScreenOn = false;
-                    updateNotificationPulse();
-                } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
-                    mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK
-                        .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
-                    updateNotificationPulse();
-                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
-                    // turn off LED when user passes through lock screen
-                    if (mNotificationLight != null) {
-                        mNotificationLight.turnOff();
-                    }
-                }
-            }
-
             if (action.equals(Intent.ACTION_USER_STOPPED)) {
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 if (userHandle >= 0) {
@@ -2164,8 +2043,6 @@
                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
         private final Uri NOTIFICATION_BUBBLES_URI
                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
-        private final Uri NOTIFICATION_LIGHT_PULSE_URI
-                = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
         private final Uri NOTIFICATION_RATE_LIMIT_URI
                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
         private final Uri NOTIFICATION_HISTORY_ENABLED
@@ -2188,10 +2065,6 @@
             ContentResolver resolver = getContext().getContentResolver();
             resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
                     false, this, UserHandle.USER_ALL);
-            if (!Flags.refactorAttentionHelper()) {
-                resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
-                    false, this, UserHandle.USER_ALL);
-            }
             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
                     false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
@@ -2218,17 +2091,6 @@
 
         public void update(Uri uri) {
             ContentResolver resolver = getContext().getContentResolver();
-            if (!Flags.refactorAttentionHelper()) {
-                if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
-                    boolean pulseEnabled = Settings.System.getIntForUser(resolver,
-                        Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
-                        != 0;
-                    if (mNotificationPulseEnabled != pulseEnabled) {
-                        mNotificationPulseEnabled = pulseEnabled;
-                        updateNotificationPulse();
-                    }
-                }
-            }
             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
@@ -2347,21 +2209,11 @@
 
     // TODO - replace these methods with new fields in the VisibleForTesting constructor
     @VisibleForTesting
-    void setAudioManager(AudioManager audioManager) {
-        mAudioManager = audioManager;
-    }
-
-    @VisibleForTesting
     void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) {
         mStrongAuthTracker = strongAuthTracker;
     }
 
     @VisibleForTesting
-    void setKeyguardManager(KeyguardManager keyguardManager) {
-        mKeyguardManager = keyguardManager;
-    }
-
-    @VisibleForTesting
     ShortcutHelper getShortcutHelper() {
         return mShortcutHelper;
     }
@@ -2372,33 +2224,6 @@
     }
 
     @VisibleForTesting
-    VibratorHelper getVibratorHelper() {
-        return mVibratorHelper;
-    }
-
-    @VisibleForTesting
-    void setVibratorHelper(VibratorHelper helper) {
-        mVibratorHelper = helper;
-    }
-
-    @VisibleForTesting
-    void setHints(int hints) {
-        mListenerHints = hints;
-    }
-
-    @VisibleForTesting
-    void setLights(LogicalLight light) {
-        mNotificationLight = light;
-        mAttentionLight = light;
-        mNotificationPulseEnabled = true;
-    }
-
-    @VisibleForTesting
-    void setScreenOn(boolean on) {
-        mScreenOn = on;
-    }
-
-    @VisibleForTesting
     int getNotificationRecordCount() {
         synchronized (mNotificationLock) {
             int count = mNotificationList.size() + mNotificationsByKey.size()
@@ -2446,12 +2271,6 @@
         return mNotificationsByKey.get(key);
     }
 
-
-    @VisibleForTesting
-    void setSystemReady(boolean systemReady) {
-        mSystemReady = systemReady;
-    }
-
     @VisibleForTesting
     void setHandler(WorkerHandler handler) {
         mHandler = handler;
@@ -2471,13 +2290,8 @@
     }
 
     @VisibleForTesting
-    void setIsAutomotive(boolean isAutomotive) {
-        mIsAutomotive = isAutomotive;
-    }
-
-    @VisibleForTesting
-    void setNotificationEffectsEnabledForAutomotive(boolean isEnabled) {
-        mNotificationEffectsEnabledForAutomotive = isEnabled;
+    void setAttentionHelper(NotificationAttentionHelper nah) {
+        mAttentionHelper = nah;
     }
 
     @VisibleForTesting
@@ -2486,16 +2300,6 @@
     }
 
     @VisibleForTesting
-    void setUsageStats(NotificationUsageStats us) {
-        mUsageStats = us;
-    }
-
-    @VisibleForTesting
-    void setAccessibilityManager(AccessibilityManager am) {
-        mAccessibilityManager = am;
-    }
-
-    @VisibleForTesting
     void setTelecomManager(TelecomManager tm) {
         mTelecomManager = tm;
     }
@@ -2513,7 +2317,7 @@
             DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
             UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
             NotificationHistoryManager historyManager, StatsManager statsManager,
-            TelephonyManager telephonyManager, ActivityManagerInternal ami,
+            ActivityManagerInternal ami,
             MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
             UsageStatsManagerInternal usageStatsManagerInternal,
             TelecomManager telecomManager, NotificationChannelLogger channelLogger,
@@ -2645,7 +2449,6 @@
                 extractorNames);
         mSnoozeHelper = snoozeHelper;
         mGroupHelper = groupHelper;
-        mVibratorHelper = new VibratorHelper(getContext());
         mHistoryManager = historyManager;
 
         // This is a ManagedServices object that keeps track of the listeners.
@@ -2664,43 +2467,9 @@
             mStatusBar.setNotificationDelegate(mNotificationDelegate);
         }
 
-        mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
-        mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
-
-        mInCallNotificationUri = Uri.parse("file://" +
-                resources.getString(R.string.config_inCallNotificationSound));
-        mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
-                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-                .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
-                .build();
-        mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
-
-        mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
-        mHasLight =
-                resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
-
-        // Don't start allowing notifications until the setup wizard has run once.
-        // After that, including subsequent boots, init with notifications turned on.
-        // This works on the first boot because the setup wizard will toggle this
-        // flag at least once and we'll go back to 0 after that.
-        if (0 == Settings.Global.getInt(getContext().getContentResolver(),
-                    Settings.Global.DEVICE_PROVISIONED, 0)) {
-            mDisableNotificationEffects = true;
-        }
         mZenModeHelper.initZenMode();
         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
 
-        if (mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
-            telephonyManager.listen(new PhoneStateListener() {
-                @Override
-                public void onCallStateChanged(int state, String incomingNumber) {
-                    if (mCallState == state) return;
-                    if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
-                    mCallState = state;
-                }
-            }, PhoneStateListener.LISTEN_CALL_STATE);
-        }
-
         mSettingsObserver = new SettingsObserver(mHandler);
 
         mArchive = new Archive(resources.getInteger(
@@ -2709,11 +2478,6 @@
         mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
                 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
 
-        mIsAutomotive =
-                mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
-        mNotificationEffectsEnabledForAutomotive =
-                resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive);
-
         mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
                 com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
 
@@ -2733,22 +2497,14 @@
 
         mToastRateLimiter = toastRateLimiter;
 
-        if (Flags.refactorAttentionHelper()) {
-            mAttentionHelper = new NotificationAttentionHelper(getContext(), lightsManager,
+        mAttentionHelper = new NotificationAttentionHelper(getContext(), lightsManager,
                 mAccessibilityManager, mPackageManagerClient, userManager, usageStats,
                 mNotificationManagerPrivate, mZenModeHelper, flagResolver);
-        }
 
         // register for various Intents.
         // If this is called within a test, make sure to unregister the intent receivers by
         // calling onDestroy()
         IntentFilter filter = new IntentFilter();
-        if (!Flags.refactorAttentionHelper()) {
-            filter.addAction(Intent.ACTION_SCREEN_ON);
-            filter.addAction(Intent.ACTION_SCREEN_OFF);
-            filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
-            filter.addAction(Intent.ACTION_USER_PRESENT);
-        }
         filter.addAction(Intent.ACTION_USER_STOPPED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_ADDED);
@@ -2874,7 +2630,6 @@
                 new NotificationHistoryManager(getContext(), handler),
                 mStatsManager = (StatsManager) getContext().getSystemService(
                         Context.STATS_MANAGER),
-                getContext().getSystemService(TelephonyManager.class),
                 LocalServices.getService(ActivityManagerInternal.class),
                 createToastRateLimiter(), new PermissionHelper(getContext(),
                         AppGlobals.getPackageManager(),
@@ -3054,14 +2809,7 @@
     @VisibleForTesting
     void onBootPhase(int phase, Looper mainLooper) {
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
-            // no beeping until we're basically done booting
-            mSystemReady = true;
-
-            // Grab our optional AudioService
-            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
-            mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
-            mKeyguardManager = getContext().getSystemService(KeyguardManager.class);
             mZenModeHelper.onSystemReady();
             RoleObserver roleObserver = new RoleObserver(getContext(),
                     getContext().getSystemService(RoleManager.class),
@@ -3080,9 +2828,7 @@
             }
             registerNotificationPreferencesPullers();
             new LockPatternUtils(getContext()).registerStrongAuthTracker(mStrongAuthTracker);
-            if (Flags.refactorAttentionHelper()) {
-                mAttentionHelper.onSystemReady();
-            }
+            mAttentionHelper.onSystemReady();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             // This observer will force an update when observe is called, causing us to
             // bind to listener services.
@@ -6866,33 +6612,6 @@
         return null;
     }
 
-    private String disableNotificationEffects(NotificationRecord record) {
-        if (mDisableNotificationEffects) {
-            return "booleanState";
-        }
-        if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
-            return "listenerHints";
-        }
-        if (record != null && record.getAudioAttributes() != null) {
-            if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
-                if (record.getAudioAttributes().getUsage()
-                        != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
-                    return "listenerNoti";
-                }
-            }
-            if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
-                if (record.getAudioAttributes().getUsage()
-                        == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
-                    return "listenerCall";
-                }
-            }
-        }
-        if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
-            return "callState";
-        }
-        return null;
-    }
-
     // Gets packages that have requested notification permission, and whether that has been
     // allowed/denied, for all users on the device.
     // Returns a single map containing that info keyed by (uid, package name) for all users.
@@ -7061,33 +6780,10 @@
                     dumpNotificationRecords(pw, filter);
                 }
                 if (!filter.filtered) {
-                    N = mLights.size();
-                    if (N > 0) {
-                        pw.println("  Lights List:");
-                        for (int i=0; i<N; i++) {
-                            if (i == N - 1) {
-                                pw.print("  > ");
-                            } else {
-                                pw.print("    ");
-                            }
-                            pw.println(mLights.get(i));
-                        }
-                        pw.println("  ");
-                    }
-                    pw.println("  mUseAttentionLight=" + mUseAttentionLight);
-                    pw.println("  mHasLight=" + mHasLight);
-                    pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
-                    pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
-                    pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
-                    pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
-                    pw.println("  mCallState=" + callStateToString(mCallState));
-                    pw.println("  mSystemReady=" + mSystemReady);
                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
                     pw.println("  hideSilentStatusBar="
                             + mPreferencesHelper.shouldHideSilentStatusIcons());
-                    if (Flags.refactorAttentionHelper()) {
-                        mAttentionHelper.dump(pw, "    ", filter);
-                    }
+                    mAttentionHelper.dump(pw, "    ", filter);
                 }
                 pw.println("  mArchive=" + mArchive.toString());
                 mArchive.dumpImpl(pw, filter);
@@ -8379,11 +8075,7 @@
             boolean wasPosted = removeFromNotificationListsLocked(r);
             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null,
                     SystemClock.elapsedRealtime());
-            if (Flags.refactorAttentionHelper()) {
-                mAttentionHelper.updateLightsLocked();
-            } else {
-                updateLightsLocked();
-            }
+            mAttentionHelper.updateLightsLocked();
             if (isSnoozable(r)) {
                 if (mSnoozeCriterionId != null) {
                     mAssistants.notifyAssistantSnoozedLocked(r, mSnoozeCriterionId);
@@ -8519,11 +8211,7 @@
                     cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
                             mSendDelete, childrenFlagChecker, mReason,
                             mCancellationElapsedTimeMs);
-                    if (Flags.refactorAttentionHelper()) {
-                        mAttentionHelper.updateLightsLocked();
-                    } else {
-                        updateLightsLocked();
-                    }
+                    mAttentionHelper.updateLightsLocked();
                     if (mShortcutHelper != null) {
                         mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
                                 true /* isRemoved */,
@@ -8802,6 +8490,11 @@
                         r.isUpdate = true;
                         final boolean isInterruptive = isVisuallyInterruptive(old, r);
                         r.setTextChanged(isInterruptive);
+                        if (updateRankingTime()) {
+                            if (isInterruptive) {
+                                r.resetRankingTime();
+                            }
+                        }
                     }
 
                     mNotificationsByKey.put(n.getKey(), r);
@@ -8818,14 +8511,10 @@
 
                     int buzzBeepBlinkLoggingCode = 0;
                     if (!r.isHidden()) {
-                        if (Flags.refactorAttentionHelper()) {
-                            buzzBeepBlinkLoggingCode = mAttentionHelper.buzzBeepBlinkLocked(r,
+                        buzzBeepBlinkLoggingCode = mAttentionHelper.buzzBeepBlinkLocked(r,
                                 new NotificationAttentionHelper.Signals(
-                                    mUserProfiles.isCurrentProfile(r.getUserId()),
-                                    mListenerHints));
-                        } else {
-                            buzzBeepBlinkLoggingCode = buzzBeepBlinkLocked(r);
-                        }
+                                        mUserProfiles.isCurrentProfile(r.getUserId()),
+                                        mListenerHints));
                     }
 
                     if (notification.getSmallIcon() != null) {
@@ -9150,425 +8839,6 @@
         }
     }
 
-    @VisibleForTesting
-    @GuardedBy("mNotificationLock")
-    /**
-     * Determine whether this notification should attempt to make noise, vibrate, or flash the LED
-     * @return buzzBeepBlink - bitfield (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)
-     */
-    int buzzBeepBlinkLocked(NotificationRecord record) {
-        if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
-            return 0;
-        }
-        boolean buzz = false;
-        boolean beep = false;
-        boolean blink = false;
-
-        final String key = record.getKey();
-
-        // Should this notification make noise, vibe, or use the LED?
-        final boolean aboveThreshold =
-                mIsAutomotive
-                        ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
-                        : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
-        // Remember if this notification already owns the notification channels.
-        boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
-        boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
-        // These are set inside the conditional if the notification is allowed to make noise.
-        boolean hasValidVibrate = false;
-        boolean hasValidSound = false;
-        boolean sentAccessibilityEvent = false;
-
-        // If the notification will appear in the status bar, it should send an accessibility event
-        final boolean suppressedByDnd = record.isIntercepted()
-                && (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
-        if (!record.isUpdate
-                && record.getImportance() > IMPORTANCE_MIN
-                && !suppressedByDnd
-                && isNotificationForCurrentUser(record)) {
-            sendAccessibilityEvent(record);
-            sentAccessibilityEvent = true;
-        }
-
-        if (aboveThreshold && isNotificationForCurrentUser(record)) {
-            if (mSystemReady && mAudioManager != null) {
-                Uri soundUri = record.getSound();
-                hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
-                VibrationEffect vibration = record.getVibration();
-                // Demote sound to vibration if vibration missing & phone in vibration mode.
-                if (vibration == null
-                        && hasValidSound
-                        && (mAudioManager.getRingerModeInternal()
-                        == AudioManager.RINGER_MODE_VIBRATE)
-                        && mAudioManager.getStreamVolume(
-                        AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
-                    boolean insistent = (record.getFlags() & Notification.FLAG_INSISTENT) != 0;
-                    vibration = mVibratorHelper.createFallbackVibration(insistent);
-                }
-                hasValidVibrate = vibration != null;
-                boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
-                if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
-                    if (!sentAccessibilityEvent) {
-                        sendAccessibilityEvent(record);
-                        sentAccessibilityEvent = true;
-                    }
-                    if (DBG) Slog.v(TAG, "Interrupting!");
-                    boolean isInsistentUpdate = isInsistentUpdate(record);
-                    if (hasValidSound) {
-                        if (isInsistentUpdate) {
-                            // don't reset insistent sound, it's jarring
-                            beep = true;
-                        } else {
-                            if (isInCall()) {
-                                playInCallNotification();
-                                beep = true;
-                            } else {
-                                beep = playSound(record, soundUri);
-                            }
-                            if (beep) {
-                                mSoundNotificationKey = key;
-                            }
-                        }
-                    }
-
-                    final boolean ringerModeSilent =
-                            mAudioManager.getRingerModeInternal()
-                                    == AudioManager.RINGER_MODE_SILENT;
-                    if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
-                        if (isInsistentUpdate) {
-                            buzz = true;
-                        } else {
-                            buzz = playVibration(record, vibration, hasValidSound);
-                            if (buzz) {
-                                mVibrateNotificationKey = key;
-                            }
-                        }
-                    }
-
-                    // Try to start flash notification event whenever an audible and non-suppressed
-                    // notification is received
-                    mAccessibilityManager.startFlashNotificationEvent(getContext(),
-                            AccessibilityManager.FLASH_REASON_NOTIFICATION,
-                            record.getSbn().getPackageName());
-
-                } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
-                    hasValidSound = false;
-                }
-            }
-        }
-        // If a notification is updated to remove the actively playing sound or vibrate,
-        // cancel that feedback now
-        if (wasBeep && !hasValidSound) {
-            clearSoundLocked();
-        }
-        if (wasBuzz && !hasValidVibrate) {
-            clearVibrateLocked();
-        }
-
-        // light
-        // release the light
-        boolean wasShowLights = mLights.remove(key);
-        if (canShowLightsLocked(record, aboveThreshold)) {
-            mLights.add(key);
-            updateLightsLocked();
-            if (mUseAttentionLight && mAttentionLight != null) {
-                mAttentionLight.pulse();
-            }
-            blink = true;
-        } else if (wasShowLights) {
-            updateLightsLocked();
-        }
-        final int buzzBeepBlink = (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0);
-        if (buzzBeepBlink > 0) {
-            // Ignore summary updates because we don't display most of the information.
-            if (record.getSbn().isGroup() && record.getSbn().getNotification().isGroupSummary()) {
-                if (DEBUG_INTERRUPTIVENESS) {
-                    Slog.v(TAG, "INTERRUPTIVENESS: "
-                            + record.getKey() + " is not interruptive: summary");
-                }
-            } else if (record.canBubble()) {
-                if (DEBUG_INTERRUPTIVENESS) {
-                    Slog.v(TAG, "INTERRUPTIVENESS: "
-                            + record.getKey() + " is not interruptive: bubble");
-                }
-            } else {
-                record.setInterruptive(true);
-                if (DEBUG_INTERRUPTIVENESS) {
-                    Slog.v(TAG, "INTERRUPTIVENESS: "
-                            + record.getKey() + " is interruptive: alerted");
-                }
-            }
-            MetricsLogger.action(record.getLogMaker()
-                    .setCategory(MetricsEvent.NOTIFICATION_ALERT)
-                    .setType(MetricsEvent.TYPE_OPEN)
-                    .setSubtype(buzzBeepBlink));
-            EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0, 0);
-        }
-        record.setAudiblyAlerted(buzz || beep);
-        return buzzBeepBlink;
-    }
-
-    @GuardedBy("mNotificationLock")
-    boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
-        // device lacks light
-        if (!mHasLight) {
-            return false;
-        }
-        // user turned lights off globally
-        if (!mNotificationPulseEnabled) {
-            return false;
-        }
-        // the notification/channel has no light
-        if (record.getLight() == null) {
-            return false;
-        }
-        // unimportant notification
-        if (!aboveThreshold) {
-            return false;
-        }
-        // suppressed due to DND
-        if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
-            return false;
-        }
-        // Suppressed because it's a silent update
-        final Notification notification = record.getNotification();
-        if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
-            return false;
-        }
-        // Suppressed because another notification in its group handles alerting
-        if (record.getSbn().isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
-            return false;
-        }
-        // not if in call
-        if (isInCall()) {
-            return false;
-        }
-        // check current user
-        if (!isNotificationForCurrentUser(record)) {
-            return false;
-        }
-        // Light, but only when the screen is off
-        return true;
-    }
-
-    @GuardedBy("mNotificationLock")
-    boolean isInsistentUpdate(final NotificationRecord record) {
-        return (Objects.equals(record.getKey(), mSoundNotificationKey)
-                || Objects.equals(record.getKey(), mVibrateNotificationKey))
-                && isCurrentlyInsistent();
-    }
-
-    @GuardedBy("mNotificationLock")
-    boolean isCurrentlyInsistent() {
-        return isLoopingRingtoneNotification(mNotificationsByKey.get(mSoundNotificationKey))
-                || isLoopingRingtoneNotification(mNotificationsByKey.get(mVibrateNotificationKey));
-    }
-
-    @GuardedBy("mNotificationLock")
-    boolean shouldMuteNotificationLocked(final NotificationRecord record) {
-        // Suppressed because it's a silent update
-        final Notification notification = record.getNotification();
-        if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
-            return true;
-        }
-
-        // Suppressed because a user manually unsnoozed something (or similar)
-        if (record.shouldPostSilently()) {
-            return true;
-        }
-
-        // muted by listener
-        final String disableEffects = disableNotificationEffects(record);
-        if (disableEffects != null) {
-            ZenLog.traceDisableEffects(record, disableEffects);
-            return true;
-        }
-
-        // suppressed due to DND
-        if (record.isIntercepted()) {
-            return true;
-        }
-
-        // Suppressed because another notification in its group handles alerting
-        if (record.getSbn().isGroup()) {
-            if (notification.suppressAlertingDueToGrouping()) {
-                return true;
-            }
-        }
-
-        // Suppressed for being too recently noisy
-        final String pkg = record.getSbn().getPackageName();
-        if (mUsageStats.isAlertRateLimited(pkg)) {
-            Slog.e(TAG, "Muting recently noisy " + record.getKey());
-            return true;
-        }
-
-        // A different looping ringtone, such as an incoming call is playing
-        if (isCurrentlyInsistent() && !isInsistentUpdate(record)) {
-            return true;
-        }
-
-        // Suppressed since it's a non-interruptive update to a bubble-suppressed notification
-        final boolean isBubbleOrOverflowed = record.canBubble() && (record.isFlagBubbleRemoved()
-                || record.getNotification().isBubbleNotification());
-        if (record.isUpdate && !record.isInterruptive() && isBubbleOrOverflowed
-                && record.getNotification().getBubbleMetadata() != null) {
-            if (record.getNotification().getBubbleMetadata().isNotificationSuppressed()) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @GuardedBy("mNotificationLock")
-    private boolean isLoopingRingtoneNotification(final NotificationRecord playingRecord) {
-        if (playingRecord != null) {
-            if (playingRecord.getAudioAttributes().getUsage() == USAGE_NOTIFICATION_RINGTONE
-                    && (playingRecord.getNotification().flags & FLAG_INSISTENT) != 0) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean playSound(final NotificationRecord record, Uri soundUri) {
-        final boolean shouldPlay;
-        if (focusExclusiveWithRecording()) {
-            // flagged path
-            shouldPlay = mAudioManager.shouldNotificationSoundPlay(record.getAudioAttributes());
-        } else {
-            // legacy path
-            // play notifications if there is no user of exclusive audio focus
-            // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
-            //   VIBRATE ringer mode)
-            shouldPlay = !mAudioManager.isAudioFocusExclusive()
-                    && (mAudioManager.getStreamVolume(
-                        AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0);
-        }
-        if (!shouldPlay) {
-            if (DBG) Slog.v(TAG, "Not playing sound " + soundUri + " due to focus/volume");
-            return false;
-        }
-
-        boolean looping = (record.getNotification().flags & FLAG_INSISTENT) != 0;
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
-            if (player != null) {
-                if (DBG) {
-                    Slog.v(TAG, "Playing sound " + soundUri
-                            + " with attributes " + record.getAudioAttributes());
-                }
-                player.playAsync(soundUri, record.getSbn().getUser(), looping,
-                        record.getAudioAttributes(), 1.0f);
-                return true;
-            }
-        } catch (RemoteException e) {
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-        return false;
-    }
-
-    private boolean playVibration(final NotificationRecord record, final VibrationEffect effect,
-            boolean delayVibForSound) {
-        // Escalate privileges so we can use the vibrator even if the
-        // notifying app does not have the VIBRATE permission.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            if (delayVibForSound) {
-                new Thread(() -> {
-                    // delay the vibration by the same amount as the notification sound
-                    final int waitMs = mAudioManager.getFocusRampTimeMs(
-                            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
-                            record.getAudioAttributes());
-                    if (DBG) {
-                        Slog.v(TAG, "Delaying vibration for notification "
-                                + record.getKey() + " by " + waitMs + "ms");
-                    }
-                    try {
-                        Thread.sleep(waitMs);
-                    } catch (InterruptedException e) { }
-                    // Notifications might be canceled before it actually vibrates due to waitMs,
-                    // so need to check that the notification is still valid for vibrate.
-                    synchronized (mNotificationLock) {
-                        if (mNotificationsByKey.get(record.getKey()) != null) {
-                            if (record.getKey().equals(mVibrateNotificationKey)) {
-                                vibrate(record, effect, true);
-                            } else {
-                                if (DBG) {
-                                    Slog.v(TAG, "No vibration for notification "
-                                            + record.getKey() + ": a new notification is "
-                                            + "vibrating, or effects were cleared while waiting");
-                                }
-                            }
-                        } else {
-                            Slog.w(TAG, "No vibration for canceled notification "
-                                    + record.getKey());
-                        }
-                    }
-                }).start();
-            } else {
-                vibrate(record, effect, false);
-            }
-            return true;
-        } finally{
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    private void vibrate(NotificationRecord record, VibrationEffect effect, boolean delayed) {
-        // We need to vibrate as "android" so we can breakthrough DND. VibratorManagerService
-        // doesn't have a concept of vibrating on an app's behalf, so add the app information
-        // to the reason so we can still debug from bugreports
-        String reason = "Notification (" + record.getSbn().getOpPkg() + " "
-                + record.getSbn().getUid() + ") " + (delayed ? "(Delayed)" : "");
-        mVibratorHelper.vibrate(effect, record.getAudioAttributes(), reason);
-    }
-
-    private boolean isNotificationForCurrentUser(NotificationRecord record) {
-        final int currentUser;
-        final long token = Binder.clearCallingIdentity();
-        try {
-            currentUser = ActivityManager.getCurrentUser();
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-        return (record.getUserId() == UserHandle.USER_ALL ||
-                record.getUserId() == currentUser ||
-                mUserProfiles.isCurrentProfile(record.getUserId()));
-    }
-
-    protected void playInCallNotification() {
-        final ContentResolver cr = getContext().getContentResolver();
-        if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
-                && Settings.Secure.getIntForUser(cr,
-                Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1, cr.getUserId()) != 0) {
-            new Thread() {
-                @Override
-                public void run() {
-                    final long identity = Binder.clearCallingIdentity();
-                    try {
-                        final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
-                        if (player != null) {
-                            if (mCallNotificationToken != null) {
-                                player.stop(mCallNotificationToken);
-                            }
-                            mCallNotificationToken = new Binder();
-                            player.play(mCallNotificationToken, mInCallNotificationUri,
-                                    mInCallNotificationAudioAttributes,
-                                    mInCallNotificationVolume, false);
-                        }
-                    } catch (RemoteException e) {
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
-                }
-            }.start();
-        }
-    }
-
     @GuardedBy("mToastQueue")
     void showNextToastLocked(boolean lastToastWasTextRecord) {
         if (mIsCurrentToastShown) {
@@ -9840,13 +9110,10 @@
                     || interruptiveChanged;
             if (interceptBefore && !record.isIntercepted()
                     && record.isNewEnoughForAlerting(System.currentTimeMillis())) {
-                if (Flags.refactorAttentionHelper()) {
-                    mAttentionHelper.buzzBeepBlinkLocked(record,
-                        new NotificationAttentionHelper.Signals(
-                            mUserProfiles.isCurrentProfile(record.getUserId()), mListenerHints));
-                } else {
-                    buzzBeepBlinkLocked(record);
-                }
+
+                mAttentionHelper.buzzBeepBlinkLocked(record,
+                        new NotificationAttentionHelper.Signals(mUserProfiles.isCurrentProfile(
+                                record.getUserId()), mListenerHints));
 
                 // Log alert after change in intercepted state to Zen Log as well
                 ZenLog.traceAlertOnUpdatedIntercept(record);
@@ -10113,37 +9380,6 @@
         return (x < low) ? low : ((x > high) ? high : x);
     }
 
-    void sendAccessibilityEvent(NotificationRecord record) {
-        if (!mAccessibilityManager.isEnabled()) {
-            return;
-        }
-
-        final Notification notification = record.getNotification();
-        final CharSequence packageName = record.getSbn().getPackageName();
-        final AccessibilityEvent event =
-            AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
-        event.setPackageName(packageName);
-        event.setClassName(Notification.class.getName());
-        final int visibilityOverride = record.getPackageVisibilityOverride();
-        final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE
-                ? notification.visibility : visibilityOverride;
-        final int userId = record.getUser().getIdentifier();
-        final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId);
-        if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) {
-            // Emit the public version if we're on the lockscreen and this notification isn't
-            // publicly visible.
-            event.setParcelableData(notification.publicVersion);
-        } else {
-            event.setParcelableData(notification);
-        }
-        final CharSequence tickerText = notification.tickerText;
-        if (!TextUtils.isEmpty(tickerText)) {
-            event.getText().add(tickerText);
-        }
-
-        mAccessibilityManager.sendAccessibilityEvent(event);
-    }
-
     /**
      * Removes all NotificationsRecords with the same key as the given notification record
      * from both lists. Do not call this method while iterating over either list.
@@ -10228,22 +9464,7 @@
                 }
             }
 
-            if (Flags.refactorAttentionHelper()) {
-                mAttentionHelper.clearEffectsLocked(canceledKey);
-            } else {
-                // sound
-                if (canceledKey.equals(mSoundNotificationKey)) {
-                    clearSoundLocked();
-                }
-
-                // vibrate
-                if (canceledKey.equals(mVibrateNotificationKey)) {
-                    clearVibrateLocked();
-                }
-
-                // light
-                mLights.remove(canceledKey);
-            }
+            mAttentionHelper.clearEffectsLocked(canceledKey);
         }
 
         // Record usage stats
@@ -10592,11 +9813,7 @@
                             cancellationElapsedTimeMs);
                 }
             }
-            if (Flags.refactorAttentionHelper()) {
-                mAttentionHelper.updateLightsLocked();
-            } else {
-                updateLightsLocked();
-            }
+            mAttentionHelper.updateLightsLocked();
         }
     }
 
@@ -10745,37 +9962,6 @@
     }
 
     @GuardedBy("mNotificationLock")
-    void updateLightsLocked()
-    {
-        if (mNotificationLight == null) {
-            return;
-        }
-
-        // handle notification lights
-        NotificationRecord ledNotification = null;
-        while (ledNotification == null && !mLights.isEmpty()) {
-            final String owner = mLights.get(mLights.size() - 1);
-            ledNotification = mNotificationsByKey.get(owner);
-            if (ledNotification == null) {
-                Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
-                mLights.remove(owner);
-            }
-        }
-
-        // Don't flash while we are in a call or screen is on
-        if (ledNotification == null || isInCall() || mScreenOn) {
-            mNotificationLight.turnOff();
-        } else {
-            NotificationRecord.Light light = ledNotification.getLight();
-            if (light != null && mNotificationPulseEnabled) {
-                // pulse repeatedly
-                mNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED,
-                        light.onMs, light.offMs);
-            }
-        }
-    }
-
-    @GuardedBy("mNotificationLock")
     @NonNull
     List<NotificationRecord> findCurrentAndSnoozedGroupNotificationsLocked(String pkg,
             String groupKey, int userId) {
@@ -10974,12 +10160,6 @@
         }
     }
 
-    private void updateNotificationPulse() {
-        synchronized (mNotificationLock) {
-            updateLightsLocked();
-        }
-    }
-
     protected boolean isCallingUidSystem() {
         final int uid = Binder.getCallingUid();
         return uid == Process.SYSTEM_UID;
@@ -11350,18 +10530,6 @@
         }
     }
 
-    private boolean isInCall() {
-        if (mInCallStateOffHook) {
-            return true;
-        }
-        int audioMode = mAudioManager.getMode();
-        if (audioMode == AudioManager.MODE_IN_CALL
-                || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
-            return true;
-        }
-        return false;
-    }
-
     public class NotificationAssistants extends ManagedServices {
         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
 
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 6ab4b99..7e58d0a 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.notification;
 
+import static android.app.Flags.updateRankingTime;
 import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
@@ -65,14 +66,12 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.widget.RemoteViews;
-
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.uri.UriGrantsManagerInternal;
-
 import dalvik.annotation.optimization.NeverCompile;
 
 import java.io.PrintWriter;
@@ -1090,8 +1089,14 @@
     private long calculateRankingTimeMs(long previousRankingTimeMs) {
         Notification n = getNotification();
         // Take developer provided 'when', unless it's in the future.
-        if (n.when != 0 && n.when <= getSbn().getPostTime()) {
-            return n.when;
+        if (updateRankingTime()) {
+            if (n.when != n.creationTime && n.when <= getSbn().getPostTime()){
+                return n.when;
+            }
+        } else {
+            if (n.when != 0 && n.when <= getSbn().getPostTime()) {
+                return n.when;
+            }
         }
         // If we've ranked a previous instance with a timestamp, inherit it. This case is
         // important in order to have ranking stability for updating notifications.
@@ -1193,6 +1198,12 @@
         return mPeopleOverride;
     }
 
+    public void resetRankingTime() {
+        if (updateRankingTime()) {
+            mRankingTimeMs = calculateRankingTimeMs(getSbn().getPostTime());
+        }
+    }
+
     public void setInterruptive(boolean interruptive) {
         mIsInterruptive = interruptive;
         final long now = System.currentTimeMillis();
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index ec98fff..e2f4d18 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -293,9 +293,26 @@
             return START_PERMISSION_DENIED;
         }
 
-        Slog.i(TAG, TextUtils.formatSimple("Unarchival is starting for: %s", packageName));
-
         try {
+            boolean openAppDetailsIfOngoingUnarchival = getAppOpsManager().checkOp(
+                    AppOpsManager.OP_UNARCHIVAL_CONFIRMATION, callingUid, callerPackageName)
+                    == MODE_ALLOWED;
+            if (openAppDetailsIfOngoingUnarchival) {
+                PackageInstaller.SessionInfo activeUnarchivalSession = getActiveUnarchivalSession(
+                        packageName, userId);
+                if (activeUnarchivalSession != null) {
+                    mPm.mHandler.post(() -> {
+                        Slog.i(TAG, "Opening app details page for ongoing unarchival of: "
+                                + packageName);
+                        getLauncherApps().startPackageInstallerSessionDetailsActivity(
+                                activeUnarchivalSession, null, null);
+                    });
+                    return START_ABORTED;
+                }
+            }
+
+            Slog.i(TAG, TextUtils.formatSimple("Unarchival is starting for: %s", packageName));
+
             requestUnarchive(packageName, callerPackageName,
                     getOrCreateLauncherListener(userId, packageName),
                     UserHandle.of(userId),
@@ -793,8 +810,27 @@
             }
         }
 
-        mPm.mHandler.post(
-                () -> unarchiveInternal(packageName, userHandle, installerPackage, draftSessionId));
+        mPm.mHandler.post(() -> {
+            Slog.i(TAG, "Starting app unarchival for: " + packageName);
+            unarchiveInternal(packageName, userHandle, installerPackage,
+                    draftSessionId);
+        });
+    }
+
+    @Nullable
+    private PackageInstaller.SessionInfo getActiveUnarchivalSession(String packageName,
+            int userId) {
+        List<PackageInstaller.SessionInfo> activeSessions =
+                mPm.mInstallerService.getAllSessions(userId).getList();
+        for (int idx = 0; idx < activeSessions.size(); idx++) {
+            PackageInstaller.SessionInfo activeSession = activeSessions.get(idx);
+            if (activeSession.appPackageName.equals(packageName)
+                    && activeSession.userId == userId && activeSession.active
+                    && activeSession.isUnarchival()) {
+                return activeSession;
+            }
+        }
+        return null;
     }
 
     private void requestUnarchiveConfirmation(String packageName, IntentSender statusReceiver,
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 88e7596..f5ac830 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1717,20 +1717,26 @@
                         return false;
                     }
 
-                    if (android.multiuser.Flags.showSetScreenLockDialog()) {
-                        // Show the prompt to set a new screen lock if the device does not have one
-                        final KeyguardManager km = mContext.getSystemService(KeyguardManager.class);
-                        if (km != null && !km.isDeviceSecure()) {
-                            Intent setScreenLockPromptIntent =
-                                    SetScreenLockDialogActivity
-                                            .createBaseIntent(LAUNCH_REASON_DISABLE_QUIET_MODE);
-                            setScreenLockPromptIntent.putExtra(EXTRA_ORIGIN_USER_ID, userId);
-                            mContext.startActivity(setScreenLockPromptIntent);
-                            return false;
-                        }
+                    final KeyguardManager km = mContext.getSystemService(KeyguardManager.class);
+                    if (km != null && km.isDeviceSecure()) {
+                        showConfirmCredentialToDisableQuietMode(userId, target, callingPackage);
+                        return false;
+                    } else if (km != null && !km.isDeviceSecure()
+                            && android.multiuser.Flags.showSetScreenLockDialog()
+                            // TODO(b/330720545): Add a better way to accomplish this, also use it
+                            //  to block profile creation w/o device credentials present.
+                            && Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                                Settings.Secure.USER_SETUP_COMPLETE, 0, userId) == 1) {
+                        Intent setScreenLockPromptIntent =
+                                SetScreenLockDialogActivity
+                                        .createBaseIntent(LAUNCH_REASON_DISABLE_QUIET_MODE);
+                        setScreenLockPromptIntent.putExtra(EXTRA_ORIGIN_USER_ID, userId);
+                        mContext.startActivity(setScreenLockPromptIntent);
+                        return false;
+                    } else {
+                        Slog.w(LOG_TAG, "Allowing profile unlock even when device credentials "
+                                + "are not set for user " + userId);
                     }
-                    showConfirmCredentialToDisableQuietMode(userId, target, callingPackage);
-                    return false;
                 }
             }
             final boolean hasUnifiedChallenge =
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 18d2718..9b2ca39 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5786,7 +5786,7 @@
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
-        if (isTopRootTaskInDisplayArea() && mAtmService.mController != null) {
+        if (mAtmService.mController != null && isTopRootTaskInDisplayArea()) {
             ActivityRecord next = topRunningActivity(null, task.mTaskId);
             if (next == null) {
                 next = topRunningActivity(null, INVALID_TASK_ID);
@@ -5830,6 +5830,15 @@
                 + tr.mTaskId);
 
         if (mTransitionController.isShellTransitionsEnabled()) {
+            // TODO(b/277838915): Consider to make it concurrent to eliminate the special case.
+            final Transition collecting = mTransitionController.getCollectingTransition();
+            if (collecting != null && collecting.mType == TRANSIT_OPEN) {
+                // It can be a CLOSING participate of an OPEN transition. This avoids the deferred
+                // transition from moving task to back after the task was moved to front.
+                collecting.collect(tr);
+                moveTaskToBackInner(tr, collecting);
+                return true;
+            }
             final Transition transition = new Transition(TRANSIT_TO_BACK, 0 /* flags */,
                     mTransitionController, mWmService.mSyncEngine);
             // Guarantee that this gets its own transition by queueing on SyncEngine
@@ -5858,7 +5867,7 @@
         return true;
     }
 
-    private boolean moveTaskToBackInner(@NonNull Task task, @Nullable Transition transition) {
+    private void moveTaskToBackInner(@NonNull Task task, @Nullable Transition transition) {
         final Transition.ReadyCondition movedToBack =
                 new Transition.ReadyCondition("moved-to-back", task);
         if (transition != null) {
@@ -5873,7 +5882,7 @@
 
             if (inPinnedWindowingMode()) {
                 mTaskSupervisor.removeRootTask(this);
-                return true;
+                return;
             }
 
             mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
@@ -5896,7 +5905,6 @@
         } else {
             mRootWindowContainer.resumeFocusedTasksTopActivities();
         }
-        return true;
     }
 
     boolean willActivityBeVisible(IBinder token) {
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 1f54518..912ff4a 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -232,6 +232,9 @@
             </xs:element>
             <xs:element name="brightness" type="xs:float" maxOccurs="unbounded">
             </xs:element>
+            <!-- Mapping of current lux to minimum allowed nits values. -->
+            <xs:element name="luxToMinimumNitsMap" type="nitsMap" maxOccurs="1">
+            </xs:element>
         </xs:sequence>
         <xs:attribute name="enabled" type="xs:boolean" use="optional"/>
     </xs:complexType>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index c39c3d7..3c70890 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -255,9 +255,11 @@
     method public java.util.List<java.lang.Float> getBacklight();
     method public java.util.List<java.lang.Float> getBrightness();
     method public boolean getEnabled();
+    method public com.android.server.display.config.NitsMap getLuxToMinimumNitsMap();
     method public java.util.List<java.lang.Float> getNits();
     method public java.math.BigDecimal getTransitionPoint();
     method public void setEnabled(boolean);
+    method public void setLuxToMinimumNitsMap(com.android.server.display.config.NitsMap);
     method public void setTransitionPoint(java.math.BigDecimal);
   }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 73a2f65..5a022c0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -1651,6 +1651,17 @@
                 + "  <brightness>0.1</brightness>\n"
                 + "  <brightness>0.5</brightness>\n"
                 + "  <brightness>1.0</brightness>\n"
+                + " <luxToMinimumNitsMap>\n"
+                + "     <point>\n"
+                + "         <value>10</value> <nits>0.3</nits>\n"
+                + "     </point>\n"
+                + "     <point>\n"
+                + "         <value>50</value> <nits>0.7</nits>\n"
+                + "     </point>\n"
+                + "     <point>\n"
+                + "         <value>100</value> <nits>1.0</nits>\n"
+                + "     </point>\n"
+                + " </luxToMinimumNitsMap>\n"
                 + "</lowBrightness>";
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
index 5294943..5487bc5 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
@@ -35,6 +35,7 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.DisplayDeviceConfig;
 import com.android.server.display.brightness.BrightnessReason;
 import com.android.server.display.feature.DeviceConfigParameterProvider;
 import com.android.server.display.feature.DisplayManagerFlags;
@@ -280,7 +281,8 @@
 
         @Override
         List<BrightnessStateModifier> getModifiers(DisplayManagerFlags flags, Context context,
-                Handler handler, BrightnessClamperController.ClamperChangeListener listener) {
+                Handler handler, BrightnessClamperController.ClamperChangeListener listener,
+                DisplayDeviceConfig displayDeviceConfig) {
             return mModifiers;
         }
     }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt
index e4a7d98..749c400 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt
@@ -15,13 +15,18 @@
  */
 package com.android.server.display.brightness.clamper
 
-import android.os.PowerManager
 import android.os.UserHandle
+import android.platform.test.annotations.RequiresFlagsEnabled
 import android.provider.Settings
 import android.testing.TestableContext
 import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED
+import com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED
+import com.android.server.display.DisplayDeviceConfig
 import com.android.server.display.brightness.BrightnessReason
+import com.android.server.display.feature.flags.Flags
 import com.android.server.testutils.TestHandler
+import com.android.server.testutils.whenever
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -32,71 +37,197 @@
 class BrightnessLowLuxModifierTest {
 
     private var mockClamperChangeListener =
-            mock<BrightnessClamperController.ClamperChangeListener>()
+        mock<BrightnessClamperController.ClamperChangeListener>()
 
     val context = TestableContext(
-            InstrumentationRegistry.getInstrumentation().getContext())
+        InstrumentationRegistry.getInstrumentation().getContext())
 
     private val testHandler = TestHandler(null)
     private lateinit var modifier: BrightnessLowLuxModifier
 
+    private var mockDisplayDeviceConfig = mock<DisplayDeviceConfig>()
+
+    private val LOW_LUX_BRIGHTNESS = 0.1f
+    private val TRANSITION_POINT = 0.25f
+    private val NORMAL_RANGE_BRIGHTNESS = 0.3f
+
     @Before
     fun setUp() {
-        modifier = BrightnessLowLuxModifier(testHandler, mockClamperChangeListener, context)
+        modifier =
+            BrightnessLowLuxModifier(testHandler,
+                mockClamperChangeListener,
+                context,
+                mockDisplayDeviceConfig)
+
+        // values below transition point (even dimmer range)
+        // nits: 0.1 -> backlight 0.02 -> brightness -> 0.1
+        whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 1.0f))
+                .thenReturn(0.02f)
+        whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.02f))
+                .thenReturn(LOW_LUX_BRIGHTNESS)
+
+        // values above transition point (noraml range)
+        // nits: 10 -> backlight 0.2 -> brightness -> 0.3
+        whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 2f))
+                .thenReturn(0.15f)
+        whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.15f))
+                .thenReturn(0.24f)
+
+        // values above transition point (normal range)
+        // nits: 10 -> backlight 0.2 -> brightness -> 0.3
+        whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 10f))
+                .thenReturn(0.2f)
+        whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.2f))
+                .thenReturn(NORMAL_RANGE_BRIGHTNESS)
+
+        // min nits when lux of 400
+        whenever(mockDisplayDeviceConfig.getMinNitsFromLux(/* lux= */ 400f))
+                .thenReturn(1.0f)
+
+
+        whenever(mockDisplayDeviceConfig.lowBrightnessTransitionPoint).thenReturn(TRANSITION_POINT)
+
         testHandler.flush()
     }
 
     @Test
-    fun testThrottlingBounds() {
-        Settings.Secure.putIntForUser(context.contentResolver,
-                Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId) // true
-        Settings.Secure.putFloatForUser(context.contentResolver,
-                Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.7f, userId)
-        modifier.recalculateLowerBound()
-        testHandler.flush()
-        assertThat(modifier.isActive).isTrue()
-
-        // TODO: code currently returns MIN/MAX; update with lux values
-        assertThat(modifier.brightnessLowerBound).isEqualTo(PowerManager.BRIGHTNESS_MIN)
-    }
-
-    @Test
-    fun testGetReason_UserSet() {
-        Settings.Secure.putIntForUser(context.contentResolver,
-                Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId)
-        Settings.Secure.putFloatForUser(context.contentResolver,
-                Settings.Secure.EVEN_DIMMER_MIN_NITS, 30.0f, userId)
-        modifier.recalculateLowerBound()
-        testHandler.flush()
-        assertThat(modifier.isActive).isTrue()
-
-        // Test restriction from user setting
-        assertThat(modifier.brightnessReason)
-                .isEqualTo(BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND)
-    }
-
-    @Test
-    fun testGetReason_Lux() {
-        Settings.Secure.putIntForUser(context.contentResolver,
-                Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId)
-        Settings.Secure.putFloatForUser(context.contentResolver,
-                Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.0f, userId)
-        modifier.onAmbientLuxChange(3000.0f)
-        testHandler.flush()
-        assertThat(modifier.isActive).isTrue()
-
-        // Test restriction from lux setting
-        assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
-    }
-
-    @Test
     fun testSettingOffDisablesModifier() {
+        // test transition point ensures brightness doesn't drop when setting is off.
         Settings.Secure.putIntForUser(context.contentResolver,
             Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, userId)
-        assertThat(modifier.brightnessLowerBound).isEqualTo(PowerManager.BRIGHTNESS_MIN)
+        modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+        modifier.recalculateLowerBound()
+        testHandler.flush()
+        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
+        assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
         modifier.onAmbientLuxChange(3000.0f)
         testHandler.flush()
         assertThat(modifier.isActive).isFalse()
-        assertThat(modifier.brightnessLowerBound).isEqualTo(PowerManager.BRIGHTNESS_MIN)
+        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
+        assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+    fun testLuxRestrictsBrightnessRange() {
+        // test that high lux prevents low brightness range.
+        Settings.Secure.putIntForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId)
+        Settings.Secure.putFloatForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.1f, userId)
+        modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+        modifier.onAmbientLuxChange(400.0f)
+        testHandler.flush()
+
+        assertThat(modifier.isActive).isTrue()
+        // Test restriction from lux setting
+        assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
+        assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+    fun testUserRestrictsBrightnessRange() {
+        // test that user minimum nits setting prevents low brightness range.
+        Settings.Secure.putIntForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId)
+        Settings.Secure.putFloatForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_MIN_NITS, 10.0f, userId)
+        modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+        modifier.recalculateLowerBound()
+        testHandler.flush()
+
+        // Test restriction from user setting
+        assertThat(modifier.isActive).isTrue()
+        assertThat(modifier.brightnessReason)
+                .isEqualTo(BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND)
+        assertThat(modifier.brightnessLowerBound).isEqualTo(NORMAL_RANGE_BRIGHTNESS)
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+    fun testOnToOff() {
+        // test that high lux prevents low brightness range.
+        Settings.Secure.putIntForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId) // on
+        Settings.Secure.putFloatForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, userId)
+        modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+        modifier.onAmbientLuxChange(400.0f)
+        testHandler.flush()
+
+        assertThat(modifier.isActive).isTrue()
+        // Test restriction from lux setting
+        assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
+        assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
+
+        Settings.Secure.putIntForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, userId) // off
+
+        modifier.recalculateLowerBound()
+        testHandler.flush()
+
+        assertThat(modifier.isActive).isFalse()
+        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
+        assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+    fun testOffToOn() {
+        // test that high lux prevents low brightness range.
+        Settings.Secure.putIntForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, userId) // off
+        Settings.Secure.putFloatForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, userId)
+        modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+        modifier.onAmbientLuxChange(400.0f)
+        testHandler.flush()
+
+        assertThat(modifier.isActive).isFalse()
+        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
+        assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
+
+
+
+        Settings.Secure.putIntForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId) // on
+        modifier.recalculateLowerBound()
+        testHandler.flush()
+
+        assertThat(modifier.isActive).isTrue()
+        // Test restriction from lux setting
+        assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
+        assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
+    fun testDisabledWhenAutobrightnessIsOff() {
+        // test that high lux prevents low brightness range.
+        Settings.Secure.putIntForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, userId) // on
+        Settings.Secure.putFloatForUser(context.contentResolver,
+            Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, userId)
+
+        modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_ENABLED)
+        modifier.onAmbientLuxChange(400.0f)
+        testHandler.flush()
+
+        assertThat(modifier.isActive).isTrue()
+        // Test restriction from lux setting
+        assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
+        assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
+
+
+        modifier.setAutoBrightnessState(AUTO_BRIGHTNESS_DISABLED)
+        modifier.onAmbientLuxChange(400.0f)
+        testHandler.flush()
+
+        assertThat(modifier.isActive).isFalse()
+        // Test restriction from lux setting
+        assertThat(modifier.brightnessReason).isEqualTo(0)
+        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
     }
 }
+
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
deleted file mode 100644
index 517dcb4..0000000
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ /dev/null
@@ -1,1969 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.notification;
-
-import static android.app.Notification.FLAG_BUBBLE;
-import static android.app.Notification.GROUP_ALERT_ALL;
-import static android.app.Notification.GROUP_ALERT_CHILDREN;
-import static android.app.Notification.GROUP_ALERT_SUMMARY;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_LOW;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
-import static android.media.AudioAttributes.USAGE_NOTIFICATION;
-import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.KeyguardManager;
-import android.app.Notification;
-import android.app.Notification.Builder;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.graphics.Color;
-import android.graphics.drawable.Icon;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.VibrationAttributes;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.IAccessibilityManager;
-import android.view.accessibility.IAccessibilityManagerClient;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.logging.InstanceIdSequence;
-import com.android.internal.logging.InstanceIdSequenceFake;
-import com.android.internal.util.IntPair;
-import com.android.server.UiServiceTestCase;
-import com.android.server.lights.LogicalLight;
-import com.android.server.pm.PackageManagerService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.verification.VerificationMode;
-
-import java.util.Objects;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
-public class BuzzBeepBlinkTest extends UiServiceTestCase {
-
-    @Mock AudioManager mAudioManager;
-    @Mock Vibrator mVibrator;
-    @Mock android.media.IRingtonePlayer mRingtonePlayer;
-    @Mock LogicalLight mLight;
-    @Mock
-    NotificationManagerService.WorkerHandler mHandler;
-    @Mock
-    NotificationUsageStats mUsageStats;
-    @Mock
-    IAccessibilityManager mAccessibilityService;
-    @Mock
-    KeyguardManager mKeyguardManager;
-    NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
-    private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
-            1 << 30);
-
-    private NotificationManagerService mService;
-    private String mPkg = "com.android.server.notification";
-    private int mId = 1001;
-    private int mOtherId = 1002;
-    private String mTag = null;
-    private int mUid = 1000;
-    private int mPid = 2000;
-    private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
-    private NotificationChannel mChannel;
-
-    private VibrateRepeatMatcher mVibrateOnceMatcher = new VibrateRepeatMatcher(-1);
-    private VibrateRepeatMatcher mVibrateLoopMatcher = new VibrateRepeatMatcher(0);
-
-    private static final long[] CUSTOM_VIBRATION = new long[] {
-            300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
-            300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
-            300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
-    private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI;
-    private static final AudioAttributes CUSTOM_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
-            .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
-            .build();
-    private static final int CUSTOM_LIGHT_COLOR = Color.BLACK;
-    private static final int CUSTOM_LIGHT_ON = 10000;
-    private static final int CUSTOM_LIGHT_OFF = 10000;
-    private static final int MAX_VIBRATION_DELAY = 1000;
-    private static final float DEFAULT_VOLUME = 1.0f;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        getContext().addMockSystemService(Vibrator.class, mVibrator);
-
-        when(mAudioManager.isAudioFocusExclusive()).thenReturn(false);
-        when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
-        // consistent with focus not exclusive and volume not muted
-        when(mAudioManager.shouldNotificationSoundPlay(any(AudioAttributes.class)))
-                .thenReturn(true);
-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
-        when(mAudioManager.getFocusRampTimeMs(anyInt(), any(AudioAttributes.class))).thenReturn(50);
-        when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
-        when(mVibrator.hasFrequencyControl()).thenReturn(false);
-        when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
-
-        long serviceReturnValue = IntPair.of(
-                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
-                AccessibilityEvent.TYPES_ALL_MASK);
-        when(mAccessibilityService.addClient(any(), anyInt())).thenReturn(serviceReturnValue);
-        AccessibilityManager accessibilityManager =
-                new AccessibilityManager(getContext(), Handler.getMain(), mAccessibilityService,
-                        0, true);
-        verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt());
-        assertTrue(accessibilityManager.isEnabled());
-
-        mService = spy(new NotificationManagerService(getContext(), mNotificationRecordLogger,
-                mNotificationInstanceIdSequence));
-        mService.setVibratorHelper(new VibratorHelper(getContext()));
-        mService.setAudioManager(mAudioManager);
-        mService.setSystemReady(true);
-        mService.setHandler(mHandler);
-        mService.setLights(mLight);
-        mService.setScreenOn(false);
-        mService.setUsageStats(mUsageStats);
-        mService.setAccessibilityManager(accessibilityManager);
-        mService.setKeyguardManager(mKeyguardManager);
-        mService.mScreenOn = false;
-        mService.mInCallStateOffHook = false;
-        mService.mNotificationPulseEnabled = true;
-
-        mChannel = new NotificationChannel("test", "test", IMPORTANCE_HIGH);
-    }
-
-    //
-    // Convenience functions for creating notification records
-    //
-
-    private NotificationRecord getNoisyOtherNotification() {
-        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
-                true /* noisy */, true /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getBeepyNotification() {
-        return getNotificationRecord(mId, false /* insistent */, false /* once */,
-                true /* noisy */, false /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getBeepyOtherNotification() {
-        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
-                true /* noisy */, false /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getBeepyOnceNotification() {
-        return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                true /* noisy */, false /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getQuietNotification() {
-        return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                false /* noisy */, false /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getQuietOtherNotification() {
-        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
-                false /* noisy */, false /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getQuietOnceNotification() {
-        return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                false /* noisy */, false /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getInsistentBeepyNotification() {
-        return getNotificationRecord(mId, true /* insistent */, false /* once */,
-                true /* noisy */, false /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getInsistentBeepyOnceNotification() {
-        return getNotificationRecord(mId, true /* insistent */, true /* once */,
-                true /* noisy */, false /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getInsistentBeepyLeanbackNotification() {
-        return getLeanbackNotificationRecord(mId, true /* insistent */, false /* once */,
-                true /* noisy */, false /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getBuzzyNotification() {
-        return getNotificationRecord(mId, false /* insistent */, false /* once */,
-                false /* noisy */, true /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getBuzzyOtherNotification() {
-        return getNotificationRecord(mOtherId, false /* insistent */, false /* once */,
-                false /* noisy */, true /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getBuzzyOnceNotification() {
-        return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                false /* noisy */, true /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getInsistentBuzzyNotification() {
-        return getNotificationRecord(mId, true /* insistent */, false /* once */,
-                false /* noisy */, true /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getBuzzyBeepyNotification() {
-        return getNotificationRecord(mId, false /* insistent */, false /* once */,
-                true /* noisy */, true /* buzzy*/, false /* lights */);
-    }
-
-    private NotificationRecord getLightsNotification() {
-        return getNotificationRecord(mId, false /* insistent */, false /* once */,
-                false /* noisy */, false /* buzzy*/, true /* lights */);
-    }
-
-    private NotificationRecord getLightsOnceNotification() {
-        return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                false /* noisy */, false /* buzzy*/, true /* lights */);
-    }
-
-    private NotificationRecord getCallRecord(int id, NotificationChannel channel, boolean looping) {
-        final Builder builder = new Builder(getContext())
-                .setContentTitle("foo")
-                .setSmallIcon(android.R.drawable.sym_def_app_icon)
-                .setPriority(Notification.PRIORITY_HIGH);
-        Notification n = builder.build();
-        if (looping) {
-            n.flags |= Notification.FLAG_INSISTENT;
-        }
-        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
-                mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
-        mService.addNotification(r);
-
-        return r;
-    }
-
-    private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
-            boolean noisy, boolean buzzy, boolean lights) {
-        return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, buzzy, noisy,
-                lights, null, Notification.GROUP_ALERT_ALL, false);
-    }
-
-    private NotificationRecord getLeanbackNotificationRecord(int id, boolean insistent,
-            boolean once,
-            boolean noisy, boolean buzzy, boolean lights) {
-        return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, true, true,
-                true,
-                null, Notification.GROUP_ALERT_ALL, true);
-    }
-
-    private NotificationRecord getBeepyNotificationRecord(String groupKey, int groupAlertBehavior) {
-        return getNotificationRecord(mId, false, false, true, false, false, true, true, true,
-                groupKey, groupAlertBehavior, false);
-    }
-
-    private NotificationRecord getLightsNotificationRecord(String groupKey,
-            int groupAlertBehavior) {
-        return getNotificationRecord(mId, false, false, false, false, true /*lights*/, true,
-                true, true, groupKey, groupAlertBehavior, false);
-    }
-
-    private NotificationRecord getNotificationRecord(int id,
-            boolean insistent, boolean once,
-            boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration,
-            boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior,
-            boolean isLeanback) {
-
-        final Builder builder = new Builder(getContext())
-                .setContentTitle("foo")
-                .setSmallIcon(android.R.drawable.sym_def_app_icon)
-                .setPriority(Notification.PRIORITY_HIGH)
-                .setOnlyAlertOnce(once);
-
-        int defaults = 0;
-        if (noisy) {
-            if (defaultSound) {
-                defaults |= Notification.DEFAULT_SOUND;
-                mChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
-                        Notification.AUDIO_ATTRIBUTES_DEFAULT);
-            } else {
-                builder.setSound(CUSTOM_SOUND);
-                mChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
-            }
-        } else {
-            mChannel.setSound(null, null);
-        }
-        if (buzzy) {
-            if (defaultVibration) {
-                defaults |= Notification.DEFAULT_VIBRATE;
-            } else {
-                builder.setVibrate(CUSTOM_VIBRATION);
-                mChannel.setVibrationPattern(CUSTOM_VIBRATION);
-            }
-            mChannel.enableVibration(true);
-        } else {
-            mChannel.setVibrationPattern(null);
-            mChannel.enableVibration(false);
-        }
-
-        if (lights) {
-            if (defaultLights) {
-                defaults |= Notification.DEFAULT_LIGHTS;
-            } else {
-                builder.setLights(CUSTOM_LIGHT_COLOR, CUSTOM_LIGHT_ON, CUSTOM_LIGHT_OFF);
-            }
-            mChannel.enableLights(true);
-        } else {
-            mChannel.enableLights(false);
-        }
-        builder.setDefaults(defaults);
-
-        builder.setGroup(groupKey);
-        builder.setGroupAlertBehavior(groupAlertBehavior);
-
-        Notification n = builder.build();
-        if (insistent) {
-            n.flags |= Notification.FLAG_INSISTENT;
-        }
-
-        Context context = spy(getContext());
-        PackageManager packageManager = spy(context.getPackageManager());
-        when(context.getPackageManager()).thenReturn(packageManager);
-        when(packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
-                .thenReturn(isLeanback);
-
-        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
-                mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(context, sbn, mChannel);
-        mService.addNotification(r);
-        return r;
-    }
-
-    //
-    // Convenience functions for interacting with mocks
-    //
-
-    private void verifyNeverBeep() throws RemoteException {
-        verify(mRingtonePlayer, never()).playAsync(any(), any(), anyBoolean(), any(), anyFloat());
-    }
-
-    private void verifyBeepUnlooped() throws RemoteException  {
-        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(false), any(),
-                eq(DEFAULT_VOLUME));
-    }
-
-    private void verifyBeepLooped() throws RemoteException  {
-        verify(mRingtonePlayer, times(1)).playAsync(any(), any(), eq(true), any(),
-                eq(DEFAULT_VOLUME));
-    }
-
-    private void verifyBeep(int times)  throws RemoteException  {
-        verify(mRingtonePlayer, times(times)).playAsync(any(), any(), anyBoolean(), any(),
-                eq(DEFAULT_VOLUME));
-    }
-
-    private void verifyNeverStopAudio() throws RemoteException {
-        verify(mRingtonePlayer, never()).stopAsync();
-    }
-
-    private void verifyStopAudio() throws RemoteException {
-        verify(mRingtonePlayer, times(1)).stopAsync();
-    }
-
-    private void verifyNeverVibrate() {
-        verify(mVibrator, never()).vibrate(anyInt(), anyString(), any(), anyString(),
-                any(VibrationAttributes.class));
-    }
-
-    private void verifyVibrate() {
-        verifyVibrate(/* times= */ 1);
-    }
-
-    private void verifyVibrate(int times) {
-        verifyVibrate(mVibrateOnceMatcher, times(times));
-    }
-
-    private void verifyVibrateLooped() {
-        verifyVibrate(mVibrateLoopMatcher, times(1));
-    }
-
-    private void verifyDelayedVibrateLooped() {
-        verifyVibrate(mVibrateLoopMatcher, timeout(MAX_VIBRATION_DELAY).times(1));
-    }
-
-    private void verifyDelayedVibrate(VibrationEffect effect) {
-        verifyVibrate(argument -> Objects.equals(effect, argument),
-                timeout(MAX_VIBRATION_DELAY).times(1));
-    }
-
-    private void verifyDelayedNeverVibrate() {
-        verify(mVibrator, after(MAX_VIBRATION_DELAY).never()).vibrate(anyInt(), anyString(), any(),
-                anyString(), any(VibrationAttributes.class));
-    }
-
-    private void verifyVibrate(ArgumentMatcher<VibrationEffect> effectMatcher,
-            VerificationMode verification) {
-        ArgumentCaptor<VibrationAttributes> captor =
-                ArgumentCaptor.forClass(VibrationAttributes.class);
-        verify(mVibrator, verification).vibrate(eq(Process.SYSTEM_UID),
-                eq(PackageManagerService.PLATFORM_PACKAGE_NAME), argThat(effectMatcher),
-                anyString(), captor.capture());
-        assertEquals(0, (captor.getValue().getFlags()
-                & VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY));
-    }
-
-    private void verifyStopVibrate() {
-        int alarmClassUsageFilter =
-                VibrationAttributes.USAGE_CLASS_ALARM | ~VibrationAttributes.USAGE_CLASS_MASK;
-        verify(mVibrator, times(1)).cancel(eq(alarmClassUsageFilter));
-    }
-
-    private void verifyNeverStopVibrate() {
-        verify(mVibrator, never()).cancel();
-        verify(mVibrator, never()).cancel(anyInt());
-    }
-
-    private void verifyNeverLights() {
-        verify(mLight, never()).setFlashing(anyInt(), anyInt(), anyInt(), anyInt());
-    }
-
-    private void verifyLights() {
-        verify(mLight, times(1)).setFlashing(anyInt(), anyInt(), anyInt(), anyInt());
-    }
-
-    //
-    // Tests
-    //
-
-    @Test
-    public void testLights() throws Exception {
-        NotificationRecord r = getLightsNotification();
-        r.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyLights();
-        assertTrue(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testBeep() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyBeepUnlooped();
-        verifyNeverVibrate();
-        verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testLockedPrivateA11yRedaction() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
-        r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
-        when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
-        AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
-        when(accessibilityManager.isEnabled()).thenReturn(true);
-        mService.setAccessibilityManager(accessibilityManager);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        ArgumentCaptor<AccessibilityEvent> eventCaptor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-
-        verify(accessibilityManager, times(1))
-                .sendAccessibilityEvent(eventCaptor.capture());
-
-        AccessibilityEvent event = eventCaptor.getValue();
-        assertEquals(r.getNotification().publicVersion, event.getParcelableData());
-    }
-
-    @Test
-    public void testLockedOverridePrivateA11yRedaction() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        r.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE);
-        r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
-        when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
-        AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
-        when(accessibilityManager.isEnabled()).thenReturn(true);
-        mService.setAccessibilityManager(accessibilityManager);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        ArgumentCaptor<AccessibilityEvent> eventCaptor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-
-        verify(accessibilityManager, times(1))
-                .sendAccessibilityEvent(eventCaptor.capture());
-
-        AccessibilityEvent event = eventCaptor.getValue();
-        assertEquals(r.getNotification().publicVersion, event.getParcelableData());
-    }
-
-    @Test
-    public void testLockedPublicA11yNoRedaction() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
-        r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
-        when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
-        AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
-        when(accessibilityManager.isEnabled()).thenReturn(true);
-        mService.setAccessibilityManager(accessibilityManager);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        ArgumentCaptor<AccessibilityEvent> eventCaptor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-
-        verify(accessibilityManager, times(1))
-                .sendAccessibilityEvent(eventCaptor.capture());
-
-        AccessibilityEvent event = eventCaptor.getValue();
-        assertEquals(r.getNotification(), event.getParcelableData());
-    }
-
-    @Test
-    public void testUnlockedPrivateA11yNoRedaction() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
-        r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
-        when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
-        AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
-        when(accessibilityManager.isEnabled()).thenReturn(true);
-        mService.setAccessibilityManager(accessibilityManager);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        ArgumentCaptor<AccessibilityEvent> eventCaptor =
-                ArgumentCaptor.forClass(AccessibilityEvent.class);
-
-        verify(accessibilityManager, times(1))
-                .sendAccessibilityEvent(eventCaptor.capture());
-
-        AccessibilityEvent event = eventCaptor.getValue();
-        assertEquals(r.getNotification(), event.getParcelableData());
-    }
-
-    @Test
-    public void testBeepInsistently() throws Exception {
-        NotificationRecord r = getInsistentBeepyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyBeepLooped();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testNoLeanbackBeep() throws Exception {
-        NotificationRecord r = getInsistentBeepyLeanbackNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testNoBeepForAutomotiveIfEffectsDisabled() throws Exception {
-        mService.setIsAutomotive(true);
-        mService.setNotificationEffectsEnabledForAutomotive(false);
-
-        NotificationRecord r = getBeepyNotification();
-        r.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-        assertFalse(r.isInterruptive());
-    }
-
-    @Test
-    public void testNoBeepForImportanceDefaultInAutomotiveIfEffectsEnabled() throws Exception {
-        mService.setIsAutomotive(true);
-        mService.setNotificationEffectsEnabledForAutomotive(true);
-
-        NotificationRecord r = getBeepyNotification();
-        r.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-        assertFalse(r.isInterruptive());
-    }
-
-    @Test
-    public void testBeepForImportanceHighInAutomotiveIfEffectsEnabled() throws Exception {
-        mService.setIsAutomotive(true);
-        mService.setNotificationEffectsEnabledForAutomotive(true);
-
-        NotificationRecord r = getBeepyNotification();
-        r.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyBeepUnlooped();
-        assertTrue(r.isInterruptive());
-    }
-
-    @Test
-    public void testNoInterruptionForMin() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        r.setSystemImportance(NotificationManager.IMPORTANCE_MIN);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-        verifyNeverVibrate();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testNoInterruptionForIntercepted() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        r.setIntercepted(true);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-        verifyNeverVibrate();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testBeepTwice() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        Mockito.reset(mRingtonePlayer);
-
-        // update should beep
-        r.isUpdate = true;
-        mService.buzzBeepBlinkLocked(r);
-        verifyBeepUnlooped();
-        verify(mAccessibilityService, times(2)).sendAccessibilityEvent(any(), anyInt());
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testHonorAlertOnlyOnceForBeep() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        NotificationRecord s = getBeepyOnceNotification();
-        s.isUpdate = true;
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        Mockito.reset(mRingtonePlayer);
-
-        // update should not beep
-        mService.buzzBeepBlinkLocked(s);
-        verifyNeverBeep();
-        verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
-    }
-
-    @Test
-    public void testNoisyUpdateDoesNotCancelAudio() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-        r.isUpdate = true;
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverStopAudio();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testNoisyOnceUpdateDoesNotCancelAudio() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        NotificationRecord s = getBeepyOnceNotification();
-        s.isUpdate = true;
-
-        mService.buzzBeepBlinkLocked(r);
-        mService.buzzBeepBlinkLocked(s);
-
-        verifyNeverStopAudio();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-        assertFalse(s.isInterruptive());
-        assertEquals(-1, s.getLastAudiblyAlertedMs());
-    }
-
-    /**
-     * Tests the case where the user re-posts a {@link Notification} with looping sound where
-     * {@link Notification.Builder#setOnlyAlertOnce(true)} has been called.  This should silence
-     * the sound associated with the notification.
-     * @throws Exception
-     */
-    @Test
-    public void testNoisyOnceUpdateDoesCancelAudio() throws Exception {
-        NotificationRecord r = getInsistentBeepyNotification();
-        NotificationRecord s = getInsistentBeepyOnceNotification();
-        s.isUpdate = true;
-
-        mService.buzzBeepBlinkLocked(r);
-        mService.buzzBeepBlinkLocked(s);
-
-        verifyStopAudio();
-    }
-
-    @Test
-    public void testQuietUpdateDoesNotCancelAudioFromOther() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        NotificationRecord s = getQuietNotification();
-        s.isUpdate = true;
-        NotificationRecord other = getNoisyOtherNotification();
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        mService.buzzBeepBlinkLocked(other); // this takes the audio stream
-        Mockito.reset(mRingtonePlayer);
-
-        // should not stop noise, since we no longer own it
-        mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
-        verifyNeverStopAudio();
-        assertTrue(other.isInterruptive());
-        assertNotEquals(-1, other.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testQuietInterloperDoesNotCancelAudio() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        NotificationRecord other = getQuietOtherNotification();
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        Mockito.reset(mRingtonePlayer);
-
-        // should not stop noise, since it does not own it
-        mService.buzzBeepBlinkLocked(other);
-        verifyNeverStopAudio();
-    }
-
-    @Test
-    public void testQuietUpdateCancelsAudio() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        NotificationRecord s = getQuietNotification();
-        s.isUpdate = true;
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-        Mockito.reset(mRingtonePlayer);
-
-        // quiet update should stop making noise
-        mService.buzzBeepBlinkLocked(s);
-        verifyStopAudio();
-        assertFalse(s.isInterruptive());
-        assertEquals(-1, s.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testQuietOnceUpdateCancelsAudio() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        NotificationRecord s = getQuietOnceNotification();
-        s.isUpdate = true;
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-        Mockito.reset(mRingtonePlayer);
-
-        // stop making noise - this is a weird corner case, but quiet should override once
-        mService.buzzBeepBlinkLocked(s);
-        verifyStopAudio();
-        assertFalse(s.isInterruptive());
-        assertEquals(-1, s.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testInCallNotification() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        Mockito.reset(mRingtonePlayer);
-
-        mService.mInCallStateOffHook = true;
-        mService.buzzBeepBlinkLocked(r);
-
-        verify(mService, times(1)).playInCallNotification();
-        verifyNeverBeep(); // doesn't play normal beep
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testNoDemoteSoundToVibrateIfVibrateGiven() throws Exception {
-        NotificationRecord r = getBuzzyBeepyNotification();
-        assertTrue(r.getSound() != null);
-
-        // the phone is quiet
-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
-        when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyDelayedVibrate(r.getVibration());
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testNoDemoteSoundToVibrateIfNonNotificationStream() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        assertTrue(r.getSound() != null);
-        assertNull(r.getVibration());
-
-        // the phone is quiet
-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(1);
-        // all streams at 1 means no muting from audio framework
-        when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(true);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverVibrate();
-        verifyBeepUnlooped();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testDemoteSoundToVibrate() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        assertTrue(r.getSound() != null);
-        assertNull(r.getVibration());
-
-        // the phone is quiet
-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
-        when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyDelayedVibrate(
-                mService.getVibratorHelper().createFallbackVibration(/* insistent= */ false));
-        verify(mRingtonePlayer, never()).playAsync
-                (anyObject(), anyObject(), anyBoolean(), anyObject(), anyFloat());
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testDemoteInsistentSoundToVibrate() throws Exception {
-        NotificationRecord r = getInsistentBeepyNotification();
-        assertTrue(r.getSound() != null);
-        assertNull(r.getVibration());
-
-        // the phone is quiet
-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
-        when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyDelayedVibrateLooped();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testVibrate() throws Exception {
-        NotificationRecord r = getBuzzyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-        verifyVibrate();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testInsistentVibrate() {
-        NotificationRecord r = getInsistentBuzzyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-        verifyVibrateLooped();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testVibrateTwice() {
-        NotificationRecord r = getBuzzyNotification();
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        Mockito.reset(mVibrator);
-
-        // update should vibrate
-        r.isUpdate = true;
-        mService.buzzBeepBlinkLocked(r);
-        verifyVibrate();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testPostSilently() throws Exception {
-        NotificationRecord r = getBuzzyNotification();
-        r.setPostSilently(true);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertSummarySilenceChild() throws Exception {
-        NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
-
-        mService.buzzBeepBlinkLocked(child);
-
-        verifyNeverBeep();
-        assertFalse(child.isInterruptive());
-        assertEquals(-1, child.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertSummaryNoSilenceSummary() throws Exception {
-        NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
-        summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
-        mService.buzzBeepBlinkLocked(summary);
-
-        verifyBeepUnlooped();
-        // summaries are never interruptive for notification counts
-        assertFalse(summary.isInterruptive());
-        assertNotEquals(-1, summary.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertSummaryNoSilenceNonGroupChild() throws Exception {
-        NotificationRecord nonGroup = getBeepyNotificationRecord(null, GROUP_ALERT_SUMMARY);
-
-        mService.buzzBeepBlinkLocked(nonGroup);
-
-        verifyBeepUnlooped();
-        assertTrue(nonGroup.isInterruptive());
-        assertNotEquals(-1, nonGroup.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertChildSilenceSummary() throws Exception {
-        NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
-        summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
-        mService.buzzBeepBlinkLocked(summary);
-
-        verifyNeverBeep();
-        assertFalse(summary.isInterruptive());
-        assertEquals(-1, summary.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertChildNoSilenceChild() throws Exception {
-        NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
-
-        mService.buzzBeepBlinkLocked(child);
-
-        verifyBeepUnlooped();
-        assertTrue(child.isInterruptive());
-        assertNotEquals(-1, child.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertChildNoSilenceNonGroupSummary() throws Exception {
-        NotificationRecord nonGroup = getBeepyNotificationRecord(null, GROUP_ALERT_CHILDREN);
-
-        mService.buzzBeepBlinkLocked(nonGroup);
-
-        verifyBeepUnlooped();
-        assertTrue(nonGroup.isInterruptive());
-        assertNotEquals(-1, nonGroup.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertAllNoSilenceGroup() throws Exception {
-        NotificationRecord group = getBeepyNotificationRecord("a", GROUP_ALERT_ALL);
-
-        mService.buzzBeepBlinkLocked(group);
-
-        verifyBeepUnlooped();
-        assertTrue(group.isInterruptive());
-        assertNotEquals(-1, group.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testHonorAlertOnlyOnceForBuzz() throws Exception {
-        NotificationRecord r = getBuzzyNotification();
-        NotificationRecord s = getBuzzyOnceNotification();
-        s.isUpdate = true;
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        Mockito.reset(mVibrator);
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-
-        // update should not beep
-        mService.buzzBeepBlinkLocked(s);
-        verifyNeverVibrate();
-        assertFalse(s.isInterruptive());
-        assertEquals(-1, s.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testNoisyUpdateDoesNotCancelVibrate() throws Exception {
-        NotificationRecord r = getBuzzyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-        r.isUpdate = true;
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverStopVibrate();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testNoisyOnceUpdateDoesNotCancelVibrate() throws Exception {
-        NotificationRecord r = getBuzzyNotification();
-        NotificationRecord s = getBuzzyOnceNotification();
-        s.isUpdate = true;
-
-        mService.buzzBeepBlinkLocked(r);
-        mService.buzzBeepBlinkLocked(s);
-
-        verifyNeverStopVibrate();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-        assertFalse(s.isInterruptive());
-        assertEquals(-1, s.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testQuietUpdateDoesNotCancelVibrateFromOther() throws Exception {
-        NotificationRecord r = getBuzzyNotification();
-        NotificationRecord s = getQuietNotification();
-        s.isUpdate = true;
-        NotificationRecord other = getNoisyOtherNotification();
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        mService.buzzBeepBlinkLocked(other); // this takes the vibrate stream
-        Mockito.reset(mVibrator);
-
-        // should not stop vibrate, since we no longer own it
-        mService.buzzBeepBlinkLocked(s); // this no longer owns the stream
-        verifyNeverStopVibrate();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-        assertTrue(other.isInterruptive());
-        assertNotEquals(-1, other.getLastAudiblyAlertedMs());
-        assertFalse(s.isInterruptive());
-        assertEquals(-1, s.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testQuietInterloperDoesNotCancelVibrate() throws Exception {
-        NotificationRecord r = getBuzzyNotification();
-        NotificationRecord other = getQuietOtherNotification();
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        Mockito.reset(mVibrator);
-
-        // should not stop noise, since it does not own it
-        mService.buzzBeepBlinkLocked(other);
-        verifyNeverStopVibrate();
-        assertFalse(other.isInterruptive());
-        assertEquals(-1, other.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testQuietUpdateCancelsVibrate() {
-        NotificationRecord r = getBuzzyNotification();
-        NotificationRecord s = getQuietNotification();
-        s.isUpdate = true;
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        verifyVibrate();
-
-        // quiet update should stop making noise
-        mService.buzzBeepBlinkLocked(s);
-        verifyStopVibrate();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-        assertFalse(s.isInterruptive());
-        assertEquals(-1, s.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testQuietOnceUpdateCancelVibrate() throws Exception {
-        NotificationRecord r = getBuzzyNotification();
-        NotificationRecord s = getQuietOnceNotification();
-        s.isUpdate = true;
-
-        // set up internal state
-        mService.buzzBeepBlinkLocked(r);
-        verifyVibrate();
-
-        // stop making noise - this is a weird corner case, but quiet should override once
-        mService.buzzBeepBlinkLocked(s);
-        verifyStopVibrate();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-        assertFalse(s.isInterruptive());
-        assertEquals(-1, s.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testQuietUpdateCancelsDemotedVibrate() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-        NotificationRecord s = getQuietNotification();
-
-        // the phone is quiet
-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
-        when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
-        mService.buzzBeepBlinkLocked(r);
-        verifyDelayedVibrate(mService.getVibratorHelper().createFallbackVibration(false));
-
-        // quiet update should stop making noise
-        mService.buzzBeepBlinkLocked(s);
-        verifyStopVibrate();
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-        assertFalse(s.isInterruptive());
-        assertEquals(-1, s.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testEmptyUriSoundTreatedAsNoSound() throws Exception {
-        NotificationChannel channel = new NotificationChannel("test", "test", IMPORTANCE_HIGH);
-        channel.setSound(Uri.EMPTY, null);
-        final Notification n = new Builder(getContext(), "test")
-                .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
-
-        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
-                mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
-        mService.addNotification(r);
-
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverBeep();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testRepeatedSoundOverLimitMuted() throws Exception {
-        when(mUsageStats.isAlertRateLimited(any())).thenReturn(true);
-
-        NotificationRecord r = getBeepyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverBeep();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testPostingSilentNotificationDoesNotAffectRateLimiting() throws Exception {
-        NotificationRecord r = getQuietNotification();
-        mService.buzzBeepBlinkLocked(r);
-
-        verify(mUsageStats, never()).isAlertRateLimited(any());
-    }
-
-    @Test
-    public void testPostingGroupSuppressedDoesNotAffectRateLimiting() throws Exception {
-        NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
-        summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
-        mService.buzzBeepBlinkLocked(summary);
-        verify(mUsageStats, never()).isAlertRateLimited(any());
-    }
-
-    @Test
-    public void testGroupSuppressionFailureDoesNotAffectRateLimiting() {
-        NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
-        summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
-        mService.buzzBeepBlinkLocked(summary);
-        verify(mUsageStats, times(1)).isAlertRateLimited(any());
-    }
-
-    @Test
-    public void testCrossUserSoundMuted() throws Exception {
-        final Notification n = new Builder(getContext(), "test")
-                .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
-
-        int userId = mUser.getIdentifier() + 1;
-        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
-                mPid, n, UserHandle.of(userId), null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn,
-                new NotificationChannel("test", "test", IMPORTANCE_HIGH));
-
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverBeep();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testA11yMinInitialPost() throws Exception {
-        NotificationRecord r = getQuietNotification();
-        r.setSystemImportance(IMPORTANCE_MIN);
-        mService.buzzBeepBlinkLocked(r);
-        verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt());
-    }
-
-    @Test
-    public void testA11yQuietInitialPost() throws Exception {
-        NotificationRecord r = getQuietNotification();
-        mService.buzzBeepBlinkLocked(r);
-        verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
-    }
-
-    @Test
-    public void testA11yQuietUpdate() throws Exception {
-        NotificationRecord r = getQuietNotification();
-        mService.buzzBeepBlinkLocked(r);
-        r.isUpdate = true;
-        mService.buzzBeepBlinkLocked(r);
-        verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
-    }
-
-    @Test
-    public void testA11yCrossUserEventNotSent() throws Exception {
-        final Notification n = new Builder(getContext(), "test")
-                .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
-        int userId = mUser.getIdentifier() + 1;
-        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
-                mPid, n, UserHandle.of(userId), null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn,
-                new NotificationChannel("test", "test", IMPORTANCE_HIGH));
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt());
-    }
-
-    @Test
-    public void testLightsScreenOn() {
-        mService.mScreenOn = true;
-        NotificationRecord r = getLightsNotification();
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverLights();
-        assertTrue(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testLightsInCall() {
-        mService.mInCallStateOffHook = true;
-        NotificationRecord r = getLightsNotification();
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverLights();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testLightsSilentUpdate() {
-        NotificationRecord r = getLightsOnceNotification();
-        mService.buzzBeepBlinkLocked(r);
-        verifyLights();
-        assertTrue(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-
-        r = getLightsOnceNotification();
-        r.isUpdate = true;
-        mService.buzzBeepBlinkLocked(r);
-        // checks that lights happened once, i.e. this new call didn't trigger them again
-        verifyLights();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testLightsUnimportant() {
-        NotificationRecord r = getLightsNotification();
-        r.setSystemImportance(IMPORTANCE_LOW);
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverLights();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testLightsNoLights() {
-        NotificationRecord r = getQuietNotification();
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverLights();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testLightsNoLightOnDevice() {
-        mService.mHasLight = false;
-        NotificationRecord r = getLightsNotification();
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverLights();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testLightsLightsOffGlobally() {
-        mService.mNotificationPulseEnabled = false;
-        NotificationRecord r = getLightsNotification();
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverLights();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testLightsDndIntercepted() {
-        NotificationRecord r = getLightsNotification();
-        r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_LIGHTS);
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverLights();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertSummaryNoLightsChild() {
-        NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY);
-
-        mService.buzzBeepBlinkLocked(child);
-
-        verifyNeverLights();
-        assertFalse(child.isInterruptive());
-        assertEquals(-1, child.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertSummaryLightsSummary() {
-        NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY);
-        summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
-        mService.buzzBeepBlinkLocked(summary);
-
-        verifyLights();
-        // summaries should never count for interruptiveness counts
-        assertFalse(summary.isInterruptive());
-        assertEquals(-1, summary.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertSummaryLightsNonGroupChild() {
-        NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_SUMMARY);
-
-        mService.buzzBeepBlinkLocked(nonGroup);
-
-        verifyLights();
-        assertTrue(nonGroup.isInterruptive());
-        assertEquals(-1, nonGroup.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertChildNoLightsSummary() {
-        NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN);
-        summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
-
-        mService.buzzBeepBlinkLocked(summary);
-
-        verifyNeverLights();
-        assertFalse(summary.isInterruptive());
-        assertEquals(-1, summary.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertChildLightsChild() {
-        NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN);
-
-        mService.buzzBeepBlinkLocked(child);
-
-        verifyLights();
-        assertTrue(child.isInterruptive());
-        assertEquals(-1, child.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertChildLightsNonGroupSummary() {
-        NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_CHILDREN);
-
-        mService.buzzBeepBlinkLocked(nonGroup);
-
-        verifyLights();
-        assertTrue(nonGroup.isInterruptive());
-        assertEquals(-1, nonGroup.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testGroupAlertAllLightsGroup() {
-        NotificationRecord group = getLightsNotificationRecord("a", GROUP_ALERT_ALL);
-
-        mService.buzzBeepBlinkLocked(group);
-
-        verifyLights();
-        assertTrue(group.isInterruptive());
-        assertEquals(-1, group.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testLightsCheckCurrentUser() {
-        final Notification n = new Builder(getContext(), "test")
-                .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
-        int userId = mUser.getIdentifier() + 10;
-        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
-                mPid, n, UserHandle.of(userId), null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn,
-                new NotificationChannel("test", "test", IMPORTANCE_HIGH));
-
-        mService.buzzBeepBlinkLocked(r);
-        verifyNeverLights();
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testListenerHintCall() throws Exception {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        NotificationRecord r = getCallRecord(1, ringtoneChannel, true);
-
-        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-    }
-
-    @Test
-    public void testListenerHintCall_notificationSound() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-
-        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyBeepUnlooped();
-    }
-
-    @Test
-    public void testListenerHintNotification() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-
-        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-    }
-
-    @Test
-    public void testListenerHintBoth() throws Exception {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        NotificationRecord r = getCallRecord(1, ringtoneChannel, true);
-        NotificationRecord s = getBeepyNotification();
-
-        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
-                | NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
-
-        mService.buzzBeepBlinkLocked(r);
-        mService.buzzBeepBlinkLocked(s);
-
-        verifyNeverBeep();
-    }
-
-    @Test
-    public void testListenerHintNotification_callSound() throws Exception {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        NotificationRecord r = getCallRecord(1, ringtoneChannel, true);
-
-        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyBeepLooped();
-    }
-
-    @Test
-    public void testCannotInterruptRingtoneInsistentBeep() throws Exception {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
-        mService.addNotification(ringtoneNotification);
-
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyBeepLooped();
-
-        NotificationRecord interrupter = getBeepyOtherNotification();
-        assertTrue(mService.shouldMuteNotificationLocked(interrupter));
-        mService.buzzBeepBlinkLocked(interrupter);
-
-        verifyBeep(1);
-
-        assertFalse(interrupter.isInterruptive());
-        assertEquals(-1, interrupter.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testRingtoneInsistentBeep_canUpdate() throws Exception {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        ringtoneChannel.enableVibration(true);
-        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
-        mService.addNotification(ringtoneNotification);
-        assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyBeepLooped();
-        verifyDelayedVibrateLooped();
-        Mockito.reset(mVibrator);
-        Mockito.reset(mRingtonePlayer);
-
-        assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-
-        // beep wasn't reset
-        verifyNeverBeep();
-        verifyNeverVibrate();
-        verifyNeverStopAudio();
-        verifyNeverStopVibrate();
-    }
-
-    @Test
-    public void testRingtoneInsistentBeep_clearEffectsStopsSoundAndVibration() throws Exception {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        ringtoneChannel.enableVibration(true);
-        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
-        mService.addNotification(ringtoneNotification);
-        assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyBeepLooped();
-        verifyDelayedVibrateLooped();
-
-        mService.clearSoundLocked();
-        mService.clearVibrateLocked();
-
-        verifyStopAudio();
-        verifyStopVibrate();
-    }
-
-    @Test
-    public void testRingtoneInsistentBeep_neverVibratesWhenEffectsClearedBeforeDelay()
-            throws Exception {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        ringtoneChannel.enableVibration(true);
-        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
-        mService.addNotification(ringtoneNotification);
-        assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyBeepLooped();
-        verifyNeverVibrate();
-
-        mService.clearSoundLocked();
-        mService.clearVibrateLocked();
-
-        verifyStopAudio();
-        verifyDelayedNeverVibrate();
-    }
-
-    @Test
-    public void testCannotInterruptRingtoneInsistentBuzz() {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Uri.EMPTY,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        ringtoneChannel.enableVibration(true);
-        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
-        assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
-
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyVibrateLooped();
-
-        NotificationRecord interrupter = getBuzzyOtherNotification();
-        assertTrue(mService.shouldMuteNotificationLocked(interrupter));
-        mService.buzzBeepBlinkLocked(interrupter);
-
-        verifyVibrate(1);
-
-        assertFalse(interrupter.isInterruptive());
-        assertEquals(-1, interrupter.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testCanInterruptRingtoneNonInsistentBeep() throws Exception {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, false);
-
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyBeepUnlooped();
-
-        NotificationRecord interrupter = getBeepyOtherNotification();
-        mService.buzzBeepBlinkLocked(interrupter);
-
-        verifyBeep(2);
-
-        assertTrue(interrupter.isInterruptive());
-    }
-
-    @Test
-    public void testCanInterruptRingtoneNonInsistentBuzz() {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(null,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        ringtoneChannel.enableVibration(true);
-        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, false);
-
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyVibrate();
-
-        NotificationRecord interrupter = getBuzzyOtherNotification();
-        mService.buzzBeepBlinkLocked(interrupter);
-
-        verifyVibrate(2);
-
-        assertTrue(interrupter.isInterruptive());
-    }
-
-    @Test
-    public void testRingtoneInsistentBeep_doesNotBlockFutureSoundsOnceStopped() throws Exception {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(Settings.System.DEFAULT_RINGTONE_URI,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
-
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyBeepLooped();
-
-        mService.clearSoundLocked();
-
-        NotificationRecord interrupter = getBeepyOtherNotification();
-        mService.buzzBeepBlinkLocked(interrupter);
-
-        verifyBeep(2);
-
-        assertTrue(interrupter.isInterruptive());
-    }
-
-    @Test
-    public void testRingtoneInsistentBuzz_doesNotBlockFutureSoundsOnceStopped() {
-        NotificationChannel ringtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        ringtoneChannel.setSound(null,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
-        ringtoneChannel.enableVibration(true);
-        NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
-
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyVibrateLooped();
-
-        mService.clearVibrateLocked();
-
-        NotificationRecord interrupter = getBuzzyOtherNotification();
-        mService.buzzBeepBlinkLocked(interrupter);
-
-        verifyVibrate(2);
-
-        assertTrue(interrupter.isInterruptive());
-    }
-
-    @Test
-    public void testCanInterruptNonRingtoneInsistentBeep() throws Exception {
-        NotificationChannel fakeRingtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        NotificationRecord ringtoneNotification = getCallRecord(1, fakeRingtoneChannel, true);
-
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-        verifyBeepLooped();
-
-        NotificationRecord interrupter = getBeepyOtherNotification();
-        mService.buzzBeepBlinkLocked(interrupter);
-
-        verifyBeep(2);
-
-        assertTrue(interrupter.isInterruptive());
-    }
-
-    @Test
-    public void testCanInterruptNonRingtoneInsistentBuzz() {
-        NotificationChannel fakeRingtoneChannel =
-                new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
-        fakeRingtoneChannel.enableVibration(true);
-        fakeRingtoneChannel.setSound(null,
-                new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION).build());
-        NotificationRecord ringtoneNotification = getCallRecord(1, fakeRingtoneChannel, true);
-
-        mService.buzzBeepBlinkLocked(ringtoneNotification);
-
-        NotificationRecord interrupter = getBuzzyOtherNotification();
-        mService.buzzBeepBlinkLocked(interrupter);
-
-        verifyVibrate(2);
-
-        assertTrue(interrupter.isInterruptive());
-    }
-
-    @Test
-    public void testBubbleSuppressedNotificationDoesntMakeSound() {
-        Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
-                        mock(PendingIntent.class), mock(Icon.class))
-                .build();
-
-        NotificationRecord record = getBuzzyNotification();
-        metadata.setFlags(Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
-        record.getNotification().setBubbleMetadata(metadata);
-        record.setAllowBubble(true);
-        record.getNotification().flags |= FLAG_BUBBLE;
-        record.isUpdate = true;
-        record.setInterruptive(false);
-
-        mService.buzzBeepBlinkLocked(record);
-        verifyNeverVibrate();
-    }
-
-    @Test
-    public void testOverflowBubbleSuppressedNotificationDoesntMakeSound() {
-        Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
-                mock(PendingIntent.class), mock(Icon.class))
-                .build();
-
-        NotificationRecord record = getBuzzyNotification();
-        metadata.setFlags(Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
-        record.getNotification().setBubbleMetadata(metadata);
-        record.setFlagBubbleRemoved(true);
-        record.setAllowBubble(true);
-        record.isUpdate = true;
-        record.setInterruptive(false);
-
-        mService.buzzBeepBlinkLocked(record);
-        verifyNeverVibrate();
-    }
-
-    @Test
-    public void testBubbleUpdateMakesSound() {
-        Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
-                mock(PendingIntent.class), mock(Icon.class))
-                .build();
-
-        NotificationRecord record = getBuzzyNotification();
-        record.getNotification().setBubbleMetadata(metadata);
-        record.setAllowBubble(true);
-        record.getNotification().flags |= FLAG_BUBBLE;
-        record.isUpdate = true;
-        record.setInterruptive(true);
-
-        mService.buzzBeepBlinkLocked(record);
-        verifyVibrate(1);
-    }
-
-    @Test
-    public void testNewBubbleSuppressedNotifMakesSound() {
-        Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
-                mock(PendingIntent.class), mock(Icon.class))
-                .build();
-
-        NotificationRecord record = getBuzzyNotification();
-        metadata.setFlags(Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
-        record.getNotification().setBubbleMetadata(metadata);
-        record.setAllowBubble(true);
-        record.getNotification().flags |= FLAG_BUBBLE;
-        record.isUpdate = false;
-        record.setInterruptive(true);
-
-        mService.buzzBeepBlinkLocked(record);
-        verifyVibrate(1);
-    }
-
-    @Test
-    public void testStartFlashNotificationEvent_receiveBeepyNotification() throws Exception {
-        NotificationRecord r = getBeepyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyBeepUnlooped();
-        verifyNeverVibrate();
-        verify(mAccessibilityService).startFlashNotificationEvent(any(), anyInt(),
-                eq(r.getSbn().getPackageName()));
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testStartFlashNotificationEvent_receiveBuzzyNotification() throws Exception {
-        NotificationRecord r = getBuzzyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-        verifyVibrate();
-        verify(mAccessibilityService).startFlashNotificationEvent(any(), anyInt(),
-                eq(r.getSbn().getPackageName()));
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testStartFlashNotificationEvent_receiveBuzzyBeepyNotification() throws Exception {
-        NotificationRecord r = getBuzzyBeepyNotification();
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyBeepUnlooped();
-        verifyDelayedVibrate(r.getVibration());
-        verify(mAccessibilityService).startFlashNotificationEvent(any(), anyInt(),
-                eq(r.getSbn().getPackageName()));
-        assertTrue(r.isInterruptive());
-        assertNotEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    @Test
-    public void testStartFlashNotificationEvent_receiveBuzzyBeepyNotification_ringerModeSilent()
-            throws Exception {
-        NotificationRecord r = getBuzzyBeepyNotification();
-        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(0);
-        when(mAudioManager.shouldNotificationSoundPlay(any())).thenReturn(false);
-
-        mService.buzzBeepBlinkLocked(r);
-
-        verifyNeverBeep();
-        verifyNeverVibrate();
-        verify(mAccessibilityService).startFlashNotificationEvent(any(), anyInt(),
-                eq(r.getSbn().getPackageName()));
-        assertFalse(r.isInterruptive());
-        assertEquals(-1, r.getLastAudiblyAlertedMs());
-    }
-
-    static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
-        private final int mRepeatIndex;
-
-        VibrateRepeatMatcher(int repeatIndex) {
-            mRepeatIndex = repeatIndex;
-        }
-
-        @Override
-        public boolean matches(VibrationEffect actual) {
-            if (actual instanceof VibrationEffect.Composed
-                    && ((VibrationEffect.Composed) actual).getRepeatIndex() == mRepeatIndex) {
-                return true;
-            }
-            // All non-waveform effects are essentially one shots.
-            return mRepeatIndex == -1;
-        }
-
-        @Override
-        public String toString() {
-            return "repeatIndex=" + mRepeatIndex;
-        }
-    }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
index a1c24f1..acac63c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAttentionHelperTest.java
@@ -210,7 +210,6 @@
         assertTrue(mAccessibilityManager.isEnabled());
 
         // TODO (b/291907312): remove feature flag
-        mSetFlagsRule.enableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER);
         // Disable feature flags by default. Tests should enable as needed.
         mSetFlagsRule.disableFlags(Flags.FLAG_POLITE_NOTIFICATIONS,
                 Flags.FLAG_CROSS_APP_POLITE_NOTIFICATIONS, Flags.FLAG_VIBRATE_WHILE_UNLOCKED);
@@ -2486,6 +2485,17 @@
         }
     }
 
+    @Test
+    public void testSoundResetsRankingTime() throws Exception {
+        mSetFlagsRule.enableFlags(android.app.Flags.FLAG_UPDATE_RANKING_TIME);
+        TestableFlagResolver flagResolver = new TestableFlagResolver();
+        initAttentionHelper(flagResolver);
+
+        NotificationRecord r = getBuzzyBeepyNotification();
+        mAttentionHelper.buzzBeepBlinkLocked(r, DEFAULT_SIGNALS);
+        assertThat(r.getRankingTimeMs()).isEqualTo(r.getSbn().getPostTime());
+    }
+
     static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
         private final int mRepeatIndex;
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 06a4ac9..4f7be46 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -24,6 +24,7 @@
 import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
+import static android.app.Flags.FLAG_UPDATE_RANKING_TIME;
 import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP;
 import static android.app.Notification.EXTRA_PICTURE;
 import static android.app.Notification.EXTRA_PICTURE_ICON;
@@ -101,7 +102,6 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
@@ -111,11 +111,11 @@
 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED;
-
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
-
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
@@ -124,7 +124,6 @@
 import static junit.framework.Assert.assertSame;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
-
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.isNull;
@@ -132,27 +131,7 @@
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
+import static org.mockito.Mockito.*;
 
 import android.Manifest;
 import android.annotation.Nullable;
@@ -207,7 +186,6 @@
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
 import android.media.AudioManager;
-import android.media.IRingtonePlayer;
 import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.Binder;
@@ -246,7 +224,6 @@
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenPolicy;
 import android.telecom.TelecomManager;
-import android.telephony.TelephonyManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -260,10 +237,8 @@
 import android.util.Pair;
 import android.util.Xml;
 import android.widget.RemoteViews;
-
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
-
 import com.android.internal.R;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.config.sysui.TestableFlagResolver;
@@ -294,13 +269,10 @@
 import com.android.server.utils.quota.MultiRateLimiter;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
-
 import com.google.android.collect.Lists;
 import com.google.common.collect.ImmutableList;
-
 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -439,6 +411,8 @@
     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
             TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
 
+    NotificationChannel mSilentChannel = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+
     private static final int NOTIFICATION_LOCATION_UNKNOWN = 0;
 
     private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
@@ -494,6 +468,9 @@
     @Mock
     StatusBarManagerInternal mStatusBar;
 
+    @Mock
+    NotificationAttentionHelper mAttentionHelper;
+
     private NotificationManagerService.WorkerHandler mWorkerHandler;
 
     private class TestableToastCallback extends ITransientNotification.Stub {
@@ -661,7 +638,7 @@
         // TODO (b/291907312): remove feature flag
         // NOTE: Prefer using the @EnableFlag annotation where possible. Do not add any android.app
         //  flags here.
-        mSetFlagsRule.disableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER,
+        mSetFlagsRule.disableFlags(
                 Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE);
 
         initNMS();
@@ -695,11 +672,12 @@
                 mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm,
                 mAppUsageStats, mDevicePolicyManager, mUgm, mUgmInternal,
                 mAppOpsManager, mUm, mHistoryManager, mStatsManager,
-                mock(TelephonyManager.class),
                 mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
                 mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
                 mPowerManager, mPostNotificationTrackerFactory);
 
+        mService.setAttentionHelper(mAttentionHelper);
+
         // Return first true for RoleObserver main-thread check
         when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
 
@@ -715,13 +693,6 @@
             verify(mHistoryManager).onBootPhaseAppsCanStart();
         }
 
-        // TODO b/291907312: remove feature flag
-        if (Flags.refactorAttentionHelper()) {
-            mService.mAttentionHelper.setAudioManager(mAudioManager);
-        } else {
-            mService.setAudioManager(mAudioManager);
-        }
-
         mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext);
         mService.setStrongAuthTracker(mStrongAuthTracker);
 
@@ -793,14 +764,16 @@
         mBinderService = mService.getBinderService();
         mInternalService = mService.getInternalService();
 
-        mBinderService.createNotificationChannels(
-                PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
-        mBinderService.createNotificationChannels(
-                PKG_P, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
-        mBinderService.createNotificationChannels(
-                PKG_O, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
+        mBinderService.createNotificationChannels(PKG, new ParceledListSlice(
+                Arrays.asList(mTestNotificationChannel, mSilentChannel)));
+        mBinderService.createNotificationChannels(PKG_P, new ParceledListSlice(
+                Arrays.asList(mTestNotificationChannel, mSilentChannel)));
+        mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice(
+                Arrays.asList(mTestNotificationChannel, mSilentChannel)));
         assertNotNull(mBinderService.getNotificationChannel(
                 PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
+        assertNotNull(mBinderService.getNotificationChannel(
+                PKG, mContext.getUserId(), PKG, mSilentChannel.getId()));
         clearInvocations(mRankingHandler);
         when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
 
@@ -1041,11 +1014,16 @@
 
     private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
             int userId) {
+        return generateNotificationRecord(channel, id, userId, "foo");
+    }
+
+    private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
+            int userId, String title) {
         if (channel == null) {
             channel = mTestNotificationChannel;
         }
         Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
-                .setContentTitle("foo")
+                .setContentTitle(title)
                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", mUid, 0,
                 nb.build(), new UserHandle(userId), null, 0);
@@ -1811,23 +1789,6 @@
     }
 
     @Test
-    public void testEnqueueNotificationWithTag_WritesExpectedLogs_NAHRefactor() throws Exception {
-        // TODO b/291907312: remove feature flag
-        mSetFlagsRule.enableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER);
-        // Cleanup NMS before re-initializing
-        if (mService != null) {
-            try {
-                mService.onDestroy();
-            } catch (IllegalStateException | IllegalArgumentException e) {
-                // can throw if a broadcast receiver was never registered
-            }
-        }
-        initNMS();
-
-        testEnqueueNotificationWithTag_WritesExpectedLogs();
-    }
-
-    @Test
     public void testEnqueueNotificationWithTag_LogsOnMajorUpdates() throws Exception {
         final String tag = "testEnqueueNotificationWithTag_LogsOnMajorUpdates";
         Notification original = new Notification.Builder(mContext,
@@ -10105,13 +10066,6 @@
     @Test
     public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped()
             throws RemoteException {
-        IRingtonePlayer mockPlayer = mock(IRingtonePlayer.class);
-        when(mAudioManager.getRingtonePlayer()).thenReturn(mockPlayer);
-        // Set up volume to be above 0, and for AudioManager to signal playback should happen,
-        // for the sound to actually play
-        when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
-        when(mAudioManager.shouldNotificationSoundPlay(any(android.media.AudioAttributes.class)))
-                .thenReturn(true);
 
         setUpPrefsForBubbles(PKG, mUid,
                 true /* global */,
@@ -10130,25 +10084,7 @@
         waitForIdle();
 
         // Check audio is stopped
-        verify(mockPlayer).stopAsync();
-    }
-
-    @Test
-    public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped_NAHRefactor()
-        throws Exception {
-        // TODO b/291907312: remove feature flag
-        mSetFlagsRule.enableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER);
-        // Cleanup NMS before re-initializing
-        if (mService != null) {
-            try {
-                mService.onDestroy();
-            } catch (IllegalStateException | IllegalArgumentException e) {
-                // can throw if a broadcast receiver was never registered
-            }
-        }
-        initNMS();
-
-        testOnBubbleMetadataChangedToSuppressNotification_soundStopped();
+        verify(mAttentionHelper).clearEffectsLocked(nr.getKey());
     }
 
     @Test
@@ -14775,6 +14711,110 @@
         verify(listener, never()).onCallNotificationRemoved(anyString(), any());
     }
 
+    @Test
+    @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+    public void rankingTime_newNotification_noisy_matchesSbn() throws Exception {
+        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, mUserId);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+
+        NotificationRecord posted = mService.mNotificationList.get(0);
+        long originalPostTime = posted.getSbn().getPostTime();
+        assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+    }
+
+    @Test
+    @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+    public void rankingTime_newNotification_silent_matchesSbn() throws Exception {
+        NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+        NotificationRecord nr = generateNotificationRecord(low, mUserId);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+
+        NotificationRecord posted = mService.mNotificationList.get(0);
+        long originalPostTime = posted.getSbn().getPostTime();
+        assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+    }
+
+    @Test
+    @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+    public void rankingTime_updatedNotification_silentSameText_originalPostTime() throws Exception {
+        NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+        NotificationRecord nr = generateNotificationRecord(low, mUserId);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+        NotificationRecord posted = mService.mNotificationList.get(0);
+        long originalPostTime = posted.getSbn().getPostTime();
+        assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+        assertThat(mService.mNotificationList.get(0).getRankingTimeMs())
+                .isEqualTo(originalPostTime);
+    }
+
+    @Test
+    @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+    public void rankingTime_updatedNotification_silentNewText_newPostTime() throws Exception {
+        NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+        NotificationRecord nr = generateNotificationRecord(low, 0, mUserId);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+        NotificationRecord posted = mService.mNotificationList.get(0);
+        long originalPostTime = posted.getSbn().getPostTime();
+        assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+
+        NotificationRecord nrUpdate = generateNotificationRecord(low, 0, mUserId, "bar");
+        // no attention helper mocked behavior needed because this does not make noise
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+                nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
+                nrUpdate.getSbn().getUserId());
+        waitForIdle();
+
+        posted = mService.mNotificationList.get(0);
+        assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
+        assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
+    }
+
+    @Test
+    @EnableFlags(FLAG_UPDATE_RANKING_TIME)
+    public void rankingTime_updatedNotification_noisySameText_newPostTime() throws Exception {
+        NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW);
+        NotificationRecord nr = generateNotificationRecord(low, mUserId);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+        NotificationRecord posted = mService.mNotificationList.get(0);
+        long originalPostTime = posted.getSbn().getPostTime();
+        assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime);
+
+        NotificationRecord nrUpdate = generateNotificationRecord(mTestNotificationChannel, mUserId);
+        when(mAttentionHelper.buzzBeepBlinkLocked(any(), any())).thenAnswer(new Answer<Object>() {
+            public Object answer(InvocationOnMock invocation) {
+                Object[] args = invocation.getArguments();
+                ((NotificationRecord) args[0]).resetRankingTime();
+                return 2; // beep
+            }
+        });
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+                nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(),
+                nrUpdate.getSbn().getUserId());
+        waitForIdle();
+        posted = mService.mNotificationList.get(0);
+        assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime);
+        assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime());
+    }
+
     private NotificationRecord createAndPostCallStyleNotification(String packageName,
             UserHandle userHandle, String testName) throws Exception {
         Person person = new Person.Builder().setName("caller").build();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 70910b1..c1bb3e7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -164,7 +164,7 @@
                     mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
                     mock(UriGrantsManagerInternal.class),
                     mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class),
-                    mock(StatsManager.class), mock(TelephonyManager.class),
+                    mock(StatsManager.class),
                     mock(ActivityManagerInternal.class),
                     mock(MultiRateLimiter.class), mock(PermissionHelper.class),
                     mock(UsageStatsManagerInternal.class), mock(TelecomManager.class),
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index 0b76154..19ce217 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -251,9 +251,9 @@
 
         VibrationEffect effect = VibrationEffect.createWaveform(
                 new long[]{5, 5, 5}, new int[]{1, 1, 1}, -1);
-        CompletableFuture<Void> mRequestVibrationParamsFuture = CompletableFuture.runAsync(() -> {
-            mVibrationScaler.updateAdaptiveHapticsScale(USAGE_RINGTONE, 0.5f);
-        });
+        mVibrationScaler.updateAdaptiveHapticsScale(USAGE_RINGTONE, 0.5f);
+        CompletableFuture<Void> mRequestVibrationParamsFuture = CompletableFuture.completedFuture(
+                null);
         long vibrationId = startThreadAndDispatcher(effect, mRequestVibrationParamsFuture,
                 USAGE_RINGTONE);
         waitForCompletion();
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 5861d88..185677f 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -1589,7 +1589,8 @@
         assertEquals(1f, ((PrimitiveSegment) segments.get(2)).getScale(), 1e-5);
         verify(mVibratorFrameworkStatsLoggerMock).logVibrationAdaptiveHapticScale(UID, 0.7f);
         verify(mVibratorFrameworkStatsLoggerMock).logVibrationAdaptiveHapticScale(UID, 0.4f);
-        verify(mVibratorFrameworkStatsLoggerMock).logVibrationAdaptiveHapticScale(UID, 1f);
+        verify(mVibratorFrameworkStatsLoggerMock,
+                timeout(TEST_TIMEOUT_MILLIS)).logVibrationAdaptiveHapticScale(UID, 1f);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index ff7129c..0186006 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -64,8 +64,10 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -2368,9 +2370,7 @@
         assertTrue(transitA.isCollecting());
 
         // finish collecting A
-        transitA.start();
-        transitA.setAllReady();
-        mSyncEngine.tryFinishForTest(transitA.getSyncId());
+        tryFinishTransitionSyncSet(transitA);
         waitUntilHandlersIdle();
 
         assertTrue(transitA.isPlaying());
@@ -2476,6 +2476,36 @@
     }
 
     @Test
+    public void testDeferredMoveTaskToBack() {
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final Task task = activity.getTask();
+        registerTestTransitionPlayer();
+        final TransitionController controller = mWm.mRoot.mTransitionController;
+        mSyncEngine = createTestBLASTSyncEngine();
+        controller.setSyncEngine(mSyncEngine);
+        final Transition transition = createTestTransition(TRANSIT_CHANGE, controller);
+        controller.moveToCollecting(transition);
+        task.moveTaskToBack(task);
+        // Actual action will be deferred by current transition.
+        verify(task, never()).moveToBack(any(), any());
+
+        tryFinishTransitionSyncSet(transition);
+        waitUntilHandlersIdle();
+        // Continue to move task to back after the transition is done.
+        verify(task).moveToBack(any(), any());
+        final Transition moveBackTransition = controller.getCollectingTransition();
+        assertNotNull(moveBackTransition);
+        moveBackTransition.abort();
+
+        // The move-to-back can be collected in to a collecting OPEN transition.
+        clearInvocations(task);
+        final Transition transition2 = createTestTransition(TRANSIT_OPEN, controller);
+        controller.moveToCollecting(transition2);
+        task.moveTaskToBack(task);
+        verify(task).moveToBack(any(), any());
+    }
+
+    @Test
     public void testNoSyncFlagIfOneTrack() {
         final TransitionController controller = mAtm.getTransitionController();
         final TestTransitionPlayer player = registerTestTransitionPlayer();
@@ -2492,17 +2522,11 @@
         controller.startCollectOrQueue(transitC, (deferred) -> {});
 
         // Verify that, as-long as there is <= 1 track, we won't get a SYNC flag
-        transitA.start();
-        transitA.setAllReady();
-        mSyncEngine.tryFinishForTest(transitA.getSyncId());
+        tryFinishTransitionSyncSet(transitA);
         assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
-        transitB.start();
-        transitB.setAllReady();
-        mSyncEngine.tryFinishForTest(transitB.getSyncId());
+        tryFinishTransitionSyncSet(transitB);
         assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
-        transitC.start();
-        transitC.setAllReady();
-        mSyncEngine.tryFinishForTest(transitC.getSyncId());
+        tryFinishTransitionSyncSet(transitC);
         assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
     }
 
@@ -2642,6 +2666,12 @@
         assertEquals("reason1", condition1.mAlternate);
     }
 
+    private void tryFinishTransitionSyncSet(Transition transition) {
+        transition.setAllReady();
+        transition.start();
+        mSyncEngine.tryFinishForTest(transition.getSyncId());
+    }
+
     private static void makeTaskOrganized(Task... tasks) {
         final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
         for (Task t : tasks) {