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.recordissue
18 
19 import android.app.IActivityManager
20 import android.app.NotificationManager
21 import android.content.Context
22 import android.content.Intent
23 import android.content.res.Resources
24 import android.net.Uri
25 import android.os.Handler
26 import android.os.UserHandle
27 import com.android.internal.logging.UiEventLogger
28 import com.android.systemui.animation.DialogTransitionAnimator
29 import com.android.systemui.dagger.qualifiers.LongRunning
30 import com.android.systemui.dagger.qualifiers.Main
31 import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
32 import com.android.systemui.res.R
33 import com.android.systemui.screenrecord.RecordingController
34 import com.android.systemui.screenrecord.RecordingService
35 import com.android.systemui.screenrecord.RecordingServiceStrings
36 import com.android.systemui.settings.UserContextProvider
37 import com.android.systemui.statusbar.phone.KeyguardDismissUtil
38 import java.util.concurrent.Executor
39 import javax.inject.Inject
40 
41 class IssueRecordingService
42 @Inject
43 constructor(
44     controller: RecordingController,
45     @LongRunning private val bgExecutor: Executor,
46     @Main handler: Handler,
47     uiEventLogger: UiEventLogger,
48     notificationManager: NotificationManager,
49     userContextProvider: UserContextProvider,
50     keyguardDismissUtil: KeyguardDismissUtil,
51     private val dialogTransitionAnimator: DialogTransitionAnimator,
52     private val panelInteractor: PanelInteractor,
53     private val traceurMessageSender: TraceurMessageSender,
54     private val issueRecordingState: IssueRecordingState,
55     private val iActivityManager: IActivityManager,
56 ) :
57     RecordingService(
58         controller,
59         bgExecutor,
60         handler,
61         uiEventLogger,
62         notificationManager,
63         userContextProvider,
64         keyguardDismissUtil
65     ) {
66 
getTagnull67     override fun getTag(): String = TAG
68 
69     override fun getChannelId(): String = CHANNEL_ID
70 
71     override fun provideRecordingServiceStrings(): RecordingServiceStrings = IrsStrings(resources)
72 
73     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
74         when (intent?.action) {
75             ACTION_START -> {
76                 bgExecutor.execute {
77                     traceurMessageSender.startTracing(issueRecordingState.traceType)
78                 }
79                 issueRecordingState.isRecording = true
80                 if (!issueRecordingState.recordScreen) {
81                     // If we don't want to record the screen, the ACTION_SHOW_START_NOTIF action
82                     // will circumvent the RecordingService's screen recording start code.
83                     return super.onStartCommand(Intent(ACTION_SHOW_START_NOTIF), flags, startId)
84                 }
85             }
86             ACTION_STOP,
87             ACTION_STOP_NOTIF -> {
88                 // ViewCapture needs to save it's data before it is disabled, or else the data will
89                 // be lost. This is expected to change in the near future, and when that happens
90                 // this line should be removed.
91                 bgExecutor.execute { traceurMessageSender.stopTracing() }
92                 issueRecordingState.isRecording = false
93             }
94             ACTION_SHARE -> {
95                 bgExecutor.execute {
96                     mNotificationManager.cancelAsUser(
97                         null,
98                         mNotificationId,
99                         UserHandle(mUserContextTracker.userContext.userId)
100                     )
101 
102                     val screenRecording = intent.getParcelableExtra(EXTRA_PATH, Uri::class.java)
103                     if (issueRecordingState.takeBugreport) {
104                         iActivityManager.requestBugReportWithExtraAttachment(screenRecording)
105                     } else {
106                         traceurMessageSender.shareTraces(applicationContext, screenRecording)
107                     }
108                 }
109 
110                 dialogTransitionAnimator.disableAllCurrentDialogsExitAnimations()
111                 panelInteractor.collapsePanels()
112 
113                 // Unlike all other actions, action_share has different behavior for the screen
114                 // recording qs tile than it does for the record issue qs tile. Return sticky to
115                 // avoid running any of the base class' code for this action.
116                 return START_STICKY
117             }
118             else -> {}
119         }
120         return super.onStartCommand(intent, flags, startId)
121     }
122 
123     companion object {
124         private const val TAG = "IssueRecordingService"
125         private const val CHANNEL_ID = "issue_record"
126 
127         /**
128          * Get an intent to stop the issue recording service.
129          *
130          * @param context Context from the requesting activity
131          * @return
132          */
getStopIntentnull133         fun getStopIntent(context: Context): Intent =
134             Intent(context, IssueRecordingService::class.java)
135                 .setAction(ACTION_STOP)
136                 .putExtra(Intent.EXTRA_USER_HANDLE, context.userId)
137 
138         /**
139          * Get an intent to start the issue recording service.
140          *
141          * @param context Context from the requesting activity
142          */
143         fun getStartIntent(context: Context): Intent =
144             Intent(context, IssueRecordingService::class.java).setAction(ACTION_START)
145     }
146 }
147 
148 private class IrsStrings(private val res: Resources) : RecordingServiceStrings(res) {
149     override val title
150         get() = res.getString(R.string.issuerecord_title)
151 
152     override val notificationChannelDescription
153         get() = res.getString(R.string.issuerecord_channel_description)
154 
155     override val startErrorResId
156         get() = R.string.issuerecord_start_error
157 
158     override val startError
159         get() = res.getString(R.string.issuerecord_start_error)
160 
161     override val saveErrorResId
162         get() = R.string.issuerecord_save_error
163 
164     override val saveError
165         get() = res.getString(R.string.issuerecord_save_error)
166 
167     override val ongoingRecording
168         get() = res.getString(R.string.issuerecord_ongoing_screen_only)
169 
170     override val backgroundProcessingLabel
171         get() = res.getString(R.string.issuerecord_background_processing_label)
172 
173     override val saveTitle
174         get() = res.getString(R.string.issuerecord_save_title)
175 }
176