Merge changes from topic "predback-qs-dialog" into tm-qpr-dev am: 1b5fb5d809
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20552932 Change-Id: I8e8d0b6af5ee18fc997f0b1adef0d435e027ee4f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
package com.android.systemui.animation
|
||||||
|
|
||||||
|
interface AnimationFeatureFlags {
|
||||||
|
val isPredictiveBackQsDialogAnim: Boolean
|
||||||
|
get() = false
|
||||||
|
}
|
||||||
@@ -33,8 +33,13 @@ import android.view.WindowInsets
|
|||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
|
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
import android.window.OnBackInvokedDispatcher
|
||||||
import com.android.internal.jank.InteractionJankMonitor
|
import com.android.internal.jank.InteractionJankMonitor
|
||||||
import com.android.internal.jank.InteractionJankMonitor.CujType
|
import com.android.internal.jank.InteractionJankMonitor.CujType
|
||||||
|
import com.android.systemui.animation.back.BackAnimationSpec
|
||||||
|
import com.android.systemui.animation.back.applyTo
|
||||||
|
import com.android.systemui.animation.back.floatingSystemSurfacesForSysUi
|
||||||
|
import com.android.systemui.animation.back.onBackAnimationCallbackFrom
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
private const val TAG = "DialogLaunchAnimator"
|
private const val TAG = "DialogLaunchAnimator"
|
||||||
@@ -55,8 +60,9 @@ class DialogLaunchAnimator
|
|||||||
constructor(
|
constructor(
|
||||||
private val callback: Callback,
|
private val callback: Callback,
|
||||||
private val interactionJankMonitor: InteractionJankMonitor,
|
private val interactionJankMonitor: InteractionJankMonitor,
|
||||||
|
private val featureFlags: AnimationFeatureFlags,
|
||||||
private val launchAnimator: LaunchAnimator = LaunchAnimator(TIMINGS, INTERPOLATORS),
|
private val launchAnimator: LaunchAnimator = LaunchAnimator(TIMINGS, INTERPOLATORS),
|
||||||
private val isForTesting: Boolean = false
|
private val isForTesting: Boolean = false,
|
||||||
) {
|
) {
|
||||||
private companion object {
|
private companion object {
|
||||||
private val TIMINGS = ActivityLaunchAnimator.TIMINGS
|
private val TIMINGS = ActivityLaunchAnimator.TIMINGS
|
||||||
@@ -273,15 +279,16 @@ constructor(
|
|||||||
|
|
||||||
val animatedDialog =
|
val animatedDialog =
|
||||||
AnimatedDialog(
|
AnimatedDialog(
|
||||||
launchAnimator,
|
launchAnimator = launchAnimator,
|
||||||
callback,
|
callback = callback,
|
||||||
interactionJankMonitor,
|
interactionJankMonitor = interactionJankMonitor,
|
||||||
controller,
|
controller = controller,
|
||||||
onDialogDismissed = { openedDialogs.remove(it) },
|
onDialogDismissed = { openedDialogs.remove(it) },
|
||||||
dialog = dialog,
|
dialog = dialog,
|
||||||
animateBackgroundBoundsChange,
|
animateBackgroundBoundsChange = animateBackgroundBoundsChange,
|
||||||
animatedParent,
|
parentAnimatedDialog = animatedParent,
|
||||||
isForTesting,
|
forceDisableSynchronization = isForTesting,
|
||||||
|
featureFlags = featureFlags,
|
||||||
)
|
)
|
||||||
|
|
||||||
openedDialogs.add(animatedDialog)
|
openedDialogs.add(animatedDialog)
|
||||||
@@ -517,6 +524,7 @@ private class AnimatedDialog(
|
|||||||
* Whether synchronization should be disabled, which can be useful if we are running in a test.
|
* Whether synchronization should be disabled, which can be useful if we are running in a test.
|
||||||
*/
|
*/
|
||||||
private val forceDisableSynchronization: Boolean,
|
private val forceDisableSynchronization: Boolean,
|
||||||
|
private val featureFlags: AnimationFeatureFlags,
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* The DecorView of this dialog window.
|
* The DecorView of this dialog window.
|
||||||
@@ -778,12 +786,45 @@ private class AnimatedDialog(
|
|||||||
// the dialog.
|
// the dialog.
|
||||||
dialog.setDismissOverride(this::onDialogDismissed)
|
dialog.setDismissOverride(this::onDialogDismissed)
|
||||||
|
|
||||||
|
if (featureFlags.isPredictiveBackQsDialogAnim) {
|
||||||
|
// TODO(b/265923095) Improve animations for QS dialogs on configuration change
|
||||||
|
registerOnBackInvokedCallback(targetView = dialogContentWithBackground)
|
||||||
|
}
|
||||||
|
|
||||||
// Show the dialog.
|
// Show the dialog.
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|
||||||
moveSourceDrawingToDialog()
|
moveSourceDrawingToDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun registerOnBackInvokedCallback(targetView: View) {
|
||||||
|
val metrics = targetView.resources.displayMetrics
|
||||||
|
|
||||||
|
val onBackAnimationCallback =
|
||||||
|
onBackAnimationCallbackFrom(
|
||||||
|
backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi(metrics),
|
||||||
|
displayMetrics = metrics, // TODO(b/265060720): We could remove this
|
||||||
|
onBackProgressed = { backTransformation -> backTransformation.applyTo(targetView) },
|
||||||
|
onBackInvoked = { dialog.dismiss() },
|
||||||
|
)
|
||||||
|
|
||||||
|
val dispatcher = dialog.onBackInvokedDispatcher
|
||||||
|
targetView.addOnAttachStateChangeListener(
|
||||||
|
object : View.OnAttachStateChangeListener {
|
||||||
|
override fun onViewAttachedToWindow(v: View) {
|
||||||
|
dispatcher.registerOnBackInvokedCallback(
|
||||||
|
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
|
||||||
|
onBackAnimationCallback
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewDetachedFromWindow(v: View) {
|
||||||
|
targetView.removeOnAttachStateChangeListener(this)
|
||||||
|
dispatcher.unregisterOnBackInvokedCallback(onBackAnimationCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun moveSourceDrawingToDialog() {
|
private fun moveSourceDrawingToDialog() {
|
||||||
if (decorView.viewRootImpl == null) {
|
if (decorView.viewRootImpl == null) {
|
||||||
// Make sure that we have access to the dialog view root to move the drawing to the
|
// Make sure that we have access to the dialog view root to move the drawing to the
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.animation.back
|
||||||
|
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.view.animation.Interpolator
|
||||||
|
import android.window.BackEvent
|
||||||
|
import com.android.systemui.animation.Interpolators
|
||||||
|
import com.android.systemui.util.dpToPx
|
||||||
|
|
||||||
|
/** Used to convert [BackEvent] into a [BackTransformation]. */
|
||||||
|
fun interface BackAnimationSpec {
|
||||||
|
|
||||||
|
/** Computes transformation based on a [backEvent] and sets it to [result]. */
|
||||||
|
fun getBackTransformation(
|
||||||
|
backEvent: BackEvent,
|
||||||
|
progressY: Float, // TODO(b/265060720): Remove progressY. Could be retrieved from backEvent
|
||||||
|
result: BackTransformation,
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a [BackAnimationSpec] from [displayMetrics] and design specs. */
|
||||||
|
fun BackAnimationSpec.Companion.createFloatingSurfaceAnimationSpec(
|
||||||
|
displayMetrics: DisplayMetrics,
|
||||||
|
maxMarginXdp: Float,
|
||||||
|
maxMarginYdp: Float,
|
||||||
|
minScale: Float,
|
||||||
|
translateXEasing: Interpolator = Interpolators.STANDARD_DECELERATE,
|
||||||
|
translateYEasing: Interpolator = Interpolators.LINEAR,
|
||||||
|
scaleEasing: Interpolator = Interpolators.STANDARD_DECELERATE,
|
||||||
|
): BackAnimationSpec {
|
||||||
|
val screenWidthPx = displayMetrics.widthPixels
|
||||||
|
val screenHeightPx = displayMetrics.heightPixels
|
||||||
|
|
||||||
|
val maxMarginXPx = maxMarginXdp.dpToPx(displayMetrics)
|
||||||
|
val maxMarginYPx = maxMarginYdp.dpToPx(displayMetrics)
|
||||||
|
val maxTranslationXByScale = (screenWidthPx - screenWidthPx * minScale) / 2
|
||||||
|
val maxTranslationX = maxTranslationXByScale - maxMarginXPx
|
||||||
|
val maxTranslationYByScale = (screenHeightPx - screenHeightPx * minScale) / 2
|
||||||
|
val maxTranslationY = maxTranslationYByScale - maxMarginYPx
|
||||||
|
val minScaleReversed = 1f - minScale
|
||||||
|
|
||||||
|
return BackAnimationSpec { backEvent, progressY, result ->
|
||||||
|
val direction = if (backEvent.swipeEdge == BackEvent.EDGE_LEFT) 1 else -1
|
||||||
|
val progressX = backEvent.progress
|
||||||
|
|
||||||
|
val ratioTranslateX = translateXEasing.getInterpolation(progressX)
|
||||||
|
val ratioTranslateY = translateYEasing.getInterpolation(progressY)
|
||||||
|
val ratioScale = scaleEasing.getInterpolation(progressX)
|
||||||
|
|
||||||
|
result.apply {
|
||||||
|
translateX = ratioTranslateX * direction * maxTranslationX
|
||||||
|
translateY = ratioTranslateY * maxTranslationY
|
||||||
|
scale = 1f - (ratioScale * minScaleReversed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.animation.back
|
||||||
|
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SysUI transitions - Dismiss app (ST1) Return to launching surface or place of origin
|
||||||
|
* https://carbon.googleplex.com/predictive-back-for-apps/pages/st-1-dismiss-app
|
||||||
|
*/
|
||||||
|
fun BackAnimationSpec.Companion.dismissAppForSysUi(
|
||||||
|
displayMetrics: DisplayMetrics,
|
||||||
|
): BackAnimationSpec =
|
||||||
|
BackAnimationSpec.createFloatingSurfaceAnimationSpec(
|
||||||
|
displayMetrics = displayMetrics,
|
||||||
|
maxMarginXdp = 8f,
|
||||||
|
maxMarginYdp = 8f,
|
||||||
|
minScale = 0.8f,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SysUI transitions - Cross task (ST2) Return to previous task/app, keeping the current one open
|
||||||
|
* https://carbon.googleplex.com/predictive-back-for-apps/pages/st-2-cross-task
|
||||||
|
*/
|
||||||
|
fun BackAnimationSpec.Companion.crossTaskForSysUi(
|
||||||
|
displayMetrics: DisplayMetrics,
|
||||||
|
): BackAnimationSpec =
|
||||||
|
BackAnimationSpec.createFloatingSurfaceAnimationSpec(
|
||||||
|
displayMetrics = displayMetrics,
|
||||||
|
maxMarginXdp = 8f,
|
||||||
|
maxMarginYdp = 8f,
|
||||||
|
minScale = 0.8f,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SysUI transitions - Inner area dismiss (ST3) Dismiss non-detachable surface
|
||||||
|
* https://carbon.googleplex.com/predictive-back-for-apps/pages/st-3-inner-area-dismiss
|
||||||
|
*/
|
||||||
|
fun BackAnimationSpec.Companion.innerAreaDismissForSysUi(
|
||||||
|
displayMetrics: DisplayMetrics,
|
||||||
|
): BackAnimationSpec =
|
||||||
|
BackAnimationSpec.createFloatingSurfaceAnimationSpec(
|
||||||
|
displayMetrics = displayMetrics,
|
||||||
|
maxMarginXdp = 0f,
|
||||||
|
maxMarginYdp = 0f,
|
||||||
|
minScale = 0.9f,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SysUI transitions - Floating system surfaces (ST4)
|
||||||
|
* https://carbon.googleplex.com/predictive-back-for-apps/pages/st-4-floating-system-surfaces
|
||||||
|
*/
|
||||||
|
fun BackAnimationSpec.Companion.floatingSystemSurfacesForSysUi(
|
||||||
|
displayMetrics: DisplayMetrics,
|
||||||
|
): BackAnimationSpec =
|
||||||
|
BackAnimationSpec.createFloatingSurfaceAnimationSpec(
|
||||||
|
displayMetrics = displayMetrics,
|
||||||
|
maxMarginXdp = 8f,
|
||||||
|
maxMarginYdp = 8f,
|
||||||
|
minScale = 0.8f,
|
||||||
|
)
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.animation.back
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object that represents the transformation to apply to the target. The properties of this
|
||||||
|
* object are mutable for performance reasons (avoid recreating this object)
|
||||||
|
*/
|
||||||
|
data class BackTransformation(
|
||||||
|
var translateX: Float = Float.NaN,
|
||||||
|
var translateY: Float = Float.NaN,
|
||||||
|
var scale: Float = Float.NaN,
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Apply the transformation to the [targetView] */
|
||||||
|
fun BackTransformation.applyTo(targetView: View) {
|
||||||
|
if (translateX.isFinite()) targetView.translationX = translateX
|
||||||
|
if (translateY.isFinite()) targetView.translationY = translateY
|
||||||
|
if (scale.isFinite()) {
|
||||||
|
targetView.scaleX = scale
|
||||||
|
targetView.scaleY = scale
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.animation.back
|
||||||
|
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.window.BackEvent
|
||||||
|
import android.window.OnBackAnimationCallback
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an [OnBackAnimationCallback] given a [backAnimationSpec]. [onBackProgressed] will be
|
||||||
|
* called on each update passing the current [BackTransformation].
|
||||||
|
*
|
||||||
|
* Optionally, you can specify [onBackStarted], [onBackInvoked], and [onBackCancelled] callbacks.
|
||||||
|
*/
|
||||||
|
fun onBackAnimationCallbackFrom(
|
||||||
|
backAnimationSpec: BackAnimationSpec,
|
||||||
|
displayMetrics: DisplayMetrics, // TODO(b/265060720): We could remove this
|
||||||
|
onBackProgressed: (BackTransformation) -> Unit,
|
||||||
|
onBackStarted: (BackEvent) -> Unit = {},
|
||||||
|
onBackInvoked: () -> Unit = {},
|
||||||
|
onBackCancelled: () -> Unit = {},
|
||||||
|
): OnBackAnimationCallback {
|
||||||
|
return object : OnBackAnimationCallback {
|
||||||
|
private var initialY = 0f
|
||||||
|
private val lastTransformation = BackTransformation()
|
||||||
|
|
||||||
|
override fun onBackStarted(backEvent: BackEvent) {
|
||||||
|
initialY = backEvent.touchY
|
||||||
|
onBackStarted(backEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackProgressed(backEvent: BackEvent) {
|
||||||
|
val progressY = (backEvent.touchY - initialY) / displayMetrics.heightPixels
|
||||||
|
|
||||||
|
backAnimationSpec.getBackTransformation(
|
||||||
|
backEvent = backEvent,
|
||||||
|
progressY = progressY,
|
||||||
|
result = lastTransformation,
|
||||||
|
)
|
||||||
|
|
||||||
|
onBackProgressed(lastTransformation)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackInvoked() {
|
||||||
|
onBackInvoked()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackCancelled() {
|
||||||
|
onBackCancelled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.TypedValue
|
||||||
|
|
||||||
|
/** Convert [this] number of dps to device pixels. */
|
||||||
|
fun Number.dpToPx(context: Context): Float = dpToPx(resources = context.resources)
|
||||||
|
|
||||||
|
/** Convert [this] number of dps to device pixels. */
|
||||||
|
fun Number.dpToPx(resources: Resources): Float = dpToPx(displayMetrics = resources.displayMetrics)
|
||||||
|
|
||||||
|
/** Convert [this] number of dps to device pixels. */
|
||||||
|
fun Number.dpToPx(displayMetrics: DisplayMetrics): Float =
|
||||||
|
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, toFloat(), displayMetrics)
|
||||||
@@ -65,8 +65,7 @@ object Flags {
|
|||||||
val FSI_ON_DND_UPDATE = unreleasedFlag(259130119, "fsi_on_dnd_update", teamfood = true)
|
val FSI_ON_DND_UPDATE = unreleasedFlag(259130119, "fsi_on_dnd_update", teamfood = true)
|
||||||
|
|
||||||
// TODO(b/265804648): Tracking Bug
|
// TODO(b/265804648): Tracking Bug
|
||||||
@JvmField
|
@JvmField val DISABLE_FSI = unreleasedFlag(265804648, "disable_fsi")
|
||||||
val DISABLE_FSI = unreleasedFlag(265804648, "disable_fsi")
|
|
||||||
|
|
||||||
// TODO(b/254512538): Tracking Bug
|
// TODO(b/254512538): Tracking Bug
|
||||||
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply", teamfood = true)
|
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply", teamfood = true)
|
||||||
@@ -483,6 +482,11 @@ object Flags {
|
|||||||
val WM_SHADE_ANIMATE_BACK_GESTURE =
|
val WM_SHADE_ANIMATE_BACK_GESTURE =
|
||||||
unreleasedFlag(1208, "persist.wm.debug.shade_animate_back_gesture", teamfood = true)
|
unreleasedFlag(1208, "persist.wm.debug.shade_animate_back_gesture", teamfood = true)
|
||||||
|
|
||||||
|
// TODO(b/265639042): Tracking Bug
|
||||||
|
@JvmField
|
||||||
|
val WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM =
|
||||||
|
unreleasedFlag(1209, "persist.wm.debug.predictive_back_qs_dialog_anim", teamfood = true)
|
||||||
|
|
||||||
// 1300 - screenshots
|
// 1300 - screenshots
|
||||||
// TODO(b/254513155): Tracking Bug
|
// TODO(b/254513155): Tracking Bug
|
||||||
@JvmField
|
@JvmField
|
||||||
@@ -573,6 +577,5 @@ object Flags {
|
|||||||
|
|
||||||
// 2600 - keyboard shortcut
|
// 2600 - keyboard shortcut
|
||||||
// TODO(b/259352579): Tracking Bug
|
// TODO(b/259352579): Tracking Bug
|
||||||
@JvmField
|
@JvmField val SHORTCUT_LIST_SEARCH_LAYOUT = unreleasedFlag(2600, "shortcut_list_search_layout")
|
||||||
val SHORTCUT_LIST_SEARCH_LAYOUT = unreleasedFlag(2600, "shortcut_list_search_layout")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,12 +25,15 @@ import android.util.Log;
|
|||||||
import com.android.internal.jank.InteractionJankMonitor;
|
import com.android.internal.jank.InteractionJankMonitor;
|
||||||
import com.android.internal.statusbar.IStatusBarService;
|
import com.android.internal.statusbar.IStatusBarService;
|
||||||
import com.android.systemui.animation.ActivityLaunchAnimator;
|
import com.android.systemui.animation.ActivityLaunchAnimator;
|
||||||
|
import com.android.systemui.animation.AnimationFeatureFlags;
|
||||||
import com.android.systemui.animation.DialogLaunchAnimator;
|
import com.android.systemui.animation.DialogLaunchAnimator;
|
||||||
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
import com.android.systemui.colorextraction.SysuiColorExtractor;
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.dump.DumpHandler;
|
import com.android.systemui.dump.DumpHandler;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
|
import com.android.systemui.flags.Flags;
|
||||||
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
|
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
|
||||||
import com.android.systemui.media.controls.pipeline.MediaDataManager;
|
import com.android.systemui.media.controls.pipeline.MediaDataManager;
|
||||||
import com.android.systemui.plugins.ActivityStarter;
|
import com.android.systemui.plugins.ActivityStarter;
|
||||||
@@ -281,7 +284,8 @@ public interface CentralSurfacesDependenciesModule {
|
|||||||
static DialogLaunchAnimator provideDialogLaunchAnimator(IDreamManager dreamManager,
|
static DialogLaunchAnimator provideDialogLaunchAnimator(IDreamManager dreamManager,
|
||||||
KeyguardStateController keyguardStateController,
|
KeyguardStateController keyguardStateController,
|
||||||
Lazy<AlternateBouncerInteractor> alternateBouncerInteractor,
|
Lazy<AlternateBouncerInteractor> alternateBouncerInteractor,
|
||||||
InteractionJankMonitor interactionJankMonitor) {
|
InteractionJankMonitor interactionJankMonitor,
|
||||||
|
AnimationFeatureFlags animationFeatureFlags) {
|
||||||
DialogLaunchAnimator.Callback callback = new DialogLaunchAnimator.Callback() {
|
DialogLaunchAnimator.Callback callback = new DialogLaunchAnimator.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public boolean isDreaming() {
|
public boolean isDreaming() {
|
||||||
@@ -303,6 +307,19 @@ public interface CentralSurfacesDependenciesModule {
|
|||||||
return alternateBouncerInteractor.get().canShowAlternateBouncerForFingerprint();
|
return alternateBouncerInteractor.get().canShowAlternateBouncerForFingerprint();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return new DialogLaunchAnimator(callback, interactionJankMonitor);
|
return new DialogLaunchAnimator(callback, interactionJankMonitor, animationFeatureFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@SysUISingleton
|
||||||
|
static AnimationFeatureFlags provideAnimationFeatureFlags(FeatureFlags featureFlags) {
|
||||||
|
return new AnimationFeatureFlags() {
|
||||||
|
@Override
|
||||||
|
public boolean isPredictiveBackQsDialogAnim() {
|
||||||
|
return featureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package com.android.systemui.animation.back
|
||||||
|
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.window.BackEvent
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
|
||||||
|
private data class BackInput(val progressX: Float, val progressY: Float, val edge: Int)
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
class BackAnimationSpecTest : SysuiTestCase() {
|
||||||
|
private var displayMetrics =
|
||||||
|
DisplayMetrics().apply {
|
||||||
|
widthPixels = 100
|
||||||
|
heightPixels = 200
|
||||||
|
density = 3f
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun sysUi_floatingSystemSurfaces_animationValues() {
|
||||||
|
val maxX = 14.0f
|
||||||
|
val maxY = 4.0f
|
||||||
|
val minScale = 0.8f
|
||||||
|
|
||||||
|
val backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi(displayMetrics)
|
||||||
|
|
||||||
|
assertBackTransformation(
|
||||||
|
backAnimationSpec = backAnimationSpec,
|
||||||
|
backInput = BackInput(progressX = 0f, progressY = 0f, edge = BackEvent.EDGE_LEFT),
|
||||||
|
expected = BackTransformation(translateX = 0f, translateY = 0f, scale = 1f),
|
||||||
|
)
|
||||||
|
assertBackTransformation(
|
||||||
|
backAnimationSpec = backAnimationSpec,
|
||||||
|
backInput = BackInput(progressX = 1f, progressY = 0f, edge = BackEvent.EDGE_LEFT),
|
||||||
|
expected = BackTransformation(translateX = -maxX, translateY = 0f, scale = minScale),
|
||||||
|
)
|
||||||
|
assertBackTransformation(
|
||||||
|
backAnimationSpec = backAnimationSpec,
|
||||||
|
backInput = BackInput(progressX = 1f, progressY = 0f, edge = BackEvent.EDGE_RIGHT),
|
||||||
|
expected = BackTransformation(translateX = maxX, translateY = 0f, scale = minScale),
|
||||||
|
)
|
||||||
|
assertBackTransformation(
|
||||||
|
backAnimationSpec = backAnimationSpec,
|
||||||
|
backInput = BackInput(progressX = 1f, progressY = 1f, edge = BackEvent.EDGE_LEFT),
|
||||||
|
expected = BackTransformation(translateX = -maxX, translateY = -maxY, scale = minScale),
|
||||||
|
)
|
||||||
|
assertBackTransformation(
|
||||||
|
backAnimationSpec = backAnimationSpec,
|
||||||
|
backInput = BackInput(progressX = 0f, progressY = 1f, edge = BackEvent.EDGE_LEFT),
|
||||||
|
expected = BackTransformation(translateX = 0f, translateY = -maxY, scale = 1f),
|
||||||
|
)
|
||||||
|
assertBackTransformation(
|
||||||
|
backAnimationSpec = backAnimationSpec,
|
||||||
|
backInput = BackInput(progressX = 0f, progressY = -1f, edge = BackEvent.EDGE_LEFT),
|
||||||
|
expected = BackTransformation(translateX = 0f, translateY = maxY, scale = 1f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertBackTransformation(
|
||||||
|
backAnimationSpec: BackAnimationSpec,
|
||||||
|
backInput: BackInput,
|
||||||
|
expected: BackTransformation,
|
||||||
|
) {
|
||||||
|
val actual = BackTransformation()
|
||||||
|
backAnimationSpec.getBackTransformation(
|
||||||
|
backEvent =
|
||||||
|
BackEvent(
|
||||||
|
/* touchX = */ 0f,
|
||||||
|
/* touchY = */ 0f,
|
||||||
|
/* progress = */ backInput.progressX,
|
||||||
|
/* swipeEdge = */ backInput.edge,
|
||||||
|
),
|
||||||
|
progressY = backInput.progressY,
|
||||||
|
result = actual
|
||||||
|
)
|
||||||
|
|
||||||
|
val tolerance = 0f
|
||||||
|
assertThat(actual.translateX).isWithin(tolerance).of(expected.translateX)
|
||||||
|
assertThat(actual.translateY).isWithin(tolerance).of(expected.translateY)
|
||||||
|
assertThat(actual.scale).isWithin(tolerance).of(expected.scale)
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.android.systemui.animation.back
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
class BackTransformationTest : SysuiTestCase() {
|
||||||
|
private val targetView: View = mock()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun defaultValue_noTransformation() {
|
||||||
|
val transformation = BackTransformation()
|
||||||
|
|
||||||
|
assertThat(transformation.translateX).isNaN()
|
||||||
|
assertThat(transformation.translateY).isNaN()
|
||||||
|
assertThat(transformation.scale).isNaN()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyTo_targetView_translateX_Y_Scale() {
|
||||||
|
val transformation = BackTransformation(translateX = 0f, translateY = 0f, scale = 1f)
|
||||||
|
|
||||||
|
transformation.applyTo(targetView = targetView)
|
||||||
|
|
||||||
|
verify(targetView).translationX = 0f
|
||||||
|
verify(targetView).translationY = 0f
|
||||||
|
verify(targetView).scaleX = 1f
|
||||||
|
verify(targetView).scaleY = 1f
|
||||||
|
verifyNoMoreInteractions(targetView)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyTo_targetView_translateX() {
|
||||||
|
val transformation = BackTransformation(translateX = 1f)
|
||||||
|
|
||||||
|
transformation.applyTo(targetView = targetView)
|
||||||
|
|
||||||
|
verify(targetView).translationX = 1f
|
||||||
|
verifyNoMoreInteractions(targetView)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyTo_targetView_translateY() {
|
||||||
|
val transformation = BackTransformation(translateY = 2f)
|
||||||
|
|
||||||
|
transformation.applyTo(targetView = targetView)
|
||||||
|
|
||||||
|
verify(targetView).translationY = 2f
|
||||||
|
verifyNoMoreInteractions(targetView)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyTo_targetView_scale() {
|
||||||
|
val transformation = BackTransformation(scale = 3f)
|
||||||
|
|
||||||
|
transformation.applyTo(targetView = targetView)
|
||||||
|
|
||||||
|
verify(targetView).scaleX = 3f
|
||||||
|
verify(targetView).scaleY = 3f
|
||||||
|
verifyNoMoreInteractions(targetView)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun applyTo_targetView_noTransformation() {
|
||||||
|
val transformation = BackTransformation()
|
||||||
|
|
||||||
|
transformation.applyTo(targetView = targetView)
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(targetView)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.android.systemui.animation.back
|
||||||
|
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.window.BackEvent
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
class OnBackAnimationCallbackExtensionTest : SysuiTestCase() {
|
||||||
|
private val onBackProgress: (BackTransformation) -> Unit = mock()
|
||||||
|
private val onBackStart: (BackEvent) -> Unit = mock()
|
||||||
|
private val onBackInvoke: () -> Unit = mock()
|
||||||
|
private val onBackCancel: () -> Unit = mock()
|
||||||
|
|
||||||
|
private val displayMetrics =
|
||||||
|
DisplayMetrics().apply {
|
||||||
|
widthPixels = 100
|
||||||
|
heightPixels = 100
|
||||||
|
density = 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onBackAnimationCallback =
|
||||||
|
onBackAnimationCallbackFrom(
|
||||||
|
backAnimationSpec = BackAnimationSpec.floatingSystemSurfacesForSysUi(displayMetrics),
|
||||||
|
displayMetrics = displayMetrics,
|
||||||
|
onBackProgressed = onBackProgress,
|
||||||
|
onBackStarted = onBackStart,
|
||||||
|
onBackInvoked = onBackInvoke,
|
||||||
|
onBackCancelled = onBackCancel,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onBackProgressed_shouldInvoke_onBackProgress() {
|
||||||
|
val backEvent = BackEvent(0f, 0f, 0f, BackEvent.EDGE_LEFT)
|
||||||
|
onBackAnimationCallback.onBackStarted(backEvent)
|
||||||
|
|
||||||
|
onBackAnimationCallback.onBackProgressed(backEvent)
|
||||||
|
|
||||||
|
verify(onBackProgress).invoke(BackTransformation(0f, 0f, 1f))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onBackStarted_shouldInvoke_onBackStart() {
|
||||||
|
val backEvent = BackEvent(0f, 0f, 0f, BackEvent.EDGE_LEFT)
|
||||||
|
|
||||||
|
onBackAnimationCallback.onBackStarted(backEvent)
|
||||||
|
|
||||||
|
verify(onBackStart).invoke(backEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onBackInvoked_shouldInvoke_onBackInvoke() {
|
||||||
|
onBackAnimationCallback.onBackInvoked()
|
||||||
|
|
||||||
|
verify(onBackInvoke).invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,14 +23,20 @@ fun fakeDialogLaunchAnimator(
|
|||||||
isUnlocked: Boolean = true,
|
isUnlocked: Boolean = true,
|
||||||
isShowingAlternateAuthOnUnlock: Boolean = false,
|
isShowingAlternateAuthOnUnlock: Boolean = false,
|
||||||
interactionJankMonitor: InteractionJankMonitor = mock(InteractionJankMonitor::class.java),
|
interactionJankMonitor: InteractionJankMonitor = mock(InteractionJankMonitor::class.java),
|
||||||
|
isPredictiveBackQsDialogAnim: Boolean = false,
|
||||||
): DialogLaunchAnimator {
|
): DialogLaunchAnimator {
|
||||||
return DialogLaunchAnimator(
|
return DialogLaunchAnimator(
|
||||||
|
callback =
|
||||||
FakeCallback(
|
FakeCallback(
|
||||||
isUnlocked = isUnlocked,
|
isUnlocked = isUnlocked,
|
||||||
isShowingAlternateAuthOnUnlock = isShowingAlternateAuthOnUnlock,
|
isShowingAlternateAuthOnUnlock = isShowingAlternateAuthOnUnlock,
|
||||||
),
|
),
|
||||||
interactionJankMonitor,
|
interactionJankMonitor = interactionJankMonitor,
|
||||||
fakeLaunchAnimator(),
|
featureFlags =
|
||||||
|
object : AnimationFeatureFlags {
|
||||||
|
override val isPredictiveBackQsDialogAnim = isPredictiveBackQsDialogAnim
|
||||||
|
},
|
||||||
|
launchAnimator = fakeLaunchAnimator(),
|
||||||
isForTesting = true,
|
isForTesting = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user