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.keyguard.shared.quickaffordance.ActivationState 30 import com.android.systemui.statusbar.policy.FlashlightController 31 import javax.inject.Inject 32 import kotlinx.coroutines.channels.awaitClose 33 import kotlinx.coroutines.flow.Flow 34 35 @SysUISingleton 36 class FlashlightQuickAffordanceConfig 37 @Inject 38 constructor( 39 @Application private val context: Context, 40 private val flashlightController: FlashlightController, 41 ) : KeyguardQuickAffordanceConfig { 42 43 private sealed class FlashlightState { 44 toLockScreenStatenull45 abstract fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState 46 47 object On : FlashlightState() { 48 override fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState = 49 KeyguardQuickAffordanceConfig.LockScreenState.Visible( 50 Icon.Resource( 51 R.drawable.qs_flashlight_icon_on, 52 ContentDescription.Resource(R.string.quick_settings_flashlight_label) 53 ), 54 ActivationState.Active 55 ) 56 } 57 58 object OffAvailable : FlashlightState() { toLockScreenStatenull59 override fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState = 60 KeyguardQuickAffordanceConfig.LockScreenState.Visible( 61 Icon.Resource( 62 R.drawable.qs_flashlight_icon_off, 63 ContentDescription.Resource(R.string.quick_settings_flashlight_label) 64 ), 65 ActivationState.Inactive 66 ) 67 } 68 69 object Unavailable : FlashlightState() { 70 override fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState = 71 KeyguardQuickAffordanceConfig.LockScreenState.Hidden 72 } 73 } 74 75 override val key: String 76 get() = BuiltInKeyguardQuickAffordanceKeys.FLASHLIGHT 77 78 override val pickerName: String 79 get() = context.getString(R.string.quick_settings_flashlight_label) 80 81 override val pickerIconResourceId: Int 82 get() = R.drawable.ic_flashlight_off 83 84 override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> = <lambda>null85 conflatedCallbackFlow { 86 val flashlightCallback = 87 object : FlashlightController.FlashlightListener { 88 override fun onFlashlightChanged(enabled: Boolean) { 89 trySendWithFailureLogging( 90 if (enabled) { 91 FlashlightState.On.toLockScreenState() 92 } else { 93 FlashlightState.OffAvailable.toLockScreenState() 94 }, 95 TAG 96 ) 97 } 98 99 override fun onFlashlightError() { 100 trySendWithFailureLogging( 101 FlashlightState.OffAvailable.toLockScreenState(), 102 TAG 103 ) 104 } 105 106 override fun onFlashlightAvailabilityChanged(available: Boolean) { 107 trySendWithFailureLogging( 108 if (!available) { 109 FlashlightState.Unavailable.toLockScreenState() 110 } else { 111 if (flashlightController.isEnabled) { 112 FlashlightState.On.toLockScreenState() 113 } else { 114 FlashlightState.OffAvailable.toLockScreenState() 115 } 116 }, 117 TAG 118 ) 119 } 120 } 121 122 flashlightController.addCallback(flashlightCallback) 123 124 awaitClose { flashlightController.removeCallback(flashlightCallback) } 125 } 126 onTriggerednull127 override fun onTriggered( 128 expandable: Expandable? 129 ): KeyguardQuickAffordanceConfig.OnTriggeredResult { 130 flashlightController.setFlashlight( 131 flashlightController.isAvailable && !flashlightController.isEnabled 132 ) 133 return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled 134 } 135 getPickerScreenStatenull136 override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState = 137 if (flashlightController.isAvailable) { 138 KeyguardQuickAffordanceConfig.PickerScreenState.Default() 139 } else { 140 KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice 141 } 142 143 companion object { 144 private const val TAG = "FlashlightQuickAffordanceConfig" 145 } 146 } 147