1 package com.android.systemui.biometrics 2 3 import android.annotation.AnyThread 4 import android.annotation.MainThread 5 import android.util.Log 6 import com.android.systemui.dagger.qualifiers.Main 7 import com.android.systemui.shade.ShadeExpansionChangeEvent 8 import com.android.systemui.shade.ShadeExpansionStateManager 9 import java.util.concurrent.Executor 10 import javax.inject.Inject 11 12 class AuthDialogPanelInteractionDetector 13 @Inject 14 constructor( 15 private val shadeExpansionStateManager: ShadeExpansionStateManager, 16 @Main private val mainExecutor: Executor, 17 ) { 18 private var action: Action? = null 19 private var panelState: Int = -1 20 21 @MainThread 22 fun enable(onPanelInteraction: Runnable) { 23 if (action == null) { 24 action = Action(onPanelInteraction) 25 shadeExpansionStateManager.addStateListener(this::onPanelStateChanged) 26 shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged) 27 } else { 28 Log.e(TAG, "Already enabled") 29 } 30 } 31 32 @MainThread 33 fun disable() { 34 if (action != null) { 35 Log.i(TAG, "Disable dectector") 36 action = null 37 panelState = -1 38 shadeExpansionStateManager.removeStateListener(this::onPanelStateChanged) 39 shadeExpansionStateManager.removeExpansionListener(this::onPanelExpansionChanged) 40 } 41 } 42 43 @AnyThread 44 private fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) = 45 mainExecutor.execute { 46 action?.let { 47 if (event.tracking || (event.expanded && event.fraction > 0 && panelState == 1)) { 48 Log.i(TAG, "onPanelExpansionChanged, event: $event") 49 it.onPanelInteraction.run() 50 disable() 51 } 52 } 53 } 54 55 @AnyThread 56 private fun onPanelStateChanged(state: Int) = 57 mainExecutor.execute { 58 // When device owner set screen lock type as Swipe, and install work profile with 59 // pin/pattern/password & fingerprint or face, if work profile allow user to verify 60 // by BP, it is possible that BP will be displayed when keyguard is closing, in this 61 // case event.expanded = true and event.fraction > 0, so BP will be closed, adding 62 // panel state into consideration is workaround^2, this workaround works because 63 // onPanelStateChanged is earlier than onPanelExpansionChanged 64 65 // we don't want to close BP in below case 66 // 67 // | Action | tracking | expanded | fraction | panelState | 68 // | HeadsUp | NA | NA | NA | 1 | 69 // | b/285111529 | false | true | > 0 | 2 | 70 71 // Note: HeadsUp behavior was changed, so we can't got onPanelExpansionChanged now 72 panelState = state 73 Log.i(TAG, "onPanelStateChanged, state: $state") 74 } 75 } 76 77 private data class Action(val onPanelInteraction: Runnable) 78 79 private const val TAG = "AuthDialogPanelInteractionDetector" 80