1 /*
<lambda>null2  * 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 package com.android.systemui.qs.footer.domain.interactor
18 
19 import android.app.admin.DevicePolicyEventLogger
20 import android.app.admin.DevicePolicyManager
21 import android.content.Context
22 import android.content.Intent
23 import android.content.IntentFilter
24 import android.os.UserHandle
25 import android.provider.Settings
26 import com.android.internal.jank.InteractionJankMonitor
27 import com.android.internal.logging.MetricsLogger
28 import com.android.internal.logging.UiEventLogger
29 import com.android.internal.logging.nano.MetricsProto
30 import com.android.internal.util.FrameworkStatsLog
31 import com.android.systemui.animation.Expandable
32 import com.android.systemui.broadcast.BroadcastDispatcher
33 import com.android.systemui.dagger.SysUISingleton
34 import com.android.systemui.dagger.qualifiers.Background
35 import com.android.systemui.globalactions.GlobalActionsDialogLite
36 import com.android.systemui.plugins.ActivityStarter
37 import com.android.systemui.qs.FgsManagerController
38 import com.android.systemui.qs.QSSecurityFooterUtils
39 import com.android.systemui.qs.footer.data.model.UserSwitcherStatusModel
40 import com.android.systemui.qs.footer.data.repository.ForegroundServicesRepository
41 import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig
42 import com.android.systemui.security.data.repository.SecurityRepository
43 import com.android.systemui.statusbar.policy.DeviceProvisionedController
44 import com.android.systemui.user.data.repository.UserSwitcherRepository
45 import com.android.systemui.user.domain.interactor.UserSwitcherInteractor
46 import javax.inject.Inject
47 import kotlinx.coroutines.CoroutineDispatcher
48 import kotlinx.coroutines.flow.Flow
49 import kotlinx.coroutines.flow.map
50 import kotlinx.coroutines.withContext
51 
52 /** Interactor for the footer actions business logic. */
53 interface FooterActionsInteractor {
54     /** The current [SecurityButtonConfig]. */
55     val securityButtonConfig: Flow<SecurityButtonConfig?>
56 
57     /** The number of packages with a service running in the foreground. */
58     val foregroundServicesCount: Flow<Int>
59 
60     /** Whether there are new packages with a service running in the foreground. */
61     val hasNewForegroundServices: Flow<Boolean>
62 
63     /** The current [UserSwitcherStatusModel]. */
64     val userSwitcherStatus: Flow<UserSwitcherStatusModel>
65 
66     /**
67      * The flow emitting `Unit` whenever a request to show the device monitoring dialog is fired.
68      */
69     val deviceMonitoringDialogRequests: Flow<Unit>
70 
71     /**
72      * Show the device monitoring dialog, expanded from [expandable] if it's not null.
73      *
74      * Important: [quickSettingsContext] *must* be the [Context] associated to the
75      * [Quick Settings fragment][com.android.systemui.qs.QSFragmentLegacy].
76      */
77     fun showDeviceMonitoringDialog(quickSettingsContext: Context, expandable: Expandable?)
78 
79     /** Show the foreground services dialog. */
80     fun showForegroundServicesDialog(expandable: Expandable)
81 
82     /** Show the power menu dialog. */
83     fun showPowerMenuDialog(
84         globalActionsDialogLite: GlobalActionsDialogLite,
85         expandable: Expandable,
86     )
87 
88     /** Show the settings. */
89     fun showSettings(expandable: Expandable)
90 
91     /** Show the user switcher. */
92     fun showUserSwitcher(expandable: Expandable)
93 }
94 
95 @SysUISingleton
96 class FooterActionsInteractorImpl
97 @Inject
98 constructor(
99     private val activityStarter: ActivityStarter,
100     private val metricsLogger: MetricsLogger,
101     private val uiEventLogger: UiEventLogger,
102     private val deviceProvisionedController: DeviceProvisionedController,
103     private val qsSecurityFooterUtils: QSSecurityFooterUtils,
104     private val fgsManagerController: FgsManagerController,
105     private val userSwitcherInteractor: UserSwitcherInteractor,
106     securityRepository: SecurityRepository,
107     foregroundServicesRepository: ForegroundServicesRepository,
108     userSwitcherRepository: UserSwitcherRepository,
109     broadcastDispatcher: BroadcastDispatcher,
110     @Background bgDispatcher: CoroutineDispatcher,
111 ) : FooterActionsInteractor {
112     override val securityButtonConfig: Flow<SecurityButtonConfig?> =
securitynull113         securityRepository.security.map { security ->
114             withContext(bgDispatcher) { qsSecurityFooterUtils.getButtonConfig(security) }
115         }
116 
117     override val foregroundServicesCount: Flow<Int> =
118         foregroundServicesRepository.foregroundServicesCount
119 
120     override val hasNewForegroundServices: Flow<Boolean> =
121         foregroundServicesRepository.hasNewChanges
122 
123     override val userSwitcherStatus: Flow<UserSwitcherStatusModel> =
124         userSwitcherRepository.userSwitcherStatus
125 
126     override val deviceMonitoringDialogRequests: Flow<Unit> =
127         broadcastDispatcher.broadcastFlow(
128             IntentFilter(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG),
129             UserHandle.ALL,
130             Context.RECEIVER_EXPORTED,
131             null,
132         )
133 
showDeviceMonitoringDialognull134     override fun showDeviceMonitoringDialog(
135         quickSettingsContext: Context,
136         expandable: Expandable?,
137     ) {
138         qsSecurityFooterUtils.showDeviceMonitoringDialog(quickSettingsContext, expandable)
139         if (expandable != null) {
140             DevicePolicyEventLogger.createEvent(
141                     FrameworkStatsLog.DEVICE_POLICY_EVENT__EVENT_ID__DO_USER_INFO_CLICKED
142                 )
143                 .write()
144         }
145     }
146 
showForegroundServicesDialognull147     override fun showForegroundServicesDialog(expandable: Expandable) {
148         fgsManagerController.showDialog(expandable)
149     }
150 
showPowerMenuDialognull151     override fun showPowerMenuDialog(
152         globalActionsDialogLite: GlobalActionsDialogLite,
153         expandable: Expandable,
154     ) {
155         uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
156         globalActionsDialogLite.showOrHideDialog(
157             /* keyguardShowing= */ false,
158             /* isDeviceProvisioned= */ true,
159             expandable,
160         )
161     }
162 
showSettingsnull163     override fun showSettings(expandable: Expandable) {
164         if (!deviceProvisionedController.isCurrentUserSetup) {
165             // If user isn't setup just unlock the device and dump them back at SUW.
166             activityStarter.postQSRunnableDismissingKeyguard {}
167             return
168         }
169 
170         metricsLogger.action(MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH)
171         activityStarter.startActivity(
172             Intent(Settings.ACTION_SETTINGS),
173             true /* dismissShade */,
174             expandable.activityTransitionController(
175                 InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON
176             ),
177         )
178     }
179 
showUserSwitchernull180     override fun showUserSwitcher(expandable: Expandable) {
181         userSwitcherInteractor.showUserSwitcher(expandable)
182     }
183 }
184