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 package com.android.systemui.back.domain.interactor 18 19 import android.window.BackEvent 20 import android.window.OnBackAnimationCallback 21 import android.window.OnBackInvokedCallback 22 import android.window.OnBackInvokedDispatcher 23 import android.window.WindowOnBackInvokedDispatcher 24 import com.android.systemui.CoreStartable 25 import com.android.systemui.Flags.predictiveBackAnimateShade 26 import com.android.systemui.dagger.SysUISingleton 27 import com.android.systemui.dagger.qualifiers.Application 28 import com.android.systemui.plugins.statusbar.StatusBarStateController 29 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor 30 import com.android.systemui.shade.QuickSettingsController 31 import com.android.systemui.shade.ShadeController 32 import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor 33 import com.android.systemui.statusbar.NotificationShadeWindowController 34 import com.android.systemui.statusbar.StatusBarState 35 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager 36 import javax.inject.Inject 37 import kotlinx.coroutines.CoroutineScope 38 import kotlinx.coroutines.launch 39 40 /** Handles requests to go back either from a button or gesture. */ 41 @SysUISingleton 42 class BackActionInteractor 43 @Inject 44 constructor( 45 @Application private val scope: CoroutineScope, 46 private val statusBarStateController: StatusBarStateController, 47 private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager, 48 private val shadeController: ShadeController, 49 private val notificationShadeWindowController: NotificationShadeWindowController, 50 private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor 51 ) : CoreStartable { 52 53 private var isCallbackRegistered = false 54 55 private val callback = 56 if (predictiveBackAnimateShade()) { 57 /** 58 * New callback that handles back gesture invoked, cancel, progress and provides 59 * feedback via Shade animation. 60 */ 61 object : OnBackAnimationCallback { 62 override fun onBackInvoked() { 63 onBackRequested() 64 } 65 66 override fun onBackProgressed(backEvent: BackEvent) { 67 if (shouldBackBeHandled() && shadeBackActionInteractor.canBeCollapsed()) { 68 shadeBackActionInteractor.onBackProgressed(backEvent.progress) 69 } 70 } 71 } 72 } else { 73 OnBackInvokedCallback { onBackRequested() } 74 } 75 76 private val onBackInvokedDispatcher: WindowOnBackInvokedDispatcher? 77 get() = 78 notificationShadeWindowController.windowRootView?.viewRootImpl?.onBackInvokedDispatcher 79 80 private lateinit var shadeBackActionInteractor: ShadeBackActionInteractor 81 private lateinit var qsController: QuickSettingsController 82 83 fun setup(qsController: QuickSettingsController, svController: ShadeBackActionInteractor) { 84 this.qsController = qsController 85 this.shadeBackActionInteractor = svController 86 } 87 88 override fun start() { 89 scope.launch { 90 windowRootViewVisibilityInteractor.isLockscreenOrShadeVisibleAndInteractive.collect { 91 visible -> 92 if (visible) { 93 registerBackCallback() 94 } else { 95 unregisterBackCallback() 96 } 97 } 98 } 99 } 100 101 fun shouldBackBeHandled(): Boolean { 102 return statusBarStateController.state != StatusBarState.KEYGUARD && 103 statusBarStateController.state != StatusBarState.SHADE_LOCKED && 104 !statusBarKeyguardViewManager.isBouncerShowingOverDream 105 } 106 107 fun onBackRequested(): Boolean { 108 if (statusBarKeyguardViewManager.canHandleBackPressed()) { 109 statusBarKeyguardViewManager.onBackPressed() 110 return true 111 } 112 if (qsController.isCustomizing) { 113 qsController.closeQsCustomizer() 114 return true 115 } 116 if (qsController.expanded) { 117 shadeBackActionInteractor.animateCollapseQs(false) 118 return true 119 } 120 if (shadeBackActionInteractor.closeUserSwitcherIfOpen()) { 121 return true 122 } 123 if (shouldBackBeHandled()) { 124 if (shadeBackActionInteractor.canBeCollapsed()) { 125 // this is the Shade dismiss animation, so make sure QQS closes when it ends. 126 shadeBackActionInteractor.onBackPressed() 127 shadeController.animateCollapseShade() 128 } 129 return true 130 } 131 return false 132 } 133 134 private fun registerBackCallback() { 135 if (isCallbackRegistered) { 136 return 137 } 138 onBackInvokedDispatcher?.let { 139 it.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT, callback) 140 isCallbackRegistered = true 141 } 142 } 143 144 private fun unregisterBackCallback() { 145 if (!isCallbackRegistered) { 146 return 147 } 148 onBackInvokedDispatcher?.let { 149 it.unregisterOnBackInvokedCallback(callback) 150 isCallbackRegistered = false 151 } 152 } 153 } 154