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

Commit 7fa4c627 authored by Nicolò Mazzucato's avatar Nicolò Mazzucato Committed by Automerger Merge Worker
Browse files

Merge "Drive Launcher unfold animation from System UI" into tm-qpr-dev am: a8719c31

parents a4364f3b a8719c31
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ public class QuickStepContract {
    public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
    public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
    public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
    public static final String KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER = "extra_unfold_animation";
    // See ISysuiUnlockAnimationController.aidl
    public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation";

+18 −0
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ import com.android.systemui.unfold.FoldStateLogger;
import com.android.systemui.unfold.FoldStateLoggingProvider;
import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.unfold.UnfoldLatencyTracker;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder;
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.back.BackAnimation;
@@ -137,6 +139,10 @@ public interface SysUIComponent {
        getUnfoldLatencyTracker().init();
        getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init);
        getFoldStateLogger().ifPresent(FoldStateLogger::init);
        getUnfoldTransitionProgressProvider().ifPresent((progressProvider) ->
                getUnfoldTransitionProgressForwarder().ifPresent((forwarder) ->
                        progressProvider.addCallback(forwarder)
                ));
    }

    /**
@@ -163,6 +169,18 @@ public interface SysUIComponent {
    @SysUISingleton
    UnfoldLatencyTracker getUnfoldLatencyTracker();

    /**
     * Creates a UnfoldTransitionProgressProvider.
     */
    @SysUISingleton
    Optional<UnfoldTransitionProgressProvider> getUnfoldTransitionProgressProvider();

    /**
     * Creates a UnfoldTransitionProgressForwarder.
     */
    @SysUISingleton
    Optional<UnfoldTransitionProgressForwarder> getUnfoldTransitionProgressForwarder();

    /**
     * Creates a FoldStateLoggingProvider.
     */
+11 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
@@ -99,6 +100,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.CallbackController;
import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder;
import com.android.wm.shell.sysui.ShellInterface;

import java.io.PrintWriter;
@@ -144,6 +146,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
    private final CommandQueue mCommandQueue;
    private final UserTracker mUserTracker;
    private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController;
    private final Optional<UnfoldTransitionProgressForwarder> mUnfoldTransitionProgressForwarder;
    private final UiEventLogger mUiEventLogger;
    private final DisplayTracker mDisplayTracker;

@@ -415,6 +418,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
            params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
            params.putBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER,
                    mSysuiUnlockAnimationController.asBinder());
            mUnfoldTransitionProgressForwarder.ifPresent(
                    unfoldProgressForwarder -> params.putBinder(
                            KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER,
                            unfoldProgressForwarder.asBinder()));
            // Add all the interfaces exposed by the shell
            mShellInterface.createExternalInterfaces(params);

@@ -512,7 +519,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
            DisplayTracker displayTracker,
            KeyguardUnlockAnimationController sysuiUnlockAnimationController,
            AssistUtils assistUtils,
            DumpManager dumpManager) {
            DumpManager dumpManager,
            Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder
    ) {
        // b/241601880: This component shouldn't be running for a non-primary user
        if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) {
            Log.e(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable());
@@ -538,6 +547,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
        mSysUiState.addCallback(this::notifySystemUiStateFlags);
        mUiEventLogger = uiEventLogger;
        mDisplayTracker = displayTracker;
        mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder;

        dumpManager.registerDumpable(getClass().getSimpleName(), this);

+7 −109
Original line number Diff line number Diff line
@@ -20,17 +20,13 @@ import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
import com.android.systemui.unfold.util.TestFoldStateProvider
import com.android.systemui.util.leak.ReferenceTestUtils.waitForCondition
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,9 +41,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {

    @Before
    fun setUp() {
        progressProvider = PhysicsBasedUnfoldTransitionProgressProvider(
            foldStateProvider
        )
        progressProvider = PhysicsBasedUnfoldTransitionProgressProvider(foldStateProvider)
        progressProvider.addCallback(listener)
    }

@@ -79,9 +73,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
        )

        with(listener.ensureTransitionFinished()) {
            assertHasSingleFinishingEvent()
        }
        with(listener.ensureTransitionFinished()) { assertHasSingleFinishingEvent() }
    }

    @Test
@@ -150,106 +142,12 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) },
        )

        with(listener.ensureTransitionFinished()) {
            assertHasFoldAnimationAtTheEnd()
        }
    }

    private class TestUnfoldProgressListener : TransitionProgressListener {

        private val recordings: MutableList<UnfoldTransitionRecording> = arrayListOf()
        private var currentRecording: UnfoldTransitionRecording? = null

        override fun onTransitionStarted() {
            assertWithMessage("Trying to start a transition when it is already in progress")
                .that(currentRecording).isNull()

            currentRecording = UnfoldTransitionRecording()
        }

        override fun onTransitionProgress(progress: Float) {
            assertWithMessage("Received transition progress event when it's not started")
                .that(currentRecording).isNotNull()
            currentRecording!!.addProgress(progress)
        }

        override fun onTransitionFinishing() {
            assertWithMessage("Received transition finishing event when it's not started")
                    .that(currentRecording).isNotNull()
            currentRecording!!.onFinishing()
        }

        override fun onTransitionFinished() {
            assertWithMessage("Received transition finish event when it's not started")
                .that(currentRecording).isNotNull()
            recordings += currentRecording!!
            currentRecording = null
        }

        fun ensureTransitionFinished(): UnfoldTransitionRecording {
            waitForCondition { recordings.size == 1 }
            return recordings.first()
        }

        class UnfoldTransitionRecording {
            private val progressHistory: MutableList<Float> = arrayListOf()
            private var finishingInvocations: Int = 0

            fun addProgress(progress: Float) {
                assertThat(progress).isAtMost(1.0f)
                assertThat(progress).isAtLeast(0.0f)

                progressHistory += progress
            }

            fun onFinishing() {
                finishingInvocations++
            }

            fun assertIncreasingProgress() {
                assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS)
                assertThat(progressHistory).isInOrder()
            }

            fun assertDecreasingProgress() {
                assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS)
                assertThat(progressHistory).isInOrder(Comparator.reverseOrder<Float>())
            }

            fun assertFinishedWithUnfold() {
                assertThat(progressHistory).isNotEmpty()
                assertThat(progressHistory.last()).isEqualTo(1.0f)
            }

            fun assertFinishedWithFold() {
                assertThat(progressHistory).isNotEmpty()
                assertThat(progressHistory.last()).isEqualTo(0.0f)
            }

            fun assertHasFoldAnimationAtTheEnd() {
                // Check that there are at least a few decreasing events at the end
                assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS)
                assertThat(progressHistory.takeLast(MIN_ANIMATION_EVENTS))
                    .isInOrder(Comparator.reverseOrder<Float>())
                assertThat(progressHistory.last()).isEqualTo(0.0f)
            }

            fun assertHasSingleFinishingEvent() {
                assertWithMessage("onTransitionFinishing callback should be invoked exactly " +
                        "one time").that(finishingInvocations).isEqualTo(1)
            }
        }

        private companion object {
            private const val MIN_ANIMATION_EVENTS = 5
        }
        with(listener.ensureTransitionFinished()) { assertHasFoldAnimationAtTheEnd() }
    }

    private fun runOnMainThreadWithInterval(vararg blocks: () -> Unit, intervalMillis: Long = 60) {
        blocks.forEach {
            InstrumentationRegistry.getInstrumentation().runOnMainSync {
                it()
            }
            InstrumentationRegistry.getInstrumentation().runOnMainSync { it() }
            Thread.sleep(intervalMillis)
        }
    }
+72 −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.unfold.progress

import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidTestingRunner::class)
@SmallTest
class RemoteUnfoldTransitionReceiverTest : SysuiTestCase() {

    private val progressProvider = RemoteUnfoldTransitionReceiver { it.run() }
    private val listener = TestUnfoldProgressListener()

    @Before
    fun setUp() {
        progressProvider.addCallback(listener)
    }

    @Test
    fun onTransitionStarted_propagated() {
        progressProvider.onTransitionStarted()

        listener.assertStarted()
    }

    @Test
    fun onTransitionProgress_propagated() {
        progressProvider.onTransitionStarted()

        progressProvider.onTransitionProgress(0.5f)

        listener.assertLastProgress(0.5f)
    }

    @Test
    fun onTransitionEnded_propagated() {
        progressProvider.onTransitionStarted()
        progressProvider.onTransitionProgress(0.5f)

        progressProvider.onTransitionFinished()

        listener.ensureTransitionFinished()
    }

    @Test
    fun onTransitionStarted_afterCallbackRemoved_notPropagated() {
        progressProvider.removeCallback(listener)

        progressProvider.onTransitionStarted()

        listener.assertNotStarted()
    }
}
Loading