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

Commit f9ae30cb authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

[flexiglass] Adds long-press settings menu support to lockscreen scene.

Bug: 280879610
Test: manually verified that long-pressing on empty spot in the
lockscreen shows the lockscreen settings menu and clicking it opens the
wallpaper picker. Manually verified the touching outside the settings
menu dismisses it.

Change-Id: I49c77e9073a280716b05a3ef22c4044a4af258f1
parent 64a34b69
Loading
Loading
Loading
Loading
+76 −12
Original line number Original line Diff line number Diff line
@@ -14,20 +14,33 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


@file:OptIn(ExperimentalCoroutinesApi::class)
@file:OptIn(ExperimentalCoroutinesApi::class, ExperimentalFoundationApi::class)


package com.android.systemui.keyguard.ui.composable
package com.android.systemui.keyguard.ui.composable


import android.view.View
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.isVisible
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.qualifiers.KeyguardRootView
import com.android.systemui.keyguard.qualifiers.KeyguardRootView
import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneKey
@@ -68,6 +81,7 @@ constructor(
    ) {
    ) {
        LockscreenScene(
        LockscreenScene(
            viewProvider = viewProvider,
            viewProvider = viewProvider,
            longPressViewModel = viewModel.longPress,
            modifier = modifier,
            modifier = modifier,
        )
        )
    }
    }
@@ -85,19 +99,69 @@ constructor(
@Composable
@Composable
private fun LockscreenScene(
private fun LockscreenScene(
    viewProvider: () -> View,
    viewProvider: () -> View,
    longPressViewModel: KeyguardLongPressViewModel,
    modifier: Modifier = Modifier,
    modifier: Modifier = Modifier,
) {
) {
    var settingsMenu: View? = null

    Box(
        modifier = modifier,
    ) {
        LongPressSurface(
            viewModel = longPressViewModel,
            isSettingsMenuVisible = { settingsMenu?.isVisible == true },
            settingsMenuBounds = {
                val bounds = android.graphics.Rect()
                settingsMenu?.getHitRect(bounds)
                bounds.toComposeRect()
            },
            modifier = Modifier.fillMaxSize(),
        )

        AndroidView(
        AndroidView(
            factory = { _ ->
            factory = { _ ->
                val keyguardRootView = viewProvider()
                val keyguardRootView = viewProvider()
            // Remove the KeyguardRootView from any parent it might already have in legacy code just
                // Remove the KeyguardRootView from any parent it might already have in legacy code
            // in case (a view can't have two parents).
                // just in case (a view can't have two parents).
                (keyguardRootView.parent as? ViewGroup)?.removeView(keyguardRootView)
                (keyguardRootView.parent as? ViewGroup)?.removeView(keyguardRootView)
                settingsMenu = keyguardRootView.requireViewById(R.id.keyguard_settings_button)
                keyguardRootView
                keyguardRootView
            },
            },
            update = { keyguardRootView ->
            update = { keyguardRootView ->
                keyguardRootView.requireViewById<View>(R.id.lock_icon_view)
                keyguardRootView.requireViewById<View>(R.id.lock_icon_view)
            },
            },
        modifier = modifier,
            modifier = Modifier.fillMaxSize(),
        )
    }
}

@Composable
private fun LongPressSurface(
    viewModel: KeyguardLongPressViewModel,
    isSettingsMenuVisible: () -> Boolean,
    settingsMenuBounds: () -> Rect,
    modifier: Modifier = Modifier,
) {
    val isEnabled: Boolean by viewModel.isLongPressHandlingEnabled.collectAsState(initial = false)

    Box(
        modifier =
            modifier
                .combinedClickable(
                    enabled = isEnabled,
                    onLongClick = viewModel::onLongPress,
                    onClick = {},
                )
                .pointerInput(Unit) {
                    awaitEachGesture {
                        val pointerInputChange = awaitFirstDown()
                        if (
                            isSettingsMenuVisible() &&
                                !settingsMenuBounds().contains(pointerInputChange.position)
                        ) {
                            viewModel.onTouchedOutside()
                        }
                    }
                },
    )
    )
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ class LockscreenSceneViewModel
@Inject
@Inject
constructor(
constructor(
    authenticationInteractor: AuthenticationInteractor,
    authenticationInteractor: AuthenticationInteractor,
    val longPress: KeyguardLongPressViewModel,
) {
) {
    /** The key of the scene we should switch to when swiping up. */
    /** The key of the scene we should switch to when swiping up. */
    val upDestinationSceneKey: Flow<SceneKey> =
    val upDestinationSceneKey: Flow<SceneKey> =
+5 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.Test
@@ -44,6 +45,10 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
    private val underTest =
    private val underTest =
        LockscreenSceneViewModel(
        LockscreenSceneViewModel(
            authenticationInteractor = authenticationInteractor,
            authenticationInteractor = authenticationInteractor,
            longPress =
                KeyguardLongPressViewModel(
                    interactor = mock(),
                ),
        )
        )


    @Test
    @Test
+5 −0
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
import com.android.systemui.model.SysUiState
import com.android.systemui.model.SysUiState
import com.android.systemui.scene.SceneTestUtils.Companion.toDataLayer
import com.android.systemui.scene.SceneTestUtils.Companion.toDataLayer
@@ -118,6 +119,10 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
    private val lockscreenSceneViewModel =
    private val lockscreenSceneViewModel =
        LockscreenSceneViewModel(
        LockscreenSceneViewModel(
            authenticationInteractor = authenticationInteractor,
            authenticationInteractor = authenticationInteractor,
            longPress =
                KeyguardLongPressViewModel(
                    interactor = mock(),
                ),
        )
        )


    private val shadeSceneViewModel =
    private val shadeSceneViewModel =