Merge "Bug fix flag to show different error screen for PS creation" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index d610f4c..c5a70df 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -34161,6 +34161,7 @@
     field public static final int USAGE_CLASS_UNKNOWN = 0; // 0x0
     field public static final int USAGE_COMMUNICATION_REQUEST = 65; // 0x41
     field public static final int USAGE_HARDWARE_FEEDBACK = 50; // 0x32
+    field @FlaggedApi("android.os.vibrator.vibration_attribute_ime_usage_api") public static final int USAGE_IME_FEEDBACK = 82; // 0x52
     field public static final int USAGE_MEDIA = 19; // 0x13
     field public static final int USAGE_NOTIFICATION = 49; // 0x31
     field public static final int USAGE_PHYSICAL_EMULATION = 34; // 0x22
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index 19de793..a1ae9da 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -84,6 +84,13 @@
 }
 
 flag {
+     namespace: "virtual_devices"
+     name: "enforce_remote_device_opt_out_on_all_virtual_displays"
+     description: "Respect canDisplayOnRemoteDevices on all virtual displays"
+     bug: "338973239"
+}
+
+flag {
     namespace: "virtual_devices"
     name: "virtual_display_multi_window_mode_support"
     description: "Add support for WINDOWING_MODE_MULTI_WINDOW to virtual displays by default"
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 6952a09..481e6b5 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -617,7 +617,7 @@
      */
     public static final int FLAG_ENABLE_VR_MODE = 0x8000;
     /**
-     * Bit in {@link #flags} indicating if the activity can be displayed on a remote device.
+     * Bit in {@link #flags} indicating if the activity can be displayed on a virtual display.
      * Corresponds to {@link android.R.attr#canDisplayOnRemoteDevices}
      * @hide
      */
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index fe14d457..00ce949 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1171,12 +1171,14 @@
             }
             switch (motionEvent.getAction()) {
                 case MotionEvent.ACTION_DOWN:
+                case MotionEvent.ACTION_HOVER_ENTER:
                     // Consume and ignore all touches while stylus is down to prevent
                     // accidental touches from going to the app while writing.
                     mPrivOps.setHandwritingSurfaceNotTouchable(false);
                     break;
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
+                case MotionEvent.ACTION_HOVER_EXIT:
                     // Go back to only consuming stylus events so that the user
                     // can continue to interact with the app using touch
                     // when the stylus is not down.
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 9df5b85..da863e5 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -16,6 +16,9 @@
 
 package android.os;
 
+import static android.os.vibrator.Flags.FLAG_VIBRATION_ATTRIBUTE_IME_USAGE_API;
+
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -55,6 +58,7 @@
             USAGE_PHYSICAL_EMULATION,
             USAGE_RINGTONE,
             USAGE_TOUCH,
+            USAGE_IME_FEEDBACK,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Usage {}
@@ -136,6 +140,12 @@
      */
     public static final int USAGE_ACCESSIBILITY = 0x40 | USAGE_CLASS_FEEDBACK;
     /**
+     * Usage value to use for input method editor (IME) haptic feedback.
+     */
+    @FlaggedApi(FLAG_VIBRATION_ATTRIBUTE_IME_USAGE_API)
+    public static final int USAGE_IME_FEEDBACK = 0x50 | USAGE_CLASS_FEEDBACK;
+
+    /**
      * Usage value to use for media vibrations, such as music, movie, soundtrack, animations, games,
      * or any interactive media that isn't for touch feedback specifically.
      */
@@ -174,7 +184,6 @@
             FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF,
             FLAG_INVALIDATE_SETTINGS_CACHE,
             FLAG_PIPELINED_EFFECT,
-            FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Flag{}
@@ -228,31 +237,12 @@
     public static final int FLAG_PIPELINED_EFFECT = 1 << 3;
 
     /**
-     * Flag requesting that this vibration effect to be played without applying the user
-     * intensity setting to scale the vibration.
-     *
-     * <p>The user setting is still applied to enable/disable the vibration, but the vibration
-     * effect strength will not be scaled based on the enabled setting value.
-     *
-     * <p>This is intended to be used on scenarios where the system needs to enforce a specific
-     * strength for the vibration effect, regardless of the user preference. Only privileged apps
-     * can ignore user settings, and this flag will be ignored otherwise.
-     *
-     * <p>If you need to bypass the user setting when it's disabling vibrations then this also
-     * needs the flag {@link #FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF} to be set.
-     *
-     * @hide
-     */
-    public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE = 1 << 4;
-
-    /**
      * All flags supported by vibrator service, update it when adding new flag.
      * @hide
      */
     public static final int FLAG_ALL_SUPPORTED =
             FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF
-                    | FLAG_INVALIDATE_SETTINGS_CACHE | FLAG_PIPELINED_EFFECT
-                    | FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE;
+                    | FLAG_INVALIDATE_SETTINGS_CACHE | FLAG_PIPELINED_EFFECT;
 
     /** Creates a new {@link VibrationAttributes} instance with given usage. */
     public static @NonNull VibrationAttributes createForUsage(@Usage int usage) {
@@ -349,6 +339,7 @@
             case USAGE_RINGTONE:
                 return AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
             case USAGE_TOUCH:
+            case USAGE_IME_FEEDBACK:
                 return AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
             case USAGE_ALARM:
                 return AudioAttributes.USAGE_ALARM;
@@ -447,6 +438,8 @@
                 return "PHYSICAL_EMULATION";
             case USAGE_HARDWARE_FEEDBACK:
                 return "HARDWARE_FEEDBACK";
+            case USAGE_IME_FEEDBACK:
+                return "IME";
             default:
                 return "unknown usage " + usage;
         }
diff --git a/core/java/android/os/vibrator/VibrationConfig.java b/core/java/android/os/vibrator/VibrationConfig.java
index f6e73b3..a4164e9 100644
--- a/core/java/android/os/vibrator/VibrationConfig.java
+++ b/core/java/android/os/vibrator/VibrationConfig.java
@@ -20,6 +20,7 @@
 import static android.os.VibrationAttributes.USAGE_ALARM;
 import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
 import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK;
+import static android.os.VibrationAttributes.USAGE_IME_FEEDBACK;
 import static android.os.VibrationAttributes.USAGE_MEDIA;
 import static android.os.VibrationAttributes.USAGE_NOTIFICATION;
 import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION;
@@ -67,6 +68,8 @@
     private final int mDefaultNotificationVibrationIntensity;
     @VibrationIntensity
     private final int mDefaultRingVibrationIntensity;
+    @VibrationIntensity
+    private final int mDefaultKeyboardVibrationIntensity;
 
     private final boolean mKeyboardVibrationSettingsSupported;
 
@@ -98,6 +101,8 @@
                 com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
         mDefaultRingVibrationIntensity = loadDefaultIntensity(resources,
                 com.android.internal.R.integer.config_defaultRingVibrationIntensity);
+        mDefaultKeyboardVibrationIntensity = loadDefaultIntensity(resources,
+                com.android.internal.R.integer.config_defaultKeyboardVibrationIntensity);
     }
 
     @VibrationIntensity
@@ -213,6 +218,9 @@
             case USAGE_PHYSICAL_EMULATION:
             case USAGE_ACCESSIBILITY:
                 return mDefaultHapticFeedbackIntensity;
+            case USAGE_IME_FEEDBACK:
+                return isKeyboardVibrationSettingsSupported()
+                        ? mDefaultKeyboardVibrationIntensity : mDefaultHapticFeedbackIntensity;
             case USAGE_MEDIA:
             case USAGE_UNKNOWN:
                 // fall through
@@ -236,6 +244,7 @@
                 + ", mDefaultMediaIntensity=" + mDefaultMediaVibrationIntensity
                 + ", mDefaultNotificationIntensity=" + mDefaultNotificationVibrationIntensity
                 + ", mDefaultRingIntensity=" + mDefaultRingVibrationIntensity
+                + ", mDefaultKeyboardIntensity=" + mDefaultKeyboardVibrationIntensity
                 + ", mKeyboardVibrationSettingsSupported=" + mKeyboardVibrationSettingsSupported
                 + "}";
     }
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index 62b3682..67c3464 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -74,3 +74,14 @@
       purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    namespace: "haptics"
+    name: "vibration_attribute_ime_usage_api"
+    is_exported: true
+    description: "A public API for IME usage vibration attribute"
+    bug: "332661766"
+    metadata {
+        purpose: PURPOSE_FEATURE
+    }
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 725d496..e5a9b6a 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -65,14 +65,6 @@
 }
 
 flag {
-    name: "defer_display_updates"
-    namespace: "windowing_frontend"
-    description: "Feature flag for deferring DisplayManager updates to WindowManager if Shell transition is running"
-    bug: "259220649"
-    is_fixed_read_only: true
-}
-
-flag {
   name: "close_to_square_config_includes_status_bar"
   namespace: "windowing_frontend"
   description: "On close to square display, when necessary, configuration includes status bar"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 2e3dbda..0be33c2 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -3296,8 +3296,8 @@
              usually TVs.
              <p>Requires permission {@code android.permission.DISABLE_SYSTEM_SOUND_EFFECTS}. -->
         <attr name="playHomeTransitionSound" format="boolean"/>
-        <!-- Indicates whether the activity can be displayed on a remote device which may or
-             may not be running Android. -->
+        <!-- Indicates whether the activity can be displayed on a display that may belong to a
+             remote device which may or may not be running Android. -->
         <attr name="canDisplayOnRemoteDevices" format="boolean"/>
         <attr name="allowUntrustedActivityEmbedding" />
         <attr name="knownActivityEmbeddingCerts" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2afc303..8ed444d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1399,6 +1399,10 @@
          Settings.System.RING_VIBRATION_INTENSITY more details on the constant values and
          meanings. -->
     <integer name="config_defaultRingVibrationIntensity">2</integer>
+    <!-- The default intensity level for keyboard vibrations. Note that this will only be applied
+         on devices where config_keyboardVibrationSettingsSupported is true, otherwise the
+         keyboard vibration will follow config_defaultHapticFeedbackIntensity -->
+    <integer name="config_defaultKeyboardVibrationIntensity">2</integer>
 
     <!-- Whether to use the strict phone number matcher by default. -->
     <bool name="config_use_strict_phone_number_comparation">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bc8c778..6b58396 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4223,6 +4223,7 @@
   <java-symbol type="integer" name="config_defaultMediaVibrationIntensity" />
   <java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
   <java-symbol type="integer" name="config_defaultRingVibrationIntensity" />
+  <java-symbol type="integer" name="config_defaultKeyboardVibrationIntensity" />
 
   <java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" />
 
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
index 94ff65e..4e1829a 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
@@ -26,6 +26,7 @@
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
@@ -49,6 +50,7 @@
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
+import com.airbnb.lottie.LottieComposition
 import com.airbnb.lottie.LottieProperty
 import com.airbnb.lottie.compose.LottieAnimation
 import com.airbnb.lottie.compose.LottieCompositionSpec
@@ -61,6 +63,9 @@
 import com.airbnb.lottie.compose.rememberLottieDynamicProperty
 import com.android.compose.theme.LocalAndroidColorScheme
 import com.android.systemui.res.R
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.IN_PROGRESS
 import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGesture.BACK
 import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGestureHandler
 
@@ -78,23 +83,49 @@
 ) {
     val screenColors = rememberScreenColors()
     BackHandler(onBack = onBack)
-    var gestureDone by remember { mutableStateOf(false) }
+    var gestureState by remember { mutableStateOf(GestureState.NOT_STARTED) }
     val swipeDistanceThresholdPx =
         LocalContext.current.resources.getDimensionPixelSize(
             com.android.internal.R.dimen.system_gestures_distance_threshold
         )
     val gestureHandler =
         remember(swipeDistanceThresholdPx) {
-            TouchpadGestureHandler(BACK, swipeDistanceThresholdPx, onDone = { gestureDone = true })
+            TouchpadGestureHandler(
+                BACK,
+                swipeDistanceThresholdPx,
+                onGestureStateChanged = { gestureState = it }
+            )
         }
+    TouchpadGesturesHandlingBox(gestureHandler, gestureState) {
+        GestureTutorialContent(gestureState, onDoneButtonClicked, screenColors)
+    }
+}
+
+@Composable
+private fun TouchpadGesturesHandlingBox(
+    gestureHandler: TouchpadGestureHandler,
+    gestureState: GestureState,
+    modifier: Modifier = Modifier,
+    content: @Composable BoxScope.() -> Unit
+) {
     Box(
         modifier =
-            Modifier.fillMaxSize()
+            modifier
+                .fillMaxSize()
                 // we need to use pointerInteropFilter because some info about touchpad gestures is
                 // only available in MotionEvent
-                .pointerInteropFilter(onTouchEvent = gestureHandler::onMotionEvent)
+                .pointerInteropFilter(
+                    onTouchEvent = { event ->
+                        // FINISHED is the final state so we don't need to process touches anymore
+                        if (gestureState != FINISHED) {
+                            gestureHandler.onMotionEvent(event)
+                        } else {
+                            false
+                        }
+                    }
+                )
     ) {
-        GestureTutorialContent(gestureDone, onDoneButtonClicked, screenColors)
+        content()
     }
 }
 
@@ -126,14 +157,14 @@
 
 @Composable
 private fun GestureTutorialContent(
-    gestureDone: Boolean,
+    gestureState: GestureState,
     onDoneButtonClicked: () -> Unit,
     screenColors: TutorialScreenColors
 ) {
     val animatedColor by
         animateColorAsState(
             targetValue =
-                if (gestureDone) screenColors.successBackgroundColor
+                if (gestureState == FINISHED) screenColors.successBackgroundColor
                 else screenColors.backgroundColor,
             animationSpec = tween(durationMillis = 150, easing = LinearEasing),
             label = "backgroundColor"
@@ -148,7 +179,7 @@
         Row(modifier = Modifier.fillMaxWidth().weight(1f)) {
             TutorialDescription(
                 titleTextId =
-                    if (gestureDone) R.string.touchpad_tutorial_gesture_done
+                    if (gestureState == FINISHED) R.string.touchpad_tutorial_gesture_done
                     else R.string.touchpad_back_gesture_action_title,
                 titleColor = screenColors.titleColor,
                 bodyTextId = R.string.touchpad_back_gesture_guidance,
@@ -156,7 +187,7 @@
             )
             Spacer(modifier = Modifier.width(76.dp))
             TutorialAnimation(
-                gestureDone,
+                gestureState,
                 screenColors.animationProperties,
                 modifier = Modifier.weight(1f).padding(top = 8.dp)
             )
@@ -189,27 +220,38 @@
 
 @Composable
 fun TutorialAnimation(
-    gestureDone: Boolean,
+    gestureState: GestureState,
     animationProperties: LottieDynamicProperties,
     modifier: Modifier = Modifier
 ) {
     Column(modifier = modifier.fillMaxWidth()) {
-        val resId = if (gestureDone) R.raw.trackpad_back_success else R.raw.trackpad_back_edu
+        val resId =
+            if (gestureState == FINISHED) R.raw.trackpad_back_success else R.raw.trackpad_back_edu
         val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(resId))
-        val progress by
-            animateLottieCompositionAsState(
-                composition,
-                iterations = if (gestureDone) 1 else LottieConstants.IterateForever
-            )
+        val progress = progressForGestureState(composition, gestureState)
         LottieAnimation(
             composition = composition,
-            progress = { progress },
+            progress = progress,
             dynamicProperties = animationProperties
         )
     }
 }
 
 @Composable
+private fun progressForGestureState(
+    composition: LottieComposition?,
+    gestureState: GestureState
+): () -> Float {
+    if (gestureState == IN_PROGRESS) {
+        return { 0f } // when gesture is in progress, animation should freeze on 1st frame
+    } else {
+        val iterations = if (gestureState == FINISHED) 1 else LottieConstants.IterateForever
+        val animationState by animateLottieCompositionAsState(composition, iterations = iterations)
+        return { animationState }
+    }
+}
+
+@Composable
 fun rememberColorFilterProperty(
     layerName: String,
     color: Color
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitor.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitor.kt
index 1fa7a0c..6fa9bcd 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitor.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitor.kt
@@ -17,23 +17,26 @@
 package com.android.systemui.touchpad.tutorial.ui.gesture
 
 import android.view.MotionEvent
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.IN_PROGRESS
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NOT_STARTED
 import kotlin.math.abs
 
 /**
- * Monitor for touchpad gestures that calls [gestureDoneCallback] when gesture was successfully
- * done. All tracked motion events should be passed to [processTouchpadEvent]
+ * Monitor for touchpad gestures that calls [gestureStateChangedCallback] when [GestureState]
+ * changes. All tracked motion events should be passed to [processTouchpadEvent]
  */
 interface TouchpadGestureMonitor {
 
     val gestureDistanceThresholdPx: Int
-    val gestureDoneCallback: () -> Unit
+    val gestureStateChangedCallback: (GestureState) -> Unit
 
     fun processTouchpadEvent(event: MotionEvent)
 }
 
 class BackGestureMonitor(
     override val gestureDistanceThresholdPx: Int,
-    override val gestureDoneCallback: () -> Unit
+    override val gestureStateChangedCallback: (GestureState) -> Unit
 ) : TouchpadGestureMonitor {
 
     private var xStart = 0f
@@ -44,13 +47,16 @@
             MotionEvent.ACTION_DOWN -> {
                 if (isThreeFingerTouchpadSwipe(event)) {
                     xStart = event.x
+                    gestureStateChangedCallback(IN_PROGRESS)
                 }
             }
             MotionEvent.ACTION_UP -> {
                 if (isThreeFingerTouchpadSwipe(event)) {
                     val distance = abs(event.x - xStart)
                     if (distance >= gestureDistanceThresholdPx) {
-                        gestureDoneCallback()
+                        gestureStateChangedCallback(FINISHED)
+                    } else {
+                        gestureStateChangedCallback(NOT_STARTED)
                     }
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureState.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureState.kt
new file mode 100644
index 0000000..446875a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/GestureState.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.touchpad.tutorial.ui.gesture
+
+enum class GestureState {
+    NOT_STARTED,
+    IN_PROGRESS,
+    FINISHED
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGesture.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGesture.kt
index 4ae9c7b..190da62 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGesture.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGesture.kt
@@ -22,10 +22,10 @@
 
     fun toMonitor(
         swipeDistanceThresholdPx: Int,
-        gestureDoneCallback: () -> Unit
+        onStateChanged: (GestureState) -> Unit
     ): TouchpadGestureMonitor {
         return when (this) {
-            BACK -> BackGestureMonitor(swipeDistanceThresholdPx, gestureDoneCallback)
+            BACK -> BackGestureMonitor(swipeDistanceThresholdPx, onStateChanged)
             else -> throw IllegalArgumentException("Not implemented yet")
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandler.kt
index dc8471c..cac2a99 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandler.kt
@@ -26,11 +26,11 @@
 class TouchpadGestureHandler(
     touchpadGesture: TouchpadGesture,
     swipeDistanceThresholdPx: Int,
-    onDone: () -> Unit
+    onGestureStateChanged: (GestureState) -> Unit
 ) {
 
     private val gestureRecognition =
-        touchpadGesture.toMonitor(swipeDistanceThresholdPx, gestureDoneCallback = onDone)
+        touchpadGesture.toMonitor(swipeDistanceThresholdPx, onStateChanged = onGestureStateChanged)
 
     fun onMotionEvent(event: MotionEvent): Boolean {
         // events from touchpad have SOURCE_MOUSE and not SOURCE_TOUCHPAD because of legacy reasons
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
index cf0db7b..8875b84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
@@ -28,6 +28,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.IN_PROGRESS
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NOT_STARTED
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -36,16 +39,19 @@
 @RunWith(AndroidJUnit4::class)
 class BackGestureMonitorTest : SysuiTestCase() {
 
-    private var gestureDoneWasCalled = false
-    private val gestureDoneCallback = { gestureDoneWasCalled = true }
-    private val gestureMonitor = BackGestureMonitor(SWIPE_DISTANCE.toInt(), gestureDoneCallback)
+    private var gestureState = NOT_STARTED
+    private val gestureMonitor =
+        BackGestureMonitor(
+            gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
+            gestureStateChangedCallback = { gestureState = it }
+        )
 
     companion object {
         const val SWIPE_DISTANCE = 100f
     }
 
     @Test
-    fun triggersGestureDoneForThreeFingerGestureRight() {
+    fun triggersGestureFinishedForThreeFingerGestureRight() {
         val events =
             listOf(
                 threeFingerEvent(ACTION_DOWN, x = 0f, y = 0f),
@@ -59,11 +65,11 @@
 
         events.forEach { gestureMonitor.processTouchpadEvent(it) }
 
-        assertThat(gestureDoneWasCalled).isTrue()
+        assertThat(gestureState).isEqualTo(FINISHED)
     }
 
     @Test
-    fun triggersGestureDoneForThreeFingerGestureLeft() {
+    fun triggersGestureFinishedForThreeFingerGestureLeft() {
         val events =
             listOf(
                 threeFingerEvent(ACTION_DOWN, x = SWIPE_DISTANCE, y = 0f),
@@ -77,7 +83,21 @@
 
         events.forEach { gestureMonitor.processTouchpadEvent(it) }
 
-        assertThat(gestureDoneWasCalled).isTrue()
+        assertThat(gestureState).isEqualTo(FINISHED)
+    }
+
+    @Test
+    fun triggersGestureProgressForThreeFingerGestureStarted() {
+        val events =
+            listOf(
+                threeFingerEvent(ACTION_DOWN, x = SWIPE_DISTANCE, y = 0f),
+                threeFingerEvent(ACTION_POINTER_DOWN, x = SWIPE_DISTANCE, y = 0f),
+                threeFingerEvent(ACTION_POINTER_DOWN, x = SWIPE_DISTANCE, y = 0f),
+            )
+
+        events.forEach { gestureMonitor.processTouchpadEvent(it) }
+
+        assertThat(gestureState).isEqualTo(IN_PROGRESS)
     }
 
     private fun threeFingerEvent(action: Int, x: Float, y: Float): MotionEvent {
@@ -91,7 +111,7 @@
     }
 
     @Test
-    fun doesntTriggerGestureDone_onThreeFingersSwipeUp() {
+    fun doesntTriggerGestureFinished_onThreeFingersSwipeUp() {
         val events =
             listOf(
                 threeFingerEvent(ACTION_DOWN, x = 0f, y = 0f),
@@ -105,11 +125,11 @@
 
         events.forEach { gestureMonitor.processTouchpadEvent(it) }
 
-        assertThat(gestureDoneWasCalled).isFalse()
+        assertThat(gestureState).isEqualTo(NOT_STARTED)
     }
 
     @Test
-    fun doesntTriggerGestureDone_onTwoFingersSwipe() {
+    fun doesntTriggerGestureFinished_onTwoFingersSwipe() {
         fun twoFingerEvent(action: Int, x: Float, y: Float) =
             motionEvent(
                 action = action,
@@ -127,11 +147,11 @@
 
         events.forEach { gestureMonitor.processTouchpadEvent(it) }
 
-        assertThat(gestureDoneWasCalled).isFalse()
+        assertThat(gestureState).isEqualTo(NOT_STARTED)
     }
 
     @Test
-    fun doesntTriggerGestureDone_onFourFingersSwipe() {
+    fun doesntTriggerGestureFinished_onFourFingersSwipe() {
         fun fourFingerEvent(action: Int, x: Float, y: Float) =
             motionEvent(
                 action = action,
@@ -155,6 +175,6 @@
 
         events.forEach { gestureMonitor.processTouchpadEvent(it) }
 
-        assertThat(gestureDoneWasCalled).isFalse()
+        assertThat(gestureState).isEqualTo(NOT_STARTED)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
index 769f264..dc4d5f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
@@ -32,6 +32,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
+import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NOT_STARTED
 import com.android.systemui.touchpad.tutorial.ui.gesture.TouchpadGesture.BACK
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
@@ -41,8 +43,8 @@
 @RunWith(AndroidJUnit4::class)
 class TouchpadGestureHandlerTest : SysuiTestCase() {
 
-    private var gestureDone = false
-    private val handler = TouchpadGestureHandler(BACK, SWIPE_DISTANCE) { gestureDone = true }
+    private var gestureState = NOT_STARTED
+    private val handler = TouchpadGestureHandler(BACK, SWIPE_DISTANCE) { gestureState = it }
 
     companion object {
         const val SWIPE_DISTANCE = 100
@@ -84,7 +86,7 @@
     fun triggersGestureDoneForThreeFingerGesture() {
         backGestureEvents().forEach { handler.onMotionEvent(it) }
 
-        assertThat(gestureDone).isTrue()
+        assertThat(gestureState).isEqualTo(FINISHED)
     }
 
     private fun backGestureEvents(): List<MotionEvent> {
diff --git a/services/core/java/com/android/server/vibrator/HalVibration.java b/services/core/java/com/android/server/vibrator/HalVibration.java
index f9bad59..46bd7af 100644
--- a/services/core/java/com/android/server/vibrator/HalVibration.java
+++ b/services/core/java/com/android/server/vibrator/HalVibration.java
@@ -108,23 +108,6 @@
     }
 
     /**
-     * Resolves the default vibration amplitude of {@link #getEffectToPlay()} and each fallback.
-     *
-     * @param defaultAmplitude An integer in [1,255] representing the device default amplitude to
-     *                        replace the {@link VibrationEffect#DEFAULT_AMPLITUDE}.
-     */
-    public void resolveEffects(int defaultAmplitude) {
-        CombinedVibration newEffect =
-                mEffectToPlay.transform(VibrationEffect::resolve, defaultAmplitude);
-        if (!Objects.equals(mEffectToPlay, newEffect)) {
-            mEffectToPlay = newEffect;
-        }
-        for (int i = 0; i < mFallbacks.size(); i++) {
-            mFallbacks.setValueAt(i, mFallbacks.valueAt(i).resolve(defaultAmplitude));
-        }
-    }
-
-    /**
      * Scales the {@link #getEffectToPlay()} and each fallback effect based on the vibration usage.
      */
     public void scaleEffects(VibrationScaler scaler) {
diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
index 98a2ba0d..3f9da82 100644
--- a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
+++ b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
@@ -46,6 +46,8 @@
             VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
     private static final VibrationAttributes COMMUNICATION_REQUEST_VIBRATION_ATTRIBUTES =
             VibrationAttributes.createForUsage(VibrationAttributes.USAGE_COMMUNICATION_REQUEST);
+    private static final VibrationAttributes IME_FEEDBACK_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_IME_FEEDBACK);
 
     private final VibratorInfo mVibratorInfo;
     private final boolean mHapticTextHandleEnabled;
@@ -219,8 +221,6 @@
         }
 
         int vibFlags = 0;
-        boolean fromIme =
-                (privFlags & HapticFeedbackConstants.PRIVATE_FLAG_APPLY_INPUT_METHOD_SETTINGS) != 0;
         boolean bypassVibrationIntensitySetting =
                 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0;
         if (bypassVibrationIntensitySetting) {
@@ -229,9 +229,6 @@
         if (shouldBypassInterruptionPolicy(effectId)) {
             vibFlags |= VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
         }
-        if (shouldBypassIntensityScale(effectId, fromIme)) {
-            vibFlags |= VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE;
-        }
 
         return vibFlags == 0 ? attrs : new VibrationAttributes.Builder(attrs)
                 .setFlags(vibFlags).build();
@@ -362,22 +359,6 @@
                 /* fallbackForPredefinedEffect= */ predefinedEffectFallback);
     }
 
-    private boolean shouldBypassIntensityScale(int effectId, boolean isIme) {
-        if (!Flags.keyboardCategoryEnabled() || mKeyboardVibrationFixedAmplitude < 0 || !isIme) {
-            // Shouldn't bypass if not support keyboard category, no fixed amplitude or not an IME.
-            return false;
-        }
-        switch (effectId) {
-            case HapticFeedbackConstants.KEYBOARD_TAP:
-                return mVibratorInfo.isPrimitiveSupported(
-                        VibrationEffect.Composition.PRIMITIVE_CLICK);
-            case HapticFeedbackConstants.KEYBOARD_RELEASE:
-                return mVibratorInfo.isPrimitiveSupported(
-                        VibrationEffect.Composition.PRIMITIVE_TICK);
-        }
-        return false;
-    }
-
     private VibrationAttributes createKeyboardVibrationAttributes(
             @HapticFeedbackConstants.PrivateFlags int privFlags) {
         // Use touch attribute when the keyboard category is disable.
@@ -388,7 +369,8 @@
         if ((privFlags & HapticFeedbackConstants.PRIVATE_FLAG_APPLY_INPUT_METHOD_SETTINGS) == 0) {
             return TOUCH_VIBRATION_ATTRIBUTES;
         }
-        return new VibrationAttributes.Builder(TOUCH_VIBRATION_ATTRIBUTES)
+        return new VibrationAttributes.Builder(IME_FEEDBACK_VIBRATION_ATTRIBUTES)
+                // TODO(b/332661766): Remove CATEGORY_KEYBOARD logic
                 .setCategory(VibrationAttributes.CATEGORY_KEYBOARD)
                 .build();
     }
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 0206155..fb92d60 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -21,6 +21,7 @@
 import static android.os.VibrationAttributes.USAGE_ALARM;
 import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
 import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK;
+import static android.os.VibrationAttributes.USAGE_IME_FEEDBACK;
 import static android.os.VibrationAttributes.USAGE_MEDIA;
 import static android.os.VibrationAttributes.USAGE_NOTIFICATION;
 import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION;
@@ -560,6 +561,7 @@
             mKeyboardVibrationOn = loadSystemSetting(
                     Settings.System.KEYBOARD_VIBRATION_ENABLED, 1, userHandle) > 0;
 
+            int keyboardIntensity = getDefaultIntensity(USAGE_IME_FEEDBACK);
             int alarmIntensity = toIntensity(
                     loadSystemSetting(Settings.System.ALARM_VIBRATION_INTENSITY, -1, userHandle),
                     getDefaultIntensity(USAGE_ALARM));
@@ -610,6 +612,12 @@
                 mCurrentVibrationIntensities.put(USAGE_TOUCH, hapticFeedbackIntensity);
             }
 
+            if (mVibrationConfig.isKeyboardVibrationSettingsSupported()) {
+                mCurrentVibrationIntensities.put(USAGE_IME_FEEDBACK, keyboardIntensity);
+            } else {
+                mCurrentVibrationIntensities.put(USAGE_IME_FEEDBACK, hapticFeedbackIntensity);
+            }
+
             // A11y is not disabled by any haptic feedback setting.
             mCurrentVibrationIntensities.put(USAGE_ACCESSIBILITY, positiveHapticFeedbackIntensity);
         }
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index 8c9a92d..7152844 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -21,7 +21,6 @@
 import android.os.Build;
 import android.os.CombinedVibration;
 import android.os.IBinder;
-import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.vibrator.Flags;
 import android.os.vibrator.PrebakedSegment;
@@ -177,16 +176,11 @@
             expectIsVibrationThread(true);
         }
 
-        if (!mVibration.callerInfo.attrs.isFlagSet(
-                VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)) {
-            if (Flags.adaptiveHapticsEnabled()) {
-                waitForVibrationParamsIfRequired();
-            }
-            // Scale resolves the default amplitudes from the effect before scaling them.
-            mVibration.scaleEffects(mVibrationScaler);
-        } else {
-            mVibration.resolveEffects(mVibrationScaler.getDefaultVibrationAmplitude());
+        if (Flags.adaptiveHapticsEnabled()) {
+            waitForVibrationParamsIfRequired();
         }
+        // Scale resolves the default amplitudes from the effect before scaling them.
+        mVibration.scaleEffects(mVibrationScaler);
 
         mVibration.adaptToDevice(mDeviceAdapter);
         CombinedVibration.Sequential sequentialEffect = toSequential(mVibration.getEffectToPlay());
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 48c4a68..7610d7d 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -103,8 +103,7 @@
             new VibrationAttributes.Builder().build();
     private static final int ATTRIBUTES_ALL_BYPASS_FLAGS =
             VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
-                    | VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF
-                    | VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE;
+                    | VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
 
     /** Fixed large duration used to note repeating vibrations to {@link IBatteryStats}. */
     private static final long BATTERY_STATS_REPEATING_VIBRATION_DURATION = 5_000;
@@ -925,8 +924,7 @@
     private VibrationStepConductor createVibrationStepConductor(HalVibration vib) {
         CompletableFuture<Void> requestVibrationParamsFuture = null;
 
-        if (Flags.adaptiveHapticsEnabled() && !vib.callerInfo.attrs.isFlagSet(
-                VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)
+        if (Flags.adaptiveHapticsEnabled()
                 && mVibratorControlService.shouldRequestVibrationParams(
                 vib.callerInfo.attrs.getUsage())) {
             requestVibrationParamsFuture =
@@ -940,13 +938,8 @@
     }
 
     private Vibration.EndInfo startVibrationOnInputDevicesLocked(HalVibration vib) {
-        if (!vib.callerInfo.attrs.isFlagSet(
-                VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)) {
-            // Scale resolves the default amplitudes from the effect before scaling them.
-            vib.scaleEffects(mVibrationScaler);
-        } else {
-            vib.resolveEffects(mVibrationScaler.getDefaultVibrationAmplitude());
-        }
+        // Scale resolves the default amplitudes from the effect before scaling them.
+        vib.scaleEffects(mVibrationScaler);
         mInputDeviceDelegate.vibrateIfAvailable(vib.callerInfo, vib.getEffectToPlay());
 
         return new Vibration.EndInfo(Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index 3b99954..1994174 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -52,7 +52,7 @@
  * display change transition. In this case, we will queue all display updates until the current
  * transition's collection finishes and then apply them afterwards.
  */
-public class DeferredDisplayUpdater implements DisplayUpdater {
+class DeferredDisplayUpdater {
 
     /**
      * List of fields that could be deferred before applying to DisplayContent.
@@ -110,7 +110,7 @@
         continueScreenUnblocking();
     };
 
-    public DeferredDisplayUpdater(@NonNull DisplayContent displayContent) {
+    DeferredDisplayUpdater(@NonNull DisplayContent displayContent) {
         mDisplayContent = displayContent;
         mNonOverrideDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
     }
@@ -122,8 +122,7 @@
      *
      * @param finishCallback is called when all pending display updates are finished
      */
-    @Override
-    public void updateDisplayInfo(@NonNull Runnable finishCallback) {
+    void updateDisplayInfo(@NonNull Runnable finishCallback) {
         // Get the latest display parameters from the DisplayManager
         final DisplayInfo displayInfo = getCurrentDisplayInfo();
 
@@ -310,9 +309,11 @@
         return !Objects.equals(first.uniqueId, second.uniqueId);
     }
 
-    @Override
-    public void onDisplayContentDisplayPropertiesPostChanged(int previousRotation, int newRotation,
-            DisplayAreaInfo newDisplayAreaInfo) {
+    /**
+     * Called after physical display has changed and after DisplayContent applied new display
+     * properties.
+     */
+    void onDisplayContentDisplayPropertiesPostChanged() {
         // Unblock immediately in case there is no transition. This is unlikely to happen.
         if (mScreenUnblocker != null && !mDisplayContent.mTransitionController.inTransition()) {
             mScreenUnblocker.sendToTarget();
@@ -320,13 +321,16 @@
         }
     }
 
-    @Override
-    public void onDisplaySwitching(boolean switching) {
+    /**
+     * Called with {@code true} when physical display is going to switch. And {@code false} when
+     * the display is turned on or the device goes to sleep.
+     */
+    void onDisplaySwitching(boolean switching) {
         mShouldWaitForTransitionWhenScreenOn = switching;
     }
 
-    @Override
-    public boolean waitForTransition(@NonNull Message screenUnblocker) {
+    /** Returns {@code true} if the transition will control when to turn on the screen. */
+    boolean waitForTransition(@NonNull Message screenUnblocker) {
         if (!Flags.waitForTransitionOnDisplaySwitch()) return false;
         if (!mShouldWaitForTransitionWhenScreenOn) {
             return false;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 403c307..b31ae90 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -159,7 +159,6 @@
 import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields;
 import static com.android.server.wm.utils.RegionUtils.forEachRectReverse;
 import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
-import static com.android.window.flags.Flags.deferDisplayUpdates;
 import static com.android.window.flags.Flags.explicitRefreshRateHints;
 
 import android.annotation.IntDef;
@@ -478,7 +477,7 @@
     AppCompatCameraPolicy mAppCompatCameraPolicy;
 
     DisplayFrames mDisplayFrames;
-    final DisplayUpdater mDisplayUpdater;
+    final DeferredDisplayUpdater mDisplayUpdater;
 
     private boolean mInTouchMode;
 
@@ -623,7 +622,6 @@
     @VisibleForTesting
     final DeviceStateController mDeviceStateController;
     final Consumer<DeviceStateController.DeviceState> mDeviceStateConsumer;
-    final PhysicalDisplaySwitchTransitionLauncher mDisplaySwitchTransitionLauncher;
     final RemoteDisplayChangeController mRemoteDisplayChangeController;
 
     /** Windows added since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */
@@ -1140,11 +1138,7 @@
         mWallpaperController.resetLargestDisplay(display);
         display.getDisplayInfo(mDisplayInfo);
         display.getMetrics(mDisplayMetrics);
-        if (deferDisplayUpdates()) {
-            mDisplayUpdater = new DeferredDisplayUpdater(this);
-        } else {
-            mDisplayUpdater = new ImmediateDisplayUpdater(this);
-        }
+        mDisplayUpdater = new DeferredDisplayUpdater(this);
         mSystemGestureExclusionLimit = mWmService.mConstants.mSystemGestureExclusionLimitDp
                 * mDisplayMetrics.densityDpi / DENSITY_DEFAULT;
         isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
@@ -1168,8 +1162,6 @@
         mAppTransitionController = new AppTransitionController(mWmService, this);
         mTransitionController.registerLegacyListener(mFixedRotationTransitionListener);
         mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
-        mDisplaySwitchTransitionLauncher = new PhysicalDisplaySwitchTransitionLauncher(this,
-                mTransitionController);
         mRemoteDisplayChangeController = new RemoteDisplayChangeController(this);
 
         final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
@@ -1190,7 +1182,6 @@
 
         mDeviceStateConsumer =
                 (@NonNull DeviceStateController.DeviceState newFoldState) -> {
-                    mDisplaySwitchTransitionLauncher.foldStateChanged(newFoldState);
                     mDisplayRotation.foldStateChanged(newFoldState);
                 };
         mDeviceStateController.registerDeviceStateCallback(mDeviceStateConsumer,
@@ -3094,8 +3085,6 @@
                 // metrics are updated as rotation settings might depend on them
                 mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this,
                         /* includeRotationSettings */ false);
-                mDisplayUpdater.onDisplayContentDisplayPropertiesPreChanged(mDisplayId,
-                        mInitialDisplayWidth, mInitialDisplayHeight, newWidth, newHeight);
                 mDisplayRotation.physicalDisplayChanged();
                 mDisplayPolicy.physicalDisplayChanged();
             }
@@ -3130,8 +3119,7 @@
 
             if (physicalDisplayChanged) {
                 mDisplayPolicy.physicalDisplayUpdated();
-                mDisplayUpdater.onDisplayContentDisplayPropertiesPostChanged(currentRotation,
-                        getRotation(), getDisplayAreaInfo());
+                mDisplayUpdater.onDisplayContentDisplayPropertiesPostChanged();
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayUpdater.java b/services/core/java/com/android/server/wm/DisplayUpdater.java
deleted file mode 100644
index 918b180..0000000
--- a/services/core/java/com/android/server/wm/DisplayUpdater.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2023 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.wm;
-
-import android.annotation.NonNull;
-import android.os.Message;
-import android.view.Surface;
-import android.window.DisplayAreaInfo;
-
-/**
- * Interface for a helper class that manages updates of DisplayInfo coming from DisplayManager
- */
-interface DisplayUpdater {
-    /**
-     * Reads the latest display parameters from the display manager and returns them in a callback.
-     * If there are pending display updates, it will wait for them to finish first and only then it
-     * will call the callback with the latest display parameters.
-     *
-     * @param callback is called when all pending display updates are finished
-     */
-    void updateDisplayInfo(@NonNull Runnable callback);
-
-    /**
-     * Called when physical display has changed and before DisplayContent has applied new display
-     * properties
-     */
-    default void onDisplayContentDisplayPropertiesPreChanged(int displayId, int initialDisplayWidth,
-            int initialDisplayHeight, int newWidth, int newHeight) {
-    }
-
-    /**
-     * Called after physical display has changed and after DisplayContent applied new display
-     * properties
-     */
-    default void onDisplayContentDisplayPropertiesPostChanged(
-            @Surface.Rotation int previousRotation, @Surface.Rotation int newRotation,
-            @NonNull DisplayAreaInfo newDisplayAreaInfo) {
-    }
-
-    /**
-     * Called with {@code true} when physical display is going to switch. And {@code false} when
-     * the display is turned on or the device goes to sleep.
-     */
-    default void onDisplaySwitching(boolean switching) {
-    }
-
-    /** Returns {@code true} if the transition will control when to turn on the screen. */
-    default boolean waitForTransition(@NonNull Message screenUnBlocker) {
-        return false;
-    }
-}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index e0d69b0..4ec318b 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -16,9 +16,12 @@
 
 package com.android.server.wm;
 
+import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.WindowConfiguration;
+import android.companion.virtualdevice.flags.Flags;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -26,6 +29,7 @@
 import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.view.Display;
 import android.window.DisplayWindowPolicyController;
 
 import java.io.PrintWriter;
@@ -80,6 +84,9 @@
                 if (hasDisplayCategory(activities.get(i))) {
                     return false;
                 }
+                if (!launchAllowedByDisplayPolicy(activities.get(i))) {
+                    return false;
+                }
             }
             return true;
         }
@@ -95,7 +102,13 @@
         if (mDisplayWindowPolicyController == null) {
             // Missing controller means that this display has no categories for activity launch
             // restriction.
-            return !hasDisplayCategory(activityInfo);
+            if (hasDisplayCategory(activityInfo)) {
+                return false;
+            }
+            if (!launchAllowedByDisplayPolicy(activityInfo)) {
+                return false;
+            }
+            return true;
         }
         return mDisplayWindowPolicyController.canActivityBeLaunched(activityInfo, intent,
             windowingMode, launchingFromDisplayId, isNewTask);
@@ -112,6 +125,24 @@
         return false;
     }
 
+    private boolean launchAllowedByDisplayPolicy(ActivityInfo aInfo) {
+        if (!Flags.enforceRemoteDeviceOptOutOnAllVirtualDisplays()) {
+            return true;
+        }
+        int displayType = mDisplayContent.getDisplay().getType();
+        if (displayType != Display.TYPE_VIRTUAL && displayType != Display.TYPE_WIFI) {
+            return true;
+        }
+        if ((aInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
+            Slog.d(TAG,
+                    String.format("Checking activity launch on display %d, activity requires"
+                                    + " android:canDisplayOnRemoteDevices=true",
+                            mDisplayContent.mDisplayId));
+            return false;
+        }
+        return true;
+    }
+
     /**
      * @see DisplayWindowPolicyController#keepActivityOnWindowFlagsChanged(ActivityInfo, int, int)
      */
diff --git a/services/core/java/com/android/server/wm/ImmediateDisplayUpdater.java b/services/core/java/com/android/server/wm/ImmediateDisplayUpdater.java
deleted file mode 100644
index 4af9013..0000000
--- a/services/core/java/com/android/server/wm/ImmediateDisplayUpdater.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2023 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.wm;
-
-import android.annotation.NonNull;
-import android.view.DisplayInfo;
-import android.window.DisplayAreaInfo;
-
-/**
- * DisplayUpdater that immediately applies new DisplayInfo properties
- */
-public class ImmediateDisplayUpdater implements DisplayUpdater {
-
-    private final DisplayContent mDisplayContent;
-    private final DisplayInfo mDisplayInfo = new DisplayInfo();
-
-    public ImmediateDisplayUpdater(@NonNull DisplayContent displayContent) {
-        mDisplayContent = displayContent;
-        mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
-    }
-
-    @Override
-    public void updateDisplayInfo(Runnable callback) {
-        mDisplayContent.mWmService.mDisplayManagerInternal.getNonOverrideDisplayInfo(
-                mDisplayContent.mDisplayId, mDisplayInfo);
-        mDisplayContent.onDisplayInfoUpdated(mDisplayInfo);
-        callback.run();
-    }
-
-    @Override
-    public void onDisplayContentDisplayPropertiesPreChanged(int displayId, int initialDisplayWidth,
-            int initialDisplayHeight, int newWidth, int newHeight) {
-        mDisplayContent.mDisplaySwitchTransitionLauncher.requestDisplaySwitchTransitionIfNeeded(
-                displayId, initialDisplayWidth, initialDisplayHeight, newWidth, newHeight);
-    }
-
-    @Override
-    public void onDisplayContentDisplayPropertiesPostChanged(int previousRotation, int newRotation,
-            DisplayAreaInfo newDisplayAreaInfo) {
-        mDisplayContent.mDisplaySwitchTransitionLauncher.onDisplayUpdated(previousRotation,
-                newRotation,
-                newDisplayAreaInfo);
-    }
-}
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
deleted file mode 100644
index 3cf301c..0000000
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
-
-import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
-import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
-import static com.android.server.wm.DeviceStateController.DeviceState.FOLDED;
-import static com.android.server.wm.DeviceStateController.DeviceState.HALF_FOLDED;
-import static com.android.server.wm.DeviceStateController.DeviceState.OPEN;
-
-import android.animation.ValueAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Rect;
-import android.window.DisplayAreaInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.ProtoLog;
-import com.android.server.wm.DeviceStateController.DeviceState;
-
-public class PhysicalDisplaySwitchTransitionLauncher {
-
-    private final DisplayContent mDisplayContent;
-    private final ActivityTaskManagerService mAtmService;
-    private final Context mContext;
-    private final TransitionController mTransitionController;
-
-    /**
-     * If on a foldable device represents whether we need to show unfold animation when receiving
-     * a physical display switch event
-     */
-    private boolean mShouldRequestTransitionOnDisplaySwitch = false;
-    /**
-     * Current device state from {@link android.hardware.devicestate.DeviceStateManager}
-     */
-    private DeviceState mDeviceState = DeviceState.UNKNOWN;
-    private Transition mTransition;
-
-    public PhysicalDisplaySwitchTransitionLauncher(DisplayContent displayContent,
-            TransitionController transitionController) {
-        this(displayContent, displayContent.mWmService.mAtmService,
-                displayContent.mWmService.mContext, transitionController);
-    }
-
-    @VisibleForTesting
-    public PhysicalDisplaySwitchTransitionLauncher(DisplayContent displayContent,
-            ActivityTaskManagerService service, Context context,
-            TransitionController transitionController) {
-        mDisplayContent = displayContent;
-        mAtmService = service;
-        mContext = context;
-        mTransitionController = transitionController;
-    }
-
-    /**
-     * Called by the display manager just before it applied the device state, it is guaranteed
-     * that in case of physical display change the
-     * {@link PhysicalDisplaySwitchTransitionLauncher#requestDisplaySwitchTransitionIfNeeded}
-     * method will be invoked *after* this one.
-     */
-    void foldStateChanged(DeviceState newDeviceState) {
-        boolean isUnfolding = mDeviceState == FOLDED
-                && (newDeviceState == HALF_FOLDED || newDeviceState == OPEN);
-
-        if (isUnfolding) {
-            // Request transition only if we are unfolding the device
-            mShouldRequestTransitionOnDisplaySwitch = true;
-        } else if (newDeviceState != HALF_FOLDED && newDeviceState != OPEN) {
-            // Cancel the transition request in case if we are folding or switching to back
-            // to the rear display before the displays got switched
-            mShouldRequestTransitionOnDisplaySwitch = false;
-        }
-
-        mDeviceState = newDeviceState;
-    }
-
-    /**
-     * Requests to start a transition for the physical display switch
-     */
-    public void requestDisplaySwitchTransitionIfNeeded(int displayId, int oldDisplayWidth,
-            int oldDisplayHeight, int newDisplayWidth, int newDisplayHeight) {
-        if (!mShouldRequestTransitionOnDisplaySwitch) return;
-        if (!mTransitionController.isShellTransitionsEnabled()) return;
-        if (!mDisplayContent.getLastHasContent()) return;
-
-        boolean shouldRequestUnfoldTransition = mContext.getResources()
-                .getBoolean(config_unfoldTransitionEnabled) && ValueAnimator.areAnimatorsEnabled();
-
-        if (!shouldRequestUnfoldTransition) {
-            return;
-        }
-
-        mTransition = null;
-
-        if (mTransitionController.isCollecting()) {
-            // Add display container to the currently collecting transition
-            mTransition = mTransitionController.getCollectingTransition();
-            mTransition.collect(mDisplayContent);
-
-            // Make sure that transition is not ready until we finish the remote display change
-            mTransition.setReady(mDisplayContent, false);
-            mTransition.addFlag(TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH);
-
-            ProtoLog.d(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
-                    "Adding display switch to existing collecting transition");
-        } else {
-            final TransitionRequestInfo.DisplayChange displayChange =
-                    new TransitionRequestInfo.DisplayChange(displayId);
-
-            final Rect startAbsBounds = new Rect(0, 0, oldDisplayWidth, oldDisplayHeight);
-            displayChange.setStartAbsBounds(startAbsBounds);
-            final Rect endAbsBounds = new Rect(0, 0, newDisplayWidth, newDisplayHeight);
-            displayChange.setEndAbsBounds(endAbsBounds);
-            displayChange.setPhysicalDisplayChanged(true);
-
-            mTransition = mTransitionController.requestStartDisplayTransition(TRANSIT_CHANGE,
-                    0 /* flags */, mDisplayContent, null /* remoteTransition */, displayChange);
-            mTransition.collect(mDisplayContent);
-        }
-
-        if (mTransition != null) {
-            mAtmService.startPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
-        }
-
-        mShouldRequestTransitionOnDisplaySwitch = false;
-    }
-
-    /**
-     * Called when physical display is getting updated, this could happen e.g. on foldable
-     * devices when the physical underlying display is replaced.
-     *
-     * @param fromRotation rotation before the display change
-     * @param toRotation rotation after the display change
-     * @param newDisplayAreaInfo display area info after the display change
-     */
-    public void onDisplayUpdated(int fromRotation, int toRotation,
-            @NonNull DisplayAreaInfo newDisplayAreaInfo) {
-        if (mTransition == null) return;
-
-        final boolean started = mDisplayContent.mRemoteDisplayChangeController
-                .performRemoteDisplayChange(fromRotation, toRotation, newDisplayAreaInfo,
-                        this::continueDisplayUpdate);
-
-        if (!started) {
-            markTransitionAsReady();
-        }
-    }
-
-    private void continueDisplayUpdate(@Nullable WindowContainerTransaction transaction) {
-        if (mTransition == null) return;
-
-        if (transaction != null) {
-            mAtmService.mWindowOrganizerController.applyTransaction(transaction);
-        }
-
-        markTransitionAsReady();
-    }
-
-    private void markTransitionAsReady() {
-        if (mTransition == null) return;
-
-        mTransition.setAllReady();
-        mTransition = null;
-    }
-
-}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
index 901c036..4f75931 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
@@ -20,7 +20,7 @@
 import static android.os.VibrationAttributes.CATEGORY_UNKNOWN;
 import static android.os.VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
 import static android.os.VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
-import static android.os.VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE;
+import static android.os.VibrationAttributes.USAGE_IME_FEEDBACK;
 import static android.os.VibrationAttributes.USAGE_TOUCH;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
 import static android.os.VibrationEffect.Composition.PRIMITIVE_TICK;
@@ -346,7 +346,7 @@
     }
 
     @Test
-    public void testVibrationAttribute_keyboardCategoryOff_isIme_notUseKeyboardCategory() {
+    public void testVibrationAttribute_keyboardCategoryOff_isIme_useTouchUsage() {
         mSetFlagsRule.disableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
         HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
@@ -362,7 +362,7 @@
     }
 
     @Test
-    public void testVibrationAttribute_keyboardCategoryOn_notIme_notUseKeyboardCategory() {
+    public void testVibrationAttribute_keyboardCategoryOn_notIme_useTouchUsage() {
         mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
         HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
@@ -377,7 +377,7 @@
     }
 
     @Test
-    public void testVibrationAttribute_keyboardCategoryOn_isIme_useKeyboardCategory() {
+    public void testVibrationAttribute_keyboardCategoryOn_isIme_useImeFeedbackUsage() {
         mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
         HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
@@ -385,64 +385,14 @@
             VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
                     effectId, /* flags */ 0,
                     HapticFeedbackConstants.PRIVATE_FLAG_APPLY_INPUT_METHOD_SETTINGS);
-            assertWithMessage("Expected USAGE_TOUCH for effect " + effectId)
-                    .that(attrs.getUsage()).isEqualTo(USAGE_TOUCH);
+            assertWithMessage("Expected USAGE_IME_FEEDBACK for effect " + effectId)
+                    .that(attrs.getUsage()).isEqualTo(USAGE_IME_FEEDBACK);
             assertWithMessage("Expected CATEGORY_KEYBOARD for effect " + effectId)
                     .that(attrs.getCategory()).isEqualTo(CATEGORY_KEYBOARD);
         }
     }
 
     @Test
-    public void testVibrationAttribute_noFixAmplitude_notBypassIntensityScale() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
-        mockVibratorPrimitiveSupport(PRIMITIVE_CLICK, PRIMITIVE_TICK);
-        mockKeyboardVibrationFixedAmplitude(-1);
-        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
-
-        for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
-            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                    effectId, /* flags */ 0,
-                    HapticFeedbackConstants.PRIVATE_FLAG_APPLY_INPUT_METHOD_SETTINGS);
-            assertWithMessage("Expected no FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE for effect "
-                    + effectId)
-                    .that(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)).isFalse();
-        }
-    }
-
-    @Test
-    public void testVibrationAttribute_notIme_notBypassIntensityScale() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
-        mockVibratorPrimitiveSupport(PRIMITIVE_CLICK, PRIMITIVE_TICK);
-        mockKeyboardVibrationFixedAmplitude(KEYBOARD_VIBRATION_FIXED_AMPLITUDE);
-        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
-
-        for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
-            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                    effectId, /* flags */ 0, /* privFlags */ 0);
-            assertWithMessage("Expected no FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE for effect "
-                    + effectId)
-                    .that(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)).isFalse();
-        }
-    }
-
-    @Test
-    public void testVibrationAttribute_fixAmplitude_isIme_bypassIntensityScale() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED);
-        mockVibratorPrimitiveSupport(PRIMITIVE_CLICK, PRIMITIVE_TICK);
-        mockKeyboardVibrationFixedAmplitude(KEYBOARD_VIBRATION_FIXED_AMPLITUDE);
-        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
-
-        for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
-            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
-                    effectId, /* flags */ 0,
-                    HapticFeedbackConstants.PRIVATE_FLAG_APPLY_INPUT_METHOD_SETTINGS);
-            assertWithMessage("Expected FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE for effect "
-                    + effectId)
-                    .that(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)).isTrue();
-        }
-    }
-
-    @Test
     public void testIsRestricted_biometricConstants_returnsTrue() {
         HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations();
 
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
index 60d8964..8d4a6aa 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -23,6 +23,7 @@
 import static android.os.VibrationAttributes.USAGE_ALARM;
 import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
 import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK;
+import static android.os.VibrationAttributes.USAGE_IME_FEEDBACK;
 import static android.os.VibrationAttributes.USAGE_MEDIA;
 import static android.os.VibrationAttributes.USAGE_NOTIFICATION;
 import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION;
@@ -893,6 +894,22 @@
     }
 
     @Test
+    public void getCurrentIntensity_ImeFeedbackValueReflectsToKeyboardVibrationSettings() {
+        setDefaultIntensity(USAGE_IME_FEEDBACK, VIBRATION_INTENSITY_MEDIUM);
+        setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_HIGH);
+
+        setKeyboardVibrationSettingsSupported(false);
+        mVibrationSettings.update();
+        assertEquals(VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getCurrentIntensity(USAGE_IME_FEEDBACK));
+
+        setKeyboardVibrationSettingsSupported(true);
+        mVibrationSettings.update();
+        assertEquals(VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getCurrentIntensity(USAGE_IME_FEEDBACK));
+    }
+
+    @Test
     public void getFallbackEffect_returnsEffectsFromSettings() {
         assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_TICK));
         assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_TEXTURE_TICK));
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 bea6917..e411a17 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -154,6 +154,9 @@
     private static final VibrationAttributes RINGTONE_ATTRS =
             new VibrationAttributes.Builder().setUsage(
                     VibrationAttributes.USAGE_RINGTONE).build();
+    private static final VibrationAttributes IME_FEEDBACK_ATTRS =
+            new VibrationAttributes.Builder().setUsage(
+                    VibrationAttributes.USAGE_IME_FEEDBACK).build();
     private static final VibrationAttributes UNKNOWN_ATTRS =
             new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_UNKNOWN).build();
 
@@ -853,6 +856,7 @@
         vibrate(service, VibrationEffect.createOneShot(2000, 200),
                 new VibrationAttributes.Builder().setUsage(
                         VibrationAttributes.USAGE_UNKNOWN).build());
+        vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), IME_FEEDBACK_ATTRS);
 
         InOrder inOrderVerifier = inOrder(mAppOpsManagerMock);
         inOrderVerifier.verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
@@ -868,6 +872,8 @@
                 anyInt(), anyString());
         inOrderVerifier.verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
                 eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString());
+        inOrderVerifier.verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+                eq(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION), anyInt(), anyString());
     }
 
     @Test
@@ -1684,40 +1690,6 @@
     }
 
     @Test
-    public void vibrate_withBypassScaleFlag_ignoresIntensitySettingsAndResolvesAmplitude()
-            throws Exception {
-        // Permission needed for bypassing user settings
-        grantPermission(android.Manifest.permission.MODIFY_PHONE_STATE);
-
-        int defaultTouchIntensity =
-                mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_TOUCH);
-        // This will scale down touch vibrations.
-        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
-                defaultTouchIntensity > Vibrator.VIBRATION_INTENSITY_LOW
-                        ? defaultTouchIntensity - 1
-                        : defaultTouchIntensity);
-
-        int defaultAmplitude = mContextSpy.getResources().getInteger(
-                com.android.internal.R.integer.config_defaultVibrationAmplitude);
-
-        mockVibrators(1);
-        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
-        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
-        VibratorManagerService service = createSystemReadyService();
-
-        vibrateAndWaitUntilFinished(service,
-                VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE),
-                new VibrationAttributes.Builder()
-                        .setUsage(VibrationAttributes.USAGE_TOUCH)
-                        .setFlags(VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)
-                        .build());
-
-        assertEquals(1, fakeVibrator.getAllEffectSegments().size());
-
-        assertEquals(defaultAmplitude / 255f, fakeVibrator.getAmplitudes().get(0), 1e-5);
-    }
-
-    @Test
     @RequiresFlagsEnabled(android.os.vibrator.Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED)
     public void vibrate_withAdaptiveHaptics_appliesCorrectAdaptiveScales() throws Exception {
         // Keep user settings the same as device default so only adaptive scale is applied.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ff1c6c8..d0080d2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -102,6 +102,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.Pair;
 import android.util.Size;
+import android.view.Display;
 import android.view.Gravity;
 import android.view.RemoteAnimationAdapter;
 import android.window.TaskFragmentOrganizerToken;
@@ -941,6 +942,91 @@
                 notNull() /* options */);
     }
 
+
+    /**
+     * This test ensures that activity launch on a secondary display is allowed if the activity did
+     * not opt out from showing on remote devices.
+     */
+    @Test
+    public void testStartActivityOnVirtualDisplay() {
+        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+                false /* mockGetRootTask */);
+        starter.mRequest.activityInfo.flags |= ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+
+        // Create a virtual display at bottom.
+        final TestDisplayContent secondaryDisplay =
+                new TestDisplayContent.Builder(mAtm, 1000, 1500)
+                        .setType(Display.TYPE_VIRTUAL)
+                        .setPosition(POSITION_BOTTOM).build();
+        final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
+        final Task stack = secondaryTaskContainer.createRootTask(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+        // Create an activity record on the top of secondary display.
+        final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
+
+        // Put an activity on default display as the top focused activity.
+        new ActivityBuilder(mAtm).setCreateTask(true).build();
+
+        // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
+        // on secondary display.
+        final ActivityOptions options = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(secondaryDisplay.mDisplayId);
+        final int result = starter.setReason("testStartActivityOnVirtualDisplay")
+                .setIntent(topActivityOnSecondaryDisplay.intent)
+                .setActivityOptions(options.toBundle())
+                .execute();
+
+        // Ensure result is delivering intent to top.
+        assertEquals(START_DELIVERED_TO_TOP, result);
+
+        // Ensure secondary display only creates one stack.
+        verify(secondaryTaskContainer, times(1)).createRootTask(anyInt(), anyInt(), anyBoolean());
+    }
+
+    /**
+     * This test ensures that activity launch on a secondary display is disallowed if the activity
+     * opted out from showing on remote devices.
+     */
+    @EnableFlags(android.companion.virtualdevice.flags.Flags
+            .FLAG_ENFORCE_REMOTE_DEVICE_OPT_OUT_ON_ALL_VIRTUAL_DISPLAYS)
+    @Test
+    public void testStartOptedOutActivityOnVirtualDisplay() {
+        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+                false /* mockGetRootTask */);
+        starter.mRequest.activityInfo.flags &= ~ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+
+        // Create a virtual display at bottom.
+        final TestDisplayContent secondaryDisplay =
+                new TestDisplayContent.Builder(mAtm, 1000, 1500)
+                        .setType(Display.TYPE_VIRTUAL)
+                        .setPosition(POSITION_BOTTOM).build();
+        final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
+        final Task stack = secondaryTaskContainer.createRootTask(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+        // Create an activity record on the top of secondary display.
+        final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
+
+        // Put an activity on default display as the top focused activity.
+        new ActivityBuilder(mAtm).setCreateTask(true).build();
+
+        // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
+        // on secondary display.
+        final ActivityOptions options = ActivityOptions.makeBasic()
+                .setLaunchDisplayId(secondaryDisplay.mDisplayId);
+        final int result = starter.setReason("testStartOptedOutActivityOnVirtualDisplay")
+                .setIntent(topActivityOnSecondaryDisplay.intent)
+                .setActivityOptions(options.toBundle())
+                .execute();
+
+        // Ensure result is canceled.
+        assertEquals(START_CANCELED, result);
+
+        // Ensure secondary display only creates one stack.
+        verify(secondaryTaskContainer, times(1)).createRootTask(anyInt(), anyInt(), anyBoolean());
+    }
+
     @Test
     public void testWasVisibleInRestartAttempt() {
         final ActivityStarter starter = prepareStarter(
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java
index 57118f2..f843386 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java
@@ -63,11 +63,6 @@
 
     private final Message mScreenUnblocker = mock(Message.class);
 
-    @Override
-    protected void onBeforeSystemServicesCreated() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_DEFER_DISPLAY_UPDATES);
-    }
-
     @Before
     public void before() {
         doReturn(true).when(mDisplayContent).getLastHasContent();
diff --git a/services/tests/wmtests/src/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncherTest.java b/services/tests/wmtests/src/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncherTest.java
deleted file mode 100644
index 78509db..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncherTest.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2023 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.wm;
-
-import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
-import static com.android.server.wm.DeviceStateController.DeviceState.REAR;
-import static com.android.server.wm.DeviceStateController.DeviceState.FOLDED;
-import static com.android.server.wm.DeviceStateController.DeviceState.HALF_FOLDED;
-import static com.android.server.wm.DeviceStateController.DeviceState.OPEN;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.when;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for the {@link WindowToken} class.
- *
- * Build/Install/Run:
- * atest WmTests:PhysicalDisplaySwitchTransitionLauncherTest
- */
-@SmallTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class PhysicalDisplaySwitchTransitionLauncherTest extends WindowTestsBase {
-
-    @Mock
-    Context mContext;
-    @Mock
-    Resources mResources;
-    @Mock
-    BLASTSyncEngine mSyncEngine;
-
-    WindowTestsBase.TestTransitionPlayer mPlayer;
-    TransitionController mTransitionController;
-    DisplayContent mDisplayContent;
-
-    private PhysicalDisplaySwitchTransitionLauncher mTarget;
-    private float mOriginalAnimationScale;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mTransitionController = new WindowTestsBase.TestTransitionController(mAtm);
-        mTransitionController.setSyncEngine(mSyncEngine);
-        mPlayer = new WindowTestsBase.TestTransitionPlayer(
-                mTransitionController, mAtm.mWindowOrganizerController);
-        when(mContext.getResources()).thenReturn(mResources);
-        mDisplayContent = new TestDisplayContent.Builder(mAtm, 100, 150).build();
-        mTarget = new PhysicalDisplaySwitchTransitionLauncher(mDisplayContent, mAtm, mContext,
-                mTransitionController);
-        mOriginalAnimationScale = ValueAnimator.getDurationScale();
-    }
-
-    @After
-    public void after() {
-        ValueAnimator.setDurationScale(mOriginalAnimationScale);
-    }
-
-    @Test
-    public void testDisplaySwitchAfterUnfoldToOpen_animationsEnabled_requestsTransition() {
-        givenAllAnimationsEnabled();
-        mTarget.foldStateChanged(FOLDED);
-
-        mTarget.foldStateChanged(OPEN);
-        final Rect origBounds = new Rect();
-        mDisplayContent.getBounds(origBounds);
-        origBounds.offsetTo(0, 0);
-        mTarget.requestDisplaySwitchTransitionIfNeeded(
-                mDisplayContent.getDisplayId(),
-                origBounds.width(),
-                origBounds.height(),
-                /* newDisplayWidth= */ 200,
-                /* newDisplayHeight= */ 250
-        );
-
-        assertNotNull(mPlayer.mLastRequest);
-        assertEquals(mDisplayContent.getDisplayId(),
-                mPlayer.mLastRequest.getDisplayChange().getDisplayId());
-        assertEquals(origBounds, mPlayer.mLastRequest.getDisplayChange().getStartAbsBounds());
-        assertEquals(new Rect(0, 0, 200, 250),
-                mPlayer.mLastRequest.getDisplayChange().getEndAbsBounds());
-    }
-
-    @Test
-    public void testDisplaySwitchAfterFolding_animationEnabled_doesNotRequestTransition() {
-        givenAllAnimationsEnabled();
-        mTarget.foldStateChanged(OPEN);
-
-        mTarget.foldStateChanged(FOLDED);
-        requestDisplaySwitch();
-
-        assertTransitionNotRequested();
-    }
-
-    @Test
-    public void testDisplaySwitchAfterUnfoldingToHalf_animationEnabled_requestsTransition() {
-        givenAllAnimationsEnabled();
-        mTarget.foldStateChanged(FOLDED);
-
-        mTarget.foldStateChanged(HALF_FOLDED);
-        requestDisplaySwitch();
-
-        assertTransitionRequested();
-    }
-
-    @Test
-    public void testDisplaySwitchSecondTimeAfterUnfolding_animationEnabled_noTransition() {
-        givenAllAnimationsEnabled();
-        mTarget.foldStateChanged(FOLDED);
-        mTarget.foldStateChanged(OPEN);
-        requestDisplaySwitch();
-        mPlayer.mLastRequest = null;
-
-        requestDisplaySwitch();
-
-        assertTransitionNotRequested();
-    }
-
-
-    @Test
-    public void testDisplaySwitchAfterGoingToRearAndBack_animationEnabled_noTransition() {
-        givenAllAnimationsEnabled();
-        mTarget.foldStateChanged(OPEN);
-
-        mTarget.foldStateChanged(REAR);
-        mTarget.foldStateChanged(OPEN);
-        requestDisplaySwitch();
-
-        assertTransitionNotRequested();
-    }
-
-    @Test
-    public void testDisplaySwitchAfterUnfoldingAndFolding_animationEnabled_noTransition() {
-        givenAllAnimationsEnabled();
-        mTarget.foldStateChanged(FOLDED);
-        mTarget.foldStateChanged(OPEN);
-        // No request display switch event (simulate very fast fold after unfold, even before
-        // the displays switched)
-        mTarget.foldStateChanged(FOLDED);
-
-        requestDisplaySwitch();
-
-        assertTransitionNotRequested();
-    }
-
-    @Test
-    public void testDisplaySwitch_whenShellTransitionsNotEnabled_noTransition() {
-        givenAllAnimationsEnabled();
-        givenShellTransitionsEnabled(false);
-        mTarget.foldStateChanged(FOLDED);
-
-        mTarget.foldStateChanged(OPEN);
-        requestDisplaySwitch();
-
-        assertTransitionNotRequested();
-    }
-
-    @Test
-    public void testDisplaySwitch_whenAnimationsDisabled_noTransition() {
-        givenAllAnimationsEnabled();
-        givenAnimationsEnabled(false);
-        mTarget.foldStateChanged(FOLDED);
-
-        mTarget.foldStateChanged(OPEN);
-        requestDisplaySwitch();
-
-        assertTransitionNotRequested();
-    }
-
-    @Test
-    public void testDisplaySwitch_whenUnfoldAnimationDisabled_noTransition() {
-        givenAllAnimationsEnabled();
-        givenUnfoldTransitionEnabled(false);
-        mTarget.foldStateChanged(FOLDED);
-
-        mTarget.foldStateChanged(OPEN);
-        requestDisplaySwitch();
-
-        assertTransitionNotRequested();
-    }
-
-    @Test
-    public void testDisplaySwitchAfterUnfolding_otherCollectingTransition_collectsDisplaySwitch() {
-        givenAllAnimationsEnabled();
-        mTarget.foldStateChanged(FOLDED);
-
-        mTarget.foldStateChanged(OPEN);
-        requestDisplaySwitch();
-
-        // Collects to the current transition
-        assertTrue(mTransitionController.getCollectingTransition().mParticipants.contains(
-                mDisplayContent));
-    }
-
-
-    @Test
-    public void testDisplaySwitch_whenNoContentInDisplayContent_noTransition() {
-        givenAllAnimationsEnabled();
-        givenDisplayContentHasContent(false);
-        mTarget.foldStateChanged(FOLDED);
-
-        mTarget.foldStateChanged(OPEN);
-        requestDisplaySwitch();
-
-        assertTransitionNotRequested();
-    }
-
-    private void assertTransitionRequested() {
-        assertNotNull(mPlayer.mLastRequest);
-    }
-
-    private void assertTransitionNotRequested() {
-        assertNull(mPlayer.mLastRequest);
-    }
-
-    private void requestDisplaySwitch() {
-        mTarget.requestDisplaySwitchTransitionIfNeeded(
-                mDisplayContent.getDisplayId(),
-                mDisplayContent.getBounds().width(),
-                mDisplayContent.getBounds().height(),
-                /* newDisplayWidth= */ 200,
-                /* newDisplayHeight= */ 250
-        );
-    }
-
-    private void givenAllAnimationsEnabled() {
-        givenAnimationsEnabled(true);
-        givenUnfoldTransitionEnabled(true);
-        givenShellTransitionsEnabled(true);
-        givenDisplayContentHasContent(true);
-    }
-
-    private void givenUnfoldTransitionEnabled(boolean enabled) {
-        when(mResources.getBoolean(config_unfoldTransitionEnabled)).thenReturn(enabled);
-    }
-
-    private void givenAnimationsEnabled(boolean enabled) {
-        ValueAnimator.setDurationScale(enabled ? 1.0f : 0.0f);
-    }
-
-    private void givenShellTransitionsEnabled(boolean enabled) {
-        if (enabled) {
-            mTransitionController.registerTransitionPlayer(mPlayer, null /* proc */);
-        } else {
-            mTransitionController.unregisterTransitionPlayer(mPlayer);
-        }
-    }
-
-    private void givenDisplayContentHasContent(boolean hasContent) {
-        when(mDisplayContent.getLastHasContent()).thenReturn(hasContent);
-    }
-}