1 /*
2  * Copyright (C) 2022 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.data.quickaffordance
19 
20 import android.content.Context
21 import com.android.systemui.res.R
22 import com.android.systemui.animation.Expandable
23 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
24 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
25 import com.android.systemui.common.shared.model.ContentDescription
26 import com.android.systemui.common.shared.model.Icon
27 import com.android.systemui.dagger.SysUISingleton
28 import com.android.systemui.dagger.qualifiers.Application
29 import com.android.systemui.qrcodescanner.controller.QRCodeScannerController
30 import javax.inject.Inject
31 import kotlinx.coroutines.channels.awaitClose
32 import kotlinx.coroutines.flow.Flow
33 
34 /** QR code scanner quick affordance data source. */
35 @SysUISingleton
36 class QrCodeScannerKeyguardQuickAffordanceConfig
37 @Inject
38 constructor(
39     @Application private val context: Context,
40     private val controller: QRCodeScannerController,
41 ) : KeyguardQuickAffordanceConfig {
42 
43     override val key: String = BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER
44 
pickerNamenull45     override fun pickerName(): String = context.getString(R.string.qr_code_scanner_title)
46 
47     override val pickerIconResourceId = R.drawable.ic_qr_code_scanner
48 
49     override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
50         conflatedCallbackFlow {
51             val callback =
52                 object : QRCodeScannerController.Callback {
53                     override fun onQRCodeScannerActivityChanged() {
54                         trySendWithFailureLogging(state(), TAG)
55                     }
56 
57                     override fun onQRCodeScannerPreferenceChanged() {
58                         trySendWithFailureLogging(state(), TAG)
59                     }
60                 }
61 
62             controller.addCallback(callback)
63             controller.registerQRCodeScannerChangeObservers(
64                 QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
65                 QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE
66             )
67             // Registering does not push an initial update.
68             trySendWithFailureLogging(state(), "initial state", TAG)
69 
70             awaitClose {
71                 controller.unregisterQRCodeScannerChangeObservers(
72                     QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
73                     QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE
74                 )
75                 controller.removeCallback(callback)
76             }
77         }
78 
getPickerScreenStatenull79     override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
80         return when {
81             !isEnabledForPickerStateOption() ->
82                 KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
83             else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default()
84         }
85     }
86 
onTriggerednull87     override fun onTriggered(
88         expandable: Expandable?,
89     ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
90         return KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity(
91             intent = controller.intent,
92             canShowWhileLocked = true,
93         )
94     }
95 
statenull96     private fun state(): KeyguardQuickAffordanceConfig.LockScreenState {
97         return if (controller.isEnabledForLockScreenButton) {
98             KeyguardQuickAffordanceConfig.LockScreenState.Visible(
99                 icon =
100                     Icon.Resource(
101                         res = R.drawable.ic_qr_code_scanner,
102                         contentDescription =
103                             ContentDescription.Resource(
104                                 res = R.string.accessibility_qr_code_scanner_button,
105                             ),
106                     ),
107             )
108         } else {
109             KeyguardQuickAffordanceConfig.LockScreenState.Hidden
110         }
111     }
112 
113     /** Returns whether QR scanner be shown as one of available lockscreen shortcut option. */
isEnabledForPickerStateOptionnull114     private fun isEnabledForPickerStateOption(): Boolean {
115         return controller.isAbleToLaunchScannerActivity && controller.isAllowedOnLockScreen
116     }
117 
118     companion object {
119         private const val TAG = "QrCodeScannerKeyguardQuickAffordanceConfig"
120     }
121 }
122