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

Commit 23b2c1c2 authored by Fangqiu Su's avatar Fangqiu Su Committed by Automerger Merge Worker
Browse files

Merge "Revert "Tap to wake up dreaming for lockscreen hosted dream"" into...

Merge "Revert "Tap to wake up dreaming for lockscreen hosted dream"" into udc-qpr-dev am: 0d129f57 am: dea9534d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24086426



Change-Id: Idc4f759f13b5712459e05d14f749e4f98d8b8952
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents e490f568 dea9534d
Loading
Loading
Loading
Loading
+0 −13
Original line number Original line Diff line number Diff line
@@ -70,19 +70,6 @@ constructor(
        }
        }
    }
    }


    /**
     * Wakes up the device if dreaming with a screensaver.
     *
     * @param why a string explaining why we're waking the device for debugging purposes. Should be
     *   in SCREAMING_SNAKE_CASE.
     * @param wakeReason the PowerManager-based reason why we're waking the device.
     */
    fun wakeUpIfDreaming(why: String, @PowerManager.WakeReason wakeReason: Int) {
        if (statusBarStateController.isDreaming) {
            repository.wakeUp(why, wakeReason)
        }
    }

    companion object {
    companion object {
        private const val FSI_WAKE_WHY = "full_screen_intent"
        private const val FSI_WAKE_WHY = "full_screen_intent"
    }
    }
+0 −72
Original line number Original line 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.shade

import android.os.PowerManager
import android.view.GestureDetector
import android.view.MotionEvent
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
import javax.inject.Inject

/**
 * This gestureListener will wake up by tap when the device is dreaming but not dozing, and the
 * selected screensaver is hosted in lockscreen. Tap is gated by the falsing manager.
 *
 * Touches go through the [NotificationShadeWindowViewController].
 */
@CentralSurfacesComponent.CentralSurfacesScope
class LockscreenHostedDreamGestureListener
@Inject
constructor(
    private val falsingManager: FalsingManager,
    private val powerInteractor: PowerInteractor,
    private val statusBarStateController: StatusBarStateController,
    private val primaryBouncerInteractor: PrimaryBouncerInteractor,
    private val keyguardRepository: KeyguardRepository,
    private val shadeLogger: ShadeLogger,
) : GestureDetector.SimpleOnGestureListener() {
    private val TAG = this::class.simpleName

    override fun onSingleTapUp(e: MotionEvent): Boolean {
        if (shouldHandleMotionEvent()) {
            if (!falsingManager.isFalseTap(LOW_PENALTY)) {
                shadeLogger.d("$TAG#onSingleTapUp tap handled, requesting wakeUpIfDreaming")
                powerInteractor.wakeUpIfDreaming(
                    "DREAMING_SINGLE_TAP",
                    PowerManager.WAKE_REASON_TAP
                )
            } else {
                shadeLogger.d("$TAG#onSingleTapUp false tap ignored")
            }
            return true
        }
        return false
    }

    private fun shouldHandleMotionEvent(): Boolean {
        return keyguardRepository.isActiveDreamLockscreenHosted.value &&
            statusBarStateController.state == StatusBarState.KEYGUARD &&
            !primaryBouncerInteractor.isBouncerShowing()
    }
}
+1 −15
Original line number Original line Diff line number Diff line
@@ -16,7 +16,6 @@


package com.android.systemui.shade;
package com.android.systemui.shade;


import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.flags.Flags.TRACKPAD_GESTURE_COMMON;
import static com.android.systemui.flags.Flags.TRACKPAD_GESTURE_COMMON;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;


@@ -103,12 +102,9 @@ public class NotificationShadeWindowViewController {
    private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
    private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
    private final AmbientState mAmbientState;
    private final AmbientState mAmbientState;
    private final PulsingGestureListener mPulsingGestureListener;
    private final PulsingGestureListener mPulsingGestureListener;
    private final LockscreenHostedDreamGestureListener mLockscreenHostedDreamGestureListener;
    private final NotificationInsetsController mNotificationInsetsController;
    private final NotificationInsetsController mNotificationInsetsController;
    private final boolean mIsTrackpadCommonEnabled;
    private final boolean mIsTrackpadCommonEnabled;
    private final FeatureFlags mFeatureFlags;
    private GestureDetector mPulsingWakeupGestureHandler;
    private GestureDetector mPulsingWakeupGestureHandler;
    private GestureDetector mDreamingWakeupGestureHandler;
    private View mBrightnessMirror;
    private View mBrightnessMirror;
    private boolean mTouchActive;
    private boolean mTouchActive;
    private boolean mTouchCancelled;
    private boolean mTouchCancelled;
@@ -160,7 +156,6 @@ public class NotificationShadeWindowViewController {
            NotificationInsetsController notificationInsetsController,
            NotificationInsetsController notificationInsetsController,
            AmbientState ambientState,
            AmbientState ambientState,
            PulsingGestureListener pulsingGestureListener,
            PulsingGestureListener pulsingGestureListener,
            LockscreenHostedDreamGestureListener lockscreenHostedDreamGestureListener,
            KeyguardBouncerViewModel keyguardBouncerViewModel,
            KeyguardBouncerViewModel keyguardBouncerViewModel,
            KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
            KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory,
            KeyguardMessageAreaController.Factory messageAreaControllerFactory,
            KeyguardMessageAreaController.Factory messageAreaControllerFactory,
@@ -192,10 +187,8 @@ public class NotificationShadeWindowViewController {
        mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
        mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
        mAmbientState = ambientState;
        mAmbientState = ambientState;
        mPulsingGestureListener = pulsingGestureListener;
        mPulsingGestureListener = pulsingGestureListener;
        mLockscreenHostedDreamGestureListener = lockscreenHostedDreamGestureListener;
        mNotificationInsetsController = notificationInsetsController;
        mNotificationInsetsController = notificationInsetsController;
        mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);
        mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);
        mFeatureFlags = featureFlags;


        // This view is not part of the newly inflated expanded status bar.
        // This view is not part of the newly inflated expanded status bar.
        mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
        mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -244,10 +237,7 @@ public class NotificationShadeWindowViewController {
        mStackScrollLayout = mView.findViewById(R.id.notification_stack_scroller);
        mStackScrollLayout = mView.findViewById(R.id.notification_stack_scroller);
        mPulsingWakeupGestureHandler = new GestureDetector(mView.getContext(),
        mPulsingWakeupGestureHandler = new GestureDetector(mView.getContext(),
                mPulsingGestureListener);
                mPulsingGestureListener);
        if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {

            mDreamingWakeupGestureHandler = new GestureDetector(mView.getContext(),
                    mLockscreenHostedDreamGestureListener);
        }
        mView.setLayoutInsetsController(mNotificationInsetsController);
        mView.setLayoutInsetsController(mNotificationInsetsController);
        mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
        mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
            @Override
            @Override
@@ -301,10 +291,6 @@ public class NotificationShadeWindowViewController {


                mFalsingCollector.onTouchEvent(ev);
                mFalsingCollector.onTouchEvent(ev);
                mPulsingWakeupGestureHandler.onTouchEvent(ev);
                mPulsingWakeupGestureHandler.onTouchEvent(ev);
                if (mDreamingWakeupGestureHandler != null
                        && mDreamingWakeupGestureHandler.onTouchEvent(ev)) {
                    return true;
                }
                if (mStatusBarKeyguardViewManager.dispatchTouchEvent(ev)) {
                if (mStatusBarKeyguardViewManager.dispatchTouchEvent(ev)) {
                    return true;
                    return true;
                }
                }
+0 −15
Original line number Original line Diff line number Diff line
@@ -182,21 +182,6 @@ class PowerInteractorTest : SysuiTestCase() {
        assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_APPLICATION)
        assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_APPLICATION)
    }
    }


    @Test
    fun wakeUpIfDreaming_notDozing() =
        runBlocking(IMMEDIATE) {
            // GIVEN device is dreaming and not dozing
            whenever(statusBarStateController.isDozing).thenReturn(false)
            whenever(statusBarStateController.isDreaming).thenReturn(true)

            // WHEN wakeUpIfDreaming is called
            underTest.wakeUpIfDreaming("testReason", PowerManager.WAKE_REASON_GESTURE)

            // THEN device is waken up
            assertThat(repository.lastWakeWhy).isEqualTo("testReason")
            assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE)
        }

    companion object {
    companion object {
        private val IMMEDIATE = Dispatchers.Main.immediate
        private val IMMEDIATE = Dispatchers.Main.immediate
    }
    }
+0 −189
Original line number Original line 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.shade

import android.os.PowerManager
import android.testing.AndroidTestingRunner
import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.data.repository.FakePowerRepository
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@SmallTest
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidTestingRunner::class)
class LockscreenHostedDreamGestureListenerTest : SysuiTestCase() {
    @Mock private lateinit var falsingManager: FalsingManager
    @Mock private lateinit var falsingCollector: FalsingCollector
    @Mock private lateinit var statusBarStateController: StatusBarStateController
    @Mock private lateinit var shadeLogger: ShadeLogger
    @Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController
    @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor

    private val testDispatcher = UnconfinedTestDispatcher()
    private val testScope = TestScope(testDispatcher)

    private lateinit var powerRepository: FakePowerRepository
    private lateinit var keyguardRepository: FakeKeyguardRepository
    private lateinit var underTest: LockscreenHostedDreamGestureListener

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        powerRepository = FakePowerRepository()
        keyguardRepository = FakeKeyguardRepository()

        underTest =
            LockscreenHostedDreamGestureListener(
                falsingManager,
                PowerInteractor(
                    powerRepository,
                    keyguardRepository,
                    falsingCollector,
                    screenOffAnimationController,
                    statusBarStateController,
                ),
                statusBarStateController,
                primaryBouncerInteractor,
                keyguardRepository,
                shadeLogger,
            )
        whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
        whenever(primaryBouncerInteractor.isBouncerShowing()).thenReturn(false)
    }

    @Test
    fun testGestureDetector_onSingleTap_whileDreaming() =
        testScope.runTest {
            // GIVEN device dreaming and the dream is hosted in lockscreen
            whenever(statusBarStateController.isDreaming).thenReturn(true)
            keyguardRepository.setIsActiveDreamLockscreenHosted(true)
            testScope.runCurrent()

            // GIVEN the falsing manager does NOT think the tap is a false tap
            whenever(falsingManager.isFalseTap(ArgumentMatchers.anyInt())).thenReturn(false)

            // WHEN there's a tap
            underTest.onSingleTapUp(upEv)

            // THEN wake up device if dreaming
            Truth.assertThat(powerRepository.lastWakeWhy).isNotNull()
            Truth.assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_TAP)
        }

    @Test
    fun testGestureDetector_onSingleTap_notOnKeyguard() =
        testScope.runTest {
            // GIVEN device dreaming and the dream is hosted in lockscreen
            whenever(statusBarStateController.isDreaming).thenReturn(true)
            keyguardRepository.setIsActiveDreamLockscreenHosted(true)
            testScope.runCurrent()

            // GIVEN shade is open
            whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)

            // GIVEN the falsing manager does NOT think the tap is a false tap
            whenever(falsingManager.isFalseTap(ArgumentMatchers.anyInt())).thenReturn(false)

            // WHEN there's a tap
            underTest.onSingleTapUp(upEv)

            // THEN the falsing manager never gets a call
            verify(falsingManager, never()).isFalseTap(ArgumentMatchers.anyInt())
        }

    @Test
    fun testGestureDetector_onSingleTap_bouncerShown() =
        testScope.runTest {
            // GIVEN device dreaming and the dream is hosted in lockscreen
            whenever(statusBarStateController.isDreaming).thenReturn(true)
            keyguardRepository.setIsActiveDreamLockscreenHosted(true)
            testScope.runCurrent()

            // GIVEN bouncer is expanded
            whenever(primaryBouncerInteractor.isBouncerShowing()).thenReturn(true)

            // GIVEN the falsing manager does NOT think the tap is a false tap
            whenever(falsingManager.isFalseTap(ArgumentMatchers.anyInt())).thenReturn(false)

            // WHEN there's a tap
            underTest.onSingleTapUp(upEv)

            // THEN the falsing manager never gets a call
            verify(falsingManager, never()).isFalseTap(ArgumentMatchers.anyInt())
        }

    @Test
    fun testGestureDetector_onSingleTap_falsing() =
        testScope.runTest {
            // GIVEN device dreaming and the dream is hosted in lockscreen
            whenever(statusBarStateController.isDreaming).thenReturn(true)
            keyguardRepository.setIsActiveDreamLockscreenHosted(true)
            testScope.runCurrent()

            // GIVEN the falsing manager thinks the tap is a false tap
            whenever(falsingManager.isFalseTap(ArgumentMatchers.anyInt())).thenReturn(true)

            // WHEN there's a tap
            underTest.onSingleTapUp(upEv)

            // THEN the device doesn't wake up
            Truth.assertThat(powerRepository.lastWakeWhy).isNull()
            Truth.assertThat(powerRepository.lastWakeReason).isNull()
        }

    @Test
    fun testSingleTap_notDreaming_noFalsingCheck() =
        testScope.runTest {
            // GIVEN device not dreaming with lockscreen hosted dream
            whenever(statusBarStateController.isDreaming).thenReturn(false)
            keyguardRepository.setIsActiveDreamLockscreenHosted(false)
            testScope.runCurrent()

            // WHEN there's a tap
            underTest.onSingleTapUp(upEv)

            // THEN the falsing manager never gets a call
            verify(falsingManager, never()).isFalseTap(ArgumentMatchers.anyInt())
        }
}

private val upEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
Loading