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

Commit 154a6abe authored by Shawn Lee's avatar Shawn Lee
Browse files

[flexiglass] Fix remote touch on flexiglass over launcher

Since flexiglass no longer consumes touches on the whole screen when we are idle on the Gone scene, we need to use the existing RemoteUserInteractionOngoing state to allow us to consume the expansion gesture when over launcher.

Bug: 347699508
Test: Manually verified Gone -> Shade gesture works as expected
Test: Manually verified RemoteUserInteractionOngoing value in TouchableRegionManager is correct throughout the gesture via logging
Flag: com.android.systemui.scene_container
Change-Id: I0e9effc5ccae5e7615570713d968b281ba0ca306
parent c78176d9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -165,6 +165,10 @@ constructor(
                initialValue = isVisibleInternal()
            )

    /** Whether there's an ongoing remotely-initiated user interaction. */
    val isRemoteUserInteractionOngoing: StateFlow<Boolean> =
        repository.isRemoteUserInteractionOngoing

    /**
     * The amount of transition into or out of the given [scene].
     *
+16 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import android.view.WindowInsets;

import androidx.annotation.VisibleForTesting;
import com.android.compose.animation.scene.ObservableTransitionState;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.Dumpable;
@@ -69,6 +70,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable {

    private boolean mIsStatusBarExpanded = false;
    private boolean mIsIdleOnGone = true;
    private boolean mIsRemoteUserInteractionOngoing = false;
    private boolean mShouldAdjustInsets = false;
    private View mNotificationShadeWindowView;
    private View mNotificationPanelView;
@@ -133,6 +135,9 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
            javaAdapter.alwaysCollectFlow(
                    sceneInteractor.get().getTransitionState(),
                    this::onSceneChanged);
            javaAdapter.alwaysCollectFlow(
                    sceneInteractor.get().isRemoteUserInteractionOngoing(),
                    this::onRemoteUserInteractionOngoingChanged);
        } else {
            javaAdapter.alwaysCollectFlow(
                    shadeInteractor.isAnyExpanded(),
@@ -179,6 +184,13 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
        }
    }

    private void onRemoteUserInteractionOngoingChanged(Boolean ongoing) {
        if (ongoing != mIsRemoteUserInteractionOngoing) {
            mIsRemoteUserInteractionOngoing = ongoing;
            updateTouchableRegion();
        }
    }

    /**
     * Calculates the touch region needed for heads up notifications, taking into consideration
     * any existing display cutouts (notch)
@@ -276,13 +288,15 @@ public final class StatusBarTouchableRegionManager implements Dumpable {
     * Helper to let us know when calculating the region is not needed because we know the entire
     * screen needs to be touchable.
     */
    private boolean shouldMakeEntireScreenTouchable() {
    @VisibleForTesting
    boolean shouldMakeEntireScreenTouchable() {
        // The touchable region is always the full area when expanded, whether we're showing the
        // shade or the bouncer. It's also fully touchable when the screen off animation is playing
        // since we don't want stray touches to go through the light reveal scrim to whatever is
        // underneath.
        return mIsStatusBarExpanded
                || (SceneContainerFlag.isEnabled() && !mIsIdleOnGone)
                || (SceneContainerFlag.isEnabled()
                && (!mIsIdleOnGone || mIsRemoteUserInteractionOngoing))
                || mPrimaryBouncerInteractor.isShowing().getValue()
                || mAlternateBouncerInteractor.isVisibleState()
                || mUnlockedScreenOffAnimationController.isAnimationPlaying();
+116 −0
Original line number 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.statusbar.phone

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.data.repository.sceneContainerRepository
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
import com.android.systemui.util.kotlin.getValue
import com.google.common.truth.Truth.assertThat
import dagger.Lazy
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class StatusBarTouchableRegionManagerTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val sceneRepository = kosmos.sceneContainerRepository

    private val underTest by Lazy { kosmos.statusBarTouchableRegionManager }

    @Test
    @EnableSceneContainer
    fun entireScreenTouchable_sceneContainerEnabled_isRemoteUserInteractionOngoing() =
        testScope.runTest {
            sceneRepository.setTransitionState(
                flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Gone))
            )
            runCurrent()
            assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()

            sceneRepository.isRemoteUserInteractionOngoing.value = true
            runCurrent()
            assertThat(underTest.shouldMakeEntireScreenTouchable()).isTrue()

            sceneRepository.isRemoteUserInteractionOngoing.value = false
            runCurrent()
            assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
        }

    @Test
    @DisableSceneContainer
    fun entireScreenTouchable_sceneContainerDisabled_isRemoteUserInteractionOngoing() =
        testScope.runTest {
            assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()

            sceneRepository.isRemoteUserInteractionOngoing.value = true
            runCurrent()

            assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
        }

    @Test
    @EnableSceneContainer
    fun entireScreenTouchable_sceneContainerEnabled_isIdleOnGone() =
        testScope.runTest {
            sceneRepository.setTransitionState(
                flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Gone))
            )
            runCurrent()
            assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()

            sceneRepository.setTransitionState(
                flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Shade))
            )
            runCurrent()
            assertThat(underTest.shouldMakeEntireScreenTouchable()).isTrue()

            sceneRepository.setTransitionState(
                flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Gone))
            )
            runCurrent()
            assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
        }

    @Test
    @DisableSceneContainer
    fun entireScreenTouchable_sceneContainerDisabled_isIdleOnGone() =
        testScope.runTest {
            assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()

            sceneRepository.setTransitionState(
                flowOf(ObservableTransitionState.Idle(currentScene = Scenes.Shade))
            )
            runCurrent()

            assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
        }
}
+47 −0
Original line number 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.statusbar.phone

import android.content.applicationContext
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.notificationShadeWindowController
import com.android.systemui.statusbar.policy.configurationController
import com.android.systemui.statusbar.policy.headsUpManager
import com.android.systemui.util.kotlin.JavaAdapter
import com.android.systemui.util.mockito.mock
import org.mockito.Mockito.mock

var Kosmos.statusBarTouchableRegionManager by
    Kosmos.Fixture {
        StatusBarTouchableRegionManager(
            applicationContext,
            notificationShadeWindowController,
            configurationController,
            headsUpManager,
            shadeInteractor,
            { sceneInteractor },
            JavaAdapter(testScope.backgroundScope),
            mock<UnlockedScreenOffAnimationController>(),
            primaryBouncerInteractor,
            alternateBouncerInteractor,
        )
    }