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.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 45 override val pickerName = 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> = <lambda>null50 conflatedCallbackFlow { 51 val callback = 52 object : QRCodeScannerController.Callback { 53 override fun onQRCodeScannerActivityChanged() { 54 trySendWithFailureLogging(state(), TAG) 55 } 56 override fun onQRCodeScannerPreferenceChanged() { 57 trySendWithFailureLogging(state(), TAG) 58 } 59 } 60 61 controller.addCallback(callback) 62 controller.registerQRCodeScannerChangeObservers( 63 QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE, 64 QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE 65 ) 66 // Registering does not push an initial update. 67 trySendWithFailureLogging(state(), "initial state", TAG) 68 69 awaitClose { 70 controller.unregisterQRCodeScannerChangeObservers( 71 QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE, 72 QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE 73 ) 74 controller.removeCallback(callback) 75 } 76 } 77 getPickerScreenStatenull78 override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { 79 return when { 80 !controller.isAvailableOnDevice -> 81 KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice 82 !controller.isAbleToOpenCameraApp -> 83 KeyguardQuickAffordanceConfig.PickerScreenState.Disabled( 84 instructions = 85 listOf( 86 context.getString( 87 R.string 88 .keyguard_affordance_enablement_dialog_qr_scanner_instruction 89 ), 90 ), 91 ) 92 else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default() 93 } 94 } 95 onTriggerednull96 override fun onTriggered( 97 expandable: Expandable?, 98 ): KeyguardQuickAffordanceConfig.OnTriggeredResult { 99 return KeyguardQuickAffordanceConfig.OnTriggeredResult.StartActivity( 100 intent = controller.intent, 101 canShowWhileLocked = true, 102 ) 103 } 104 statenull105 private fun state(): KeyguardQuickAffordanceConfig.LockScreenState { 106 return if (controller.isEnabledForLockScreenButton) { 107 KeyguardQuickAffordanceConfig.LockScreenState.Visible( 108 icon = 109 Icon.Resource( 110 res = R.drawable.ic_qr_code_scanner, 111 contentDescription = 112 ContentDescription.Resource( 113 res = R.string.accessibility_qr_code_scanner_button, 114 ), 115 ), 116 ) 117 } else { 118 KeyguardQuickAffordanceConfig.LockScreenState.Hidden 119 } 120 } 121 122 companion object { 123 private const val TAG = "QrCodeScannerKeyguardQuickAffordanceConfig" 124 } 125 } 126