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);
- }
-}