• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.tiles.impl.irecording.domain.interactor
18 
19 import android.app.AlertDialog
20 import android.app.BroadcastOptions
21 import android.app.PendingIntent
22 import android.content.Intent
23 import android.util.Log
24 import com.android.internal.jank.InteractionJankMonitor
25 import com.android.systemui.animation.DialogCuj
26 import com.android.systemui.animation.DialogTransitionAnimator
27 import com.android.systemui.animation.Expandable
28 import com.android.systemui.dagger.qualifiers.Main
29 import com.android.systemui.plugins.ActivityStarter
30 import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
31 import com.android.systemui.qs.tiles.DELAY_MS
32 import com.android.systemui.qs.tiles.INTERVAL_MS
33 import com.android.systemui.qs.tiles.base.domain.interactor.QSTileUserActionInteractor
34 import com.android.systemui.qs.tiles.base.domain.model.QSTileInput
35 import com.android.systemui.qs.tiles.base.shared.model.QSTileUserAction
36 import com.android.systemui.qs.tiles.impl.irecording.data.model.IssueRecordingModel
37 import com.android.systemui.recordissue.IssueRecordingService.Companion.getStartIntent
38 import com.android.systemui.recordissue.IssueRecordingService.Companion.getStopIntent
39 import com.android.systemui.recordissue.IssueRecordingState
40 import com.android.systemui.recordissue.RecordIssueDialogDelegate
41 import com.android.systemui.recordissue.RecordIssueModule.Companion.TILE_SPEC
42 import com.android.systemui.screenrecord.RecordingController
43 import com.android.systemui.screenrecord.RecordingService
44 import com.android.systemui.settings.UserContextProvider
45 import com.android.systemui.statusbar.phone.KeyguardDismissUtil
46 import com.android.systemui.statusbar.policy.KeyguardStateController
47 import javax.inject.Inject
48 import kotlin.coroutines.CoroutineContext
49 import kotlinx.coroutines.withContext
50 
51 class IssueRecordingUserActionInteractor
52 @Inject
53 constructor(
54     @Main private val mainCoroutineContext: CoroutineContext,
55     private val state: IssueRecordingState,
56     private val keyguardDismissUtil: KeyguardDismissUtil,
57     private val keyguardStateController: KeyguardStateController,
58     private val dialogTransitionAnimator: DialogTransitionAnimator,
59     private val panelInteractor: PanelInteractor,
60     private val userContextProvider: UserContextProvider,
61     private val delegateFactory: RecordIssueDialogDelegate.Factory,
62     private val recordingController: RecordingController,
63 ) : QSTileUserActionInteractor<IssueRecordingModel> {
64 
handleInputnull65     override suspend fun handleInput(input: QSTileInput<IssueRecordingModel>) {
66         if (input.action is QSTileUserAction.Click) {
67             if (input.data.isRecording) {
68                 stopIssueRecordingService()
69             } else {
70                 withContext(mainCoroutineContext) { showPrompt(input.action.expandable) }
71             }
72         } else {
73             Log.v(TAG, "the RecordIssueTile doesn't handle ${input.action} events yet.")
74         }
75     }
76 
showPromptnull77     private fun showPrompt(expandable: Expandable?) {
78         val dialog: AlertDialog =
79             delegateFactory
80                 .create {
81                     startIssueRecordingService()
82                     dialogTransitionAnimator.disableAllCurrentDialogsExitAnimations()
83                     panelInteractor.collapsePanels()
84                 }
85                 .createDialog()
86         val dismissAction =
87             ActivityStarter.OnDismissAction {
88                 // We animate from the touched view only if we are not on the keyguard, given
89                 // that if we are we will dismiss it which will also collapse the shade.
90                 if (expandable != null && !keyguardStateController.isShowing) {
91                     expandable
92                         .dialogTransitionController(
93                             DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, TILE_SPEC)
94                         )
95                         ?.let { dialogTransitionAnimator.show(dialog, it) } ?: dialog.show()
96                 } else {
97                     dialog.show()
98                 }
99                 false
100             }
101         keyguardDismissUtil.executeWhenUnlocked(dismissAction, false, true)
102     }
103 
startIssueRecordingServicenull104     private fun startIssueRecordingService() =
105         recordingController.startCountdown(
106             DELAY_MS,
107             INTERVAL_MS,
108             pendingServiceIntent(
109                 getStartIntent(
110                     userContextProvider.userContext,
111                     state.traceConfig,
112                     state.recordScreen,
113                     state.takeBugreport,
114                 )
115             ),
116             pendingServiceIntent(getStopIntent(userContextProvider.userContext)),
117         )
118 
119     private fun stopIssueRecordingService() =
120         pendingServiceIntent(getStopIntent(userContextProvider.userContext))
121             .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
122 
pendingServiceIntentnull123     private fun pendingServiceIntent(action: Intent) =
124         PendingIntent.getService(
125             userContextProvider.userContext,
126             RecordingService.REQUEST_CODE,
127             action,
128             PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
129         )
130 
131     companion object {
132         private const val TAG = "IssueRecordingUserActionInteractor"
133     }
134 }
135