1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 @file:OptIn(ExperimentalFoundationApi::class)
18
19 package com.android.systemui.keyguard.ui.composable
20
21 import androidx.compose.foundation.ExperimentalFoundationApi
22 import androidx.compose.foundation.gestures.awaitEachGesture
23 import androidx.compose.foundation.gestures.awaitFirstDown
24 import androidx.compose.foundation.gestures.detectTapGestures
25 import androidx.compose.foundation.indication
26 import androidx.compose.foundation.interaction.MutableInteractionSource
27 import androidx.compose.foundation.layout.Box
28 import androidx.compose.foundation.layout.BoxScope
29 import androidx.compose.runtime.Composable
30 import androidx.compose.runtime.getValue
31 import androidx.compose.runtime.mutableStateOf
32 import androidx.compose.runtime.remember
33 import androidx.compose.ui.Modifier
34 import androidx.compose.ui.geometry.Rect
35 import androidx.compose.ui.input.pointer.pointerInput
36 import androidx.lifecycle.compose.collectAsStateWithLifecycle
37 import com.android.systemui.communal.ui.compose.extensions.detectLongPressGesture
38 import com.android.systemui.keyguard.ui.viewmodel.KeyguardTouchHandlingViewModel
39
40 /** Container for lockscreen content that handles long-press to bring up the settings menu. */
41 @Composable
42 // TODO(b/344879669): now that it's more generic than long-press, rename it.
LockscreenLongPressnull43 fun LockscreenLongPress(
44 viewModel: KeyguardTouchHandlingViewModel,
45 modifier: Modifier = Modifier,
46 content: @Composable BoxScope.(onSettingsMenuPlaces: (coordinates: Rect?) -> Unit) -> Unit,
47 ) {
48 val isEnabled: Boolean by
49 viewModel.isLongPressHandlingEnabled.collectAsStateWithLifecycle(initialValue = false)
50 val (settingsMenuBounds, setSettingsMenuBounds) = remember { mutableStateOf<Rect?>(null) }
51 val interactionSource = remember { MutableInteractionSource() }
52
53 Box(
54 modifier =
55 modifier
56 .pointerInput(isEnabled) {
57 if (isEnabled) {
58 detectLongPressGesture { viewModel.onLongPress(isA11yAction = false) }
59 }
60 }
61 .pointerInput(Unit) {
62 detectTapGestures(
63 onTap = { viewModel.onClick(it.x, it.y) },
64 onDoubleTap = { viewModel.onDoubleClick() },
65 )
66 }
67 .pointerInput(settingsMenuBounds) {
68 awaitEachGesture {
69 val pointerInputChange = awaitFirstDown()
70 if (settingsMenuBounds?.contains(pointerInputChange.position) == false) {
71 viewModel.onTouchedOutside()
72 }
73 }
74 }
75 // Passing null for the indication removes the ripple effect.
76 .indication(interactionSource, null)
77 ) {
78 content(setSettingsMenuBounds)
79 }
80 }
81