Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b69ff7b4 authored by Johannes Gallmann's avatar Johannes Gallmann
Browse files

Add bottomsheet predictive back animation for SysUI

Bug: 340724858
Flag: com.android.systemui.predictiveBackAnimateDialogs
Test: atest BackAnimationSpecTest
Test: atest SystemUIDialogTest
Test: atest BackTransformationTest
Test: Manual, i.e. testing predictive back animation for volume panel bottomsheet on device
Change-Id: Ica27bb102e747dd83503eae70a93cfaad1906050
parent c14c0eac
Loading
Loading
Loading
Loading
+8 −0
Original line number Original line Diff line number Diff line
@@ -73,3 +73,11 @@ fun BackAnimationSpec.Companion.floatingSystemSurfacesForSysUi(
        maxMarginYdp = 8f,
        maxMarginYdp = 8f,
        minScale = 0.9f,
        minScale = 0.9f,
    )
    )

/**
 * SysUI transitions - Bottomsheet (AT3)
 * https://carbon.googleplex.com/predictive-back-for-apps/pages/at-3-bottom-sheets
 */
fun BackAnimationSpec.Companion.bottomSheetForSysUi(
    displayMetricsProvider: () -> DisplayMetrics,
): BackAnimationSpec = BackAnimationSpec.createBottomsheetAnimationSpec(displayMetricsProvider)
+24 −0
Original line number Original line Diff line number Diff line
@@ -26,12 +26,36 @@ data class BackTransformation(
    var translateX: Float = Float.NaN,
    var translateX: Float = Float.NaN,
    var translateY: Float = Float.NaN,
    var translateY: Float = Float.NaN,
    var scale: Float = Float.NaN,
    var scale: Float = Float.NaN,
    var scalePivotPosition: ScalePivotPosition? = null,
)
)


/** Enum that describes the location of the scale pivot position */
enum class ScalePivotPosition {
    // more options may be added in the future
    CENTER,
    BOTTOM_CENTER;

    fun applyTo(view: View) {
        val pivotX =
            when (this) {
                CENTER -> view.width / 2f
                BOTTOM_CENTER -> view.width / 2f
            }
        val pivotY =
            when (this) {
                CENTER -> view.height / 2f
                BOTTOM_CENTER -> view.height.toFloat()
            }
        view.pivotX = pivotX
        view.pivotY = pivotY
    }
}

/** Apply the transformation to the [targetView] */
/** Apply the transformation to the [targetView] */
fun BackTransformation.applyTo(targetView: View) {
fun BackTransformation.applyTo(targetView: View) {
    if (translateX.isFinite()) targetView.translationX = translateX
    if (translateX.isFinite()) targetView.translationX = translateX
    if (translateY.isFinite()) targetView.translationY = translateY
    if (translateY.isFinite()) targetView.translationY = translateY
    scalePivotPosition?.applyTo(targetView)
    if (scale.isFinite()) {
    if (scale.isFinite()) {
        targetView.scaleX = scale
        targetView.scaleX = scale
        targetView.scaleY = scale
        targetView.scaleY = scale
+42 −0
Original line number Original line Diff line number Diff line
/*
 * 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.animation.back

import android.util.DisplayMetrics
import android.view.animation.Interpolator
import com.android.app.animation.Interpolators
import com.android.systemui.util.dpToPx

private const val MAX_SCALE_DELTA_DP = 48

/** Create a [BackAnimationSpec] from [displayMetrics] and design specs. */
fun BackAnimationSpec.Companion.createBottomsheetAnimationSpec(
    displayMetricsProvider: () -> DisplayMetrics,
    scaleEasing: Interpolator = Interpolators.BACK_GESTURE,
): BackAnimationSpec {
    return BackAnimationSpec { backEvent, _, result ->
        val displayMetrics = displayMetricsProvider()
        val screenWidthPx = displayMetrics.widthPixels
        val minScale = 1 - MAX_SCALE_DELTA_DP.dpToPx(displayMetrics) / screenWidthPx
        val progressX = backEvent.progress
        val ratioScale = scaleEasing.getInterpolation(progressX)
        result.apply {
            scale = 1f - ratioScale * (1f - minScale)
            scalePivotPosition = ScalePivotPosition.BOTTOM_CENTER
        }
    }
}
+9 −0
Original line number Original line Diff line number Diff line
@@ -17,8 +17,11 @@
package com.android.systemui.statusbar.phone
package com.android.systemui.statusbar.phone


import android.os.Bundle
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.Gravity
import android.view.Gravity
import android.view.WindowManager
import android.view.WindowManager
import com.android.systemui.animation.back.BackAnimationSpec
import com.android.systemui.animation.back.bottomSheetForSysUi


/** [DialogDelegate] that configures a dialog to be an edge-to-edge one. */
/** [DialogDelegate] that configures a dialog to be an edge-to-edge one. */
class EdgeToEdgeDialogDelegate : DialogDelegate<SystemUIDialog> {
class EdgeToEdgeDialogDelegate : DialogDelegate<SystemUIDialog> {
@@ -40,4 +43,10 @@ class EdgeToEdgeDialogDelegate : DialogDelegate<SystemUIDialog> {
    override fun getWidth(dialog: SystemUIDialog): Int = WindowManager.LayoutParams.MATCH_PARENT
    override fun getWidth(dialog: SystemUIDialog): Int = WindowManager.LayoutParams.MATCH_PARENT


    override fun getHeight(dialog: SystemUIDialog): Int = WindowManager.LayoutParams.MATCH_PARENT
    override fun getHeight(dialog: SystemUIDialog): Int = WindowManager.LayoutParams.MATCH_PARENT

    override fun getBackAnimationSpec(
        displayMetricsProvider: () -> DisplayMetrics
    ): BackAnimationSpec {
        return BackAnimationSpec.bottomSheetForSysUi(displayMetricsProvider)
    }
}
}
+5 −0
Original line number Original line Diff line number Diff line
@@ -21,8 +21,10 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertTrue;


import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.Intent;
@@ -41,6 +43,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.Flags;
import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogTransitionAnimator;
import com.android.systemui.animation.DialogTransitionAnimator;
import com.android.systemui.animation.back.BackAnimationSpec;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.model.SysUiState;
import com.android.systemui.model.SysUiState;


@@ -78,6 +81,8 @@ public class SystemUIDialogTest extends SysuiTestCase {
        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.initMocks(this);


        mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher);
        mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher);
        when(mDelegate.getBackAnimationSpec(ArgumentMatchers.any()))
                .thenReturn(mock(BackAnimationSpec.class));
    }
    }


    @Test
    @Test
Loading