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

Commit d1b950b2 authored by omarmt's avatar omarmt Committed by Omar Miatello
Browse files

Add Predictive Back animation to all SysUI dialogs

Test: atest SystemUIDialogTest
Bug: 238475102
Change-Id: I0afb1bd1e6fe3146a8e2820de6611c14caddd615
parent efe52d28
Loading
Loading
Loading
Loading
+2 −35
Original line number Diff line number Diff line
@@ -33,13 +33,9 @@ import android.view.WindowInsets
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
import android.widget.FrameLayout
import android.window.OnBackInvokedDispatcher
import com.android.internal.jank.InteractionJankMonitor
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 com.android.systemui.util.registerAnimationOnBackInvoked
import java.lang.IllegalArgumentException
import kotlin.math.roundToInt

@@ -798,7 +794,7 @@ private class AnimatedDialog(

        if (featureFlags.isPredictiveBackQsDialogAnim) {
            // TODO(b/265923095) Improve animations for QS dialogs on configuration change
            registerOnBackInvokedCallback(targetView = dialogContentWithBackground)
            dialog.registerAnimationOnBackInvoked(targetView = dialogContentWithBackground)
        }

        // Show the dialog.
@@ -806,35 +802,6 @@ private class AnimatedDialog(
        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() {
        if (decorView.viewRootImpl == null) {
            // Make sure that we have access to the dialog view root to move the drawing to the
+37 −0
Original line number Diff line number Diff line
@@ -16,15 +16,21 @@

package com.android.systemui.animation.back

import android.annotation.IntRange
import android.util.DisplayMetrics
import android.view.View
import android.window.BackEvent
import android.window.OnBackAnimationCallback
import android.window.OnBackInvokedDispatcher
import android.window.OnBackInvokedDispatcher.Priority

/**
 * 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.
 *
 * @sample com.android.systemui.util.registerAnimationOnBackInvoked
 */
fun onBackAnimationCallbackFrom(
    backAnimationSpec: BackAnimationSpec,
@@ -64,3 +70,34 @@ fun onBackAnimationCallbackFrom(
        }
    }
}

/**
 * Register [OnBackAnimationCallback] when View is attached and unregister it when View is detached
 *
 * @sample com.android.systemui.util.registerAnimationOnBackInvoked
 */
fun View.registerOnBackInvokedCallbackOnViewAttached(
    onBackInvokedDispatcher: OnBackInvokedDispatcher,
    onBackAnimationCallback: OnBackAnimationCallback,
    @Priority @IntRange(from = 0) priority: Int = OnBackInvokedDispatcher.PRIORITY_DEFAULT,
) {
    addOnAttachStateChangeListener(
        object : View.OnAttachStateChangeListener {
            override fun onViewAttachedToWindow(v: View) {
                onBackInvokedDispatcher.registerOnBackInvokedCallback(
                    priority,
                    onBackAnimationCallback
                )
            }

            override fun onViewDetachedFromWindow(v: View) {
                removeOnAttachStateChangeListener(this)
                onBackInvokedDispatcher.unregisterOnBackInvokedCallback(onBackAnimationCallback)
            }
        }
    )

    if (isAttachedToWindow) {
        onBackInvokedDispatcher.registerOnBackInvokedCallback(priority, onBackAnimationCallback)
    }
}
+51 −0
Original line number Diff line number Diff line
/*
 * 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.app.Dialog
import android.view.View
import android.window.OnBackInvokedDispatcher
import com.android.systemui.animation.back.BackAnimationSpec
import com.android.systemui.animation.back.BackTransformation
import com.android.systemui.animation.back.applyTo
import com.android.systemui.animation.back.floatingSystemSurfacesForSysUi
import com.android.systemui.animation.back.onBackAnimationCallbackFrom
import com.android.systemui.animation.back.registerOnBackInvokedCallbackOnViewAttached

/**
 * Register on the Dialog's [OnBackInvokedDispatcher] an animation using the [BackAnimationSpec].
 * The [BackTransformation] will be applied on the [targetView].
 */
@JvmOverloads
fun Dialog.registerAnimationOnBackInvoked(
    targetView: View,
    backAnimationSpec: BackAnimationSpec =
        BackAnimationSpec.floatingSystemSurfacesForSysUi(
            displayMetrics = targetView.resources.displayMetrics,
        ),
) {
    targetView.registerOnBackInvokedCallbackOnViewAttached(
        onBackInvokedDispatcher = onBackInvokedDispatcher,
        onBackAnimationCallback =
            onBackAnimationCallbackFrom(
                backAnimationSpec = backAnimationSpec,
                displayMetrics = targetView.resources.displayMetrics,
                onBackProgressed = { backTransformation -> backTransformation.applyTo(targetView) },
                onBackInvoked = { dismiss() },
            ),
    )
}
+21 −4
Original line number Diff line number Diff line
@@ -45,8 +45,11 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.model.SysUiState;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.util.DialogKt;

import java.util.ArrayList;
import java.util.List;
@@ -68,6 +71,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
    private static final boolean DEFAULT_DISMISS_ON_DEVICE_LOCK = true;

    private final Context mContext;
    private final FeatureFlags mFeatureFlags;
    @Nullable private final DismissReceiver mDismissReceiver;
    private final Handler mHandler = new Handler();
    private final SystemUIDialogManager mDialogManager;
@@ -96,16 +100,23 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
        // TODO(b/219008720): Remove those calls to Dependency.get by introducing a
        // SystemUIDialogFactory and make all other dialogs create a SystemUIDialog to which we set
        // the content and attach listeners.
        this(context, theme, dismissOnDeviceLock, Dependency.get(SystemUIDialogManager.class),
                Dependency.get(SysUiState.class), Dependency.get(BroadcastDispatcher.class),
        this(context, theme, dismissOnDeviceLock,
                Dependency.get(FeatureFlags.class),
                Dependency.get(SystemUIDialogManager.class),
                Dependency.get(SysUiState.class),
                Dependency.get(BroadcastDispatcher.class),
                Dependency.get(DialogLaunchAnimator.class));
    }

    public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock,
            SystemUIDialogManager dialogManager, SysUiState sysUiState,
            BroadcastDispatcher broadcastDispatcher, DialogLaunchAnimator dialogLaunchAnimator) {
            FeatureFlags featureFlags,
            SystemUIDialogManager dialogManager,
            SysUiState sysUiState,
            BroadcastDispatcher broadcastDispatcher,
            DialogLaunchAnimator dialogLaunchAnimator) {
        super(context, theme);
        mContext = context;
        mFeatureFlags = featureFlags;

        applyFlags(this);
        WindowManager.LayoutParams attrs = getWindow().getAttributes();
@@ -130,6 +141,12 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
        for (int i = 0; i < mOnCreateRunnables.size(); i++) {
            mOnCreateRunnables.get(i).run();
        }
        if (mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM)) {
            DialogKt.registerAnimationOnBackInvoked(
                    /* dialog = */ this,
                    /* targetView = */ getWindow().getDecorView()
            );
        }
    }

    private void updateWindowSize() {
+15 −7
Original line number Diff line number Diff line
@@ -13,8 +13,9 @@ import org.junit.runners.Parameterized

@RunWith(Parameterized::class)
@SmallTest
internal class FloatingRotationButtonPositionCalculatorTest(private val testCase: TestCase)
    : SysuiTestCase() {
internal class FloatingRotationButtonPositionCalculatorTest(
        private val testCase: TestCase,
) : SysuiTestCase() {

    @Test
    fun calculatePosition() {
@@ -34,11 +35,18 @@ internal class FloatingRotationButtonPositionCalculatorTest(private val testCase
        val expectedPosition: Position
    ) {
        override fun toString(): String =
            "when calculator = $calculator, " +
                "rotation = $rotation, " +
                "taskbarVisible = $taskbarVisible, " +
                "taskbarStashed = $taskbarStashed - " +
                "expected $expectedPosition"
                buildString {
                    append("when calculator = ")
                    append(when (calculator) {
                        posLeftCalculator -> "LEFT"
                        posRightCalculator -> "RIGHT"
                        else -> error("Unknown calculator: $calculator")
                    })
                    append(", rotation = $rotation")
                    append(", taskbarVisible = $taskbarVisible")
                    append(", taskbarStashed = $taskbarStashed")
                    append(" - expected $expectedPosition")
                }
    }

    companion object {
Loading