• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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 
18 package com.android.systemui.keyguard.ui.binder
19 
20 import android.graphics.Rect
21 import android.util.TypedValue
22 import android.view.View
23 import android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED
24 import android.widget.TextView
25 import androidx.core.view.isVisible
26 import androidx.lifecycle.Lifecycle
27 import androidx.lifecycle.repeatOnLifecycle
28 import com.android.app.tracing.coroutines.launchTraced as launch
29 import com.android.systemui.Flags
30 import com.android.systemui.animation.ActivityTransitionAnimator
31 import com.android.systemui.common.ui.binder.IconViewBinder
32 import com.android.systemui.common.ui.binder.TextViewBinder
33 import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
34 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsMenuViewModel
35 import com.android.systemui.keyguard.ui.viewmodel.KeyguardTouchHandlingViewModel
36 import com.android.systemui.keyguard.util.WallpaperPickerIntentUtils
37 import com.android.systemui.keyguard.util.WallpaperPickerIntentUtils.LAUNCH_SOURCE_KEYGUARD
38 import com.android.systemui.lifecycle.repeatWhenAttached
39 import com.android.systemui.plugins.ActivityStarter
40 import com.android.systemui.res.R
41 import com.android.systemui.statusbar.VibratorHelper
42 import kotlinx.coroutines.DisposableHandle
43 import kotlinx.coroutines.flow.distinctUntilChanged
44 import kotlinx.coroutines.flow.filter
45 import kotlinx.coroutines.flow.filterNotNull
46 
47 object KeyguardSettingsViewBinder {
48     fun bind(
49         view: View,
50         viewModel: KeyguardSettingsMenuViewModel,
51         touchHandlingViewModel: KeyguardTouchHandlingViewModel,
52         rootViewModel: KeyguardRootViewModel?,
53         vibratorHelper: VibratorHelper,
54         activityStarter: ActivityStarter,
55     ): DisposableHandle {
56         val disposableHandle =
57             view.repeatWhenAttached {
58                 repeatOnLifecycle(Lifecycle.State.STARTED) {
59                     launch("$TAG#viewModel.isVisible") {
60                         viewModel.isVisible.distinctUntilChanged().collect { isVisible ->
61                             view.animateVisibility(visible = isVisible)
62                             if (isVisible) {
63                                 if (!Flags.msdlFeedback()) {
64                                     vibratorHelper.vibrate(KeyguardBottomAreaVibrations.Activated)
65                                 }
66                                 val textView = view.requireViewById(R.id.text) as TextView
67                                 view.setOnTouchListener(
68                                     KeyguardSettingsButtonOnTouchListener(viewModel = viewModel)
69                                 )
70                                 IconViewBinder.bind(
71                                     icon = viewModel.icon,
72                                     view = view.requireViewById(R.id.icon),
73                                 )
74                                 TextViewBinder.bind(view = textView, viewModel = viewModel.text)
75                                 textView.sendAccessibilityEvent(TYPE_VIEW_FOCUSED)
76                             }
77                         }
78                     }
79 
80                     // activityStarter will only be null when rendering the preview that
81                     // shows up in the Wallpaper Picker app. If we do that, then the
82                     // settings menu should never be visible.
83                     if (activityStarter != null) {
84                         launch("$TAG#viewModel.shouldOpenSettings") {
85                             viewModel.shouldOpenSettings
86                                 .filter { it }
87                                 .collect {
88                                     navigateToLockScreenSettings(
89                                         activityStarter = activityStarter,
90                                         view = view,
91                                     )
92                                     viewModel.onSettingsShown()
93                                 }
94                         }
95                     }
96 
97                     launch("$TAG#rootViewModel?.lastRootViewTapPosition") {
98                         rootViewModel?.lastRootViewTapPosition?.filterNotNull()?.collect { point ->
99                             if (view.isVisible) {
100                                 val hitRect = Rect()
101                                 view.getHitRect(hitRect)
102                                 if (!hitRect.contains(point.x, point.y)) {
103                                     touchHandlingViewModel.onTouchedOutside()
104                                 }
105                             }
106                         }
107                     }
108 
109                     launch("$TAG#viewModel.textSize") {
110                         viewModel.textSize.collect { textSize ->
111                             val textView: TextView = view.requireViewById(R.id.text)
112                             textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize.toFloat())
113                         }
114                     }
115                 }
116             }
117         return disposableHandle
118     }
119 
120     /** Opens the wallpaper picker screen after the device is unlocked by the user. */
121     private fun navigateToLockScreenSettings(activityStarter: ActivityStarter, view: View) {
122         activityStarter.postStartActivityDismissingKeyguard(
123             WallpaperPickerIntentUtils.getIntent(view.context, LAUNCH_SOURCE_KEYGUARD),
124             /* delay= */ 0,
125             /* animationController= */ ActivityTransitionAnimator.Controller.fromView(view),
126             /* customMessage= */ view.context.getString(R.string.keyguard_unlock_to_customize_ls),
127         )
128     }
129 
130     private fun View.animateVisibility(visible: Boolean) {
131         animate()
132             .withStartAction {
133                 if (visible) {
134                     alpha = 0f
135                     isVisible = true
136                 }
137             }
138             .alpha(if (visible) 1f else 0f)
139             .withEndAction {
140                 if (!visible) {
141                     isVisible = false
142                 }
143             }
144             .start()
145     }
146 
147     private const val TAG = "KeyguardSettingsViewBinder"
148 }
149