Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 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.screenrecord; |
| 18 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 19 | import android.app.Notification; |
| 20 | import android.app.NotificationChannel; |
| 21 | import android.app.NotificationManager; |
| 22 | import android.app.PendingIntent; |
| 23 | import android.app.Service; |
Beth Thibodeau | eb48d0a | 2019-07-24 15:23:54 -0400 | [diff] [blame] | 24 | import android.content.ContentResolver; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 25 | import android.content.Context; |
| 26 | import android.content.Intent; |
Beth Thibodeau | 630225c | 2020-02-04 17:16:45 -0500 | [diff] [blame] | 27 | import android.content.res.Resources; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 28 | import android.graphics.Bitmap; |
| 29 | import android.graphics.drawable.Icon; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 30 | import android.media.MediaRecorder; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 31 | import android.net.Uri; |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 32 | import android.os.Bundle; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 33 | import android.os.IBinder; |
Beth Thibodeau | 630225c | 2020-02-04 17:16:45 -0500 | [diff] [blame] | 34 | import android.os.RemoteException; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 35 | import android.provider.Settings; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 36 | import android.util.Log; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 37 | import android.widget.Toast; |
| 38 | |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 39 | import com.android.internal.annotations.VisibleForTesting; |
| 40 | import com.android.internal.logging.UiEventLogger; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 41 | import com.android.systemui.R; |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 42 | import com.android.systemui.dagger.qualifiers.LongRunning; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 43 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 44 | import java.io.IOException; |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 45 | import java.util.concurrent.Executor; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 46 | |
Beth Thibodeau | 77c2545 | 2020-01-09 14:33:47 -0500 | [diff] [blame] | 47 | import javax.inject.Inject; |
| 48 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 49 | /** |
| 50 | * A service which records the device screen and optionally microphone input. |
| 51 | */ |
Beth Thibodeau | 26fefde | 2020-02-21 16:04:41 -0500 | [diff] [blame] | 52 | public class RecordingService extends Service implements MediaRecorder.OnInfoListener { |
Beth Thibodeau | 77c2545 | 2020-01-09 14:33:47 -0500 | [diff] [blame] | 53 | public static final int REQUEST_CODE = 2; |
| 54 | |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 55 | private static final int NOTIFICATION_RECORDING_ID = 4274; |
| 56 | private static final int NOTIFICATION_PROCESSING_ID = 4275; |
| 57 | private static final int NOTIFICATION_VIEW_ID = 4273; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 58 | private static final String TAG = "RecordingService"; |
| 59 | private static final String CHANNEL_ID = "screen_record"; |
| 60 | private static final String EXTRA_RESULT_CODE = "extra_resultCode"; |
| 61 | private static final String EXTRA_DATA = "extra_data"; |
| 62 | private static final String EXTRA_PATH = "extra_path"; |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 63 | private static final String EXTRA_AUDIO_SOURCE = "extra_useAudio"; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 64 | private static final String EXTRA_SHOW_TAPS = "extra_showTaps"; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 65 | |
| 66 | private static final String ACTION_START = "com.android.systemui.screenrecord.START"; |
| 67 | private static final String ACTION_STOP = "com.android.systemui.screenrecord.STOP"; |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 68 | private static final String ACTION_STOP_NOTIF = |
| 69 | "com.android.systemui.screenrecord.STOP_FROM_NOTIF"; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 70 | private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE"; |
| 71 | private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE"; |
| 72 | |
Beth Thibodeau | 77c2545 | 2020-01-09 14:33:47 -0500 | [diff] [blame] | 73 | private final RecordingController mController; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 74 | |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 75 | private ScreenRecordingAudioSource mAudioSource; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 76 | private boolean mShowTaps; |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 77 | private boolean mOriginalShowTaps; |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 78 | private ScreenMediaRecorder mRecorder; |
| 79 | private final Executor mLongExecutor; |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 80 | private final UiEventLogger mUiEventLogger; |
| 81 | private final NotificationManager mNotificationManager; |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 82 | |
Beth Thibodeau | 77c2545 | 2020-01-09 14:33:47 -0500 | [diff] [blame] | 83 | @Inject |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 84 | public RecordingService(RecordingController controller, @LongRunning Executor executor, |
| 85 | UiEventLogger uiEventLogger, NotificationManager notificationManager) { |
Beth Thibodeau | 77c2545 | 2020-01-09 14:33:47 -0500 | [diff] [blame] | 86 | mController = controller; |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 87 | mLongExecutor = executor; |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 88 | mUiEventLogger = uiEventLogger; |
| 89 | mNotificationManager = notificationManager; |
Beth Thibodeau | 77c2545 | 2020-01-09 14:33:47 -0500 | [diff] [blame] | 90 | } |
| 91 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 92 | /** |
| 93 | * Get an intent to start the recording service. |
| 94 | * |
| 95 | * @param context Context from the requesting activity |
| 96 | * @param resultCode The result code from {@link android.app.Activity#onActivityResult(int, int, |
| 97 | * android.content.Intent)} |
| 98 | * @param data The data from {@link android.app.Activity#onActivityResult(int, int, |
| 99 | * android.content.Intent)} |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 100 | * @param audioSource The ordinal value of the audio source |
| 101 | * {@link com.android.systemui.screenrecord.ScreenRecordingAudioSource} |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 102 | * @param showTaps True to make touches visible while recording |
| 103 | */ |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 104 | public static Intent getStartIntent(Context context, int resultCode, |
| 105 | int audioSource, boolean showTaps) { |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 106 | return new Intent(context, RecordingService.class) |
| 107 | .setAction(ACTION_START) |
| 108 | .putExtra(EXTRA_RESULT_CODE, resultCode) |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 109 | .putExtra(EXTRA_AUDIO_SOURCE, audioSource) |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 110 | .putExtra(EXTRA_SHOW_TAPS, showTaps); |
| 111 | } |
| 112 | |
| 113 | @Override |
| 114 | public int onStartCommand(Intent intent, int flags, int startId) { |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 115 | if (intent == null) { |
| 116 | return Service.START_NOT_STICKY; |
| 117 | } |
| 118 | String action = intent.getAction(); |
Beth Thibodeau | 11e6cbf | 2019-08-08 14:52:24 -0400 | [diff] [blame] | 119 | Log.d(TAG, "onStartCommand " + action); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 120 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 121 | switch (action) { |
| 122 | case ACTION_START: |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 123 | mAudioSource = ScreenRecordingAudioSource |
| 124 | .values()[intent.getIntExtra(EXTRA_AUDIO_SOURCE, 0)]; |
| 125 | Log.d(TAG, "recording with audio source" + mAudioSource); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 126 | mShowTaps = intent.getBooleanExtra(EXTRA_SHOW_TAPS, false); |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 127 | |
| 128 | mOriginalShowTaps = Settings.System.getInt( |
| 129 | getApplicationContext().getContentResolver(), |
| 130 | Settings.System.SHOW_TOUCHES, 0) != 0; |
| 131 | |
| 132 | setTapsVisible(mShowTaps); |
| 133 | |
| 134 | mRecorder = new ScreenMediaRecorder( |
| 135 | getApplicationContext(), |
| 136 | getUserId(), |
| 137 | mAudioSource, |
| 138 | this |
| 139 | ); |
| 140 | startRecording(); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 141 | break; |
| 142 | |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 143 | case ACTION_STOP_NOTIF: |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 144 | case ACTION_STOP: |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 145 | // only difference for actions is the log event |
| 146 | if (ACTION_STOP_NOTIF.equals(action)) { |
| 147 | mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION); |
| 148 | } else { |
| 149 | mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE); |
| 150 | } |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 151 | stopRecording(); |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 152 | mNotificationManager.cancel(NOTIFICATION_RECORDING_ID); |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 153 | stopSelf(); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 154 | break; |
| 155 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 156 | case ACTION_SHARE: |
Beth Thibodeau | 11e6cbf | 2019-08-08 14:52:24 -0400 | [diff] [blame] | 157 | Uri shareUri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 158 | |
| 159 | Intent shareIntent = new Intent(Intent.ACTION_SEND) |
| 160 | .setType("video/mp4") |
| 161 | .putExtra(Intent.EXTRA_STREAM, shareUri); |
| 162 | String shareLabel = getResources().getString(R.string.screenrecord_share_label); |
| 163 | |
| 164 | // Close quick shade |
| 165 | sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); |
| 166 | |
| 167 | // Remove notification |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 168 | mNotificationManager.cancel(NOTIFICATION_VIEW_ID); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 169 | |
| 170 | startActivity(Intent.createChooser(shareIntent, shareLabel) |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 171 | .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 172 | break; |
| 173 | case ACTION_DELETE: |
| 174 | // Close quick shade |
| 175 | sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); |
| 176 | |
Beth Thibodeau | 11e6cbf | 2019-08-08 14:52:24 -0400 | [diff] [blame] | 177 | ContentResolver resolver = getContentResolver(); |
| 178 | Uri uri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); |
| 179 | resolver.delete(uri, null, null); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 180 | |
Beth Thibodeau | 11e6cbf | 2019-08-08 14:52:24 -0400 | [diff] [blame] | 181 | Toast.makeText( |
| 182 | this, |
| 183 | R.string.screenrecord_delete_description, |
| 184 | Toast.LENGTH_LONG).show(); |
| 185 | |
| 186 | // Remove notification |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 187 | mNotificationManager.cancel(NOTIFICATION_VIEW_ID); |
Beth Thibodeau | 11e6cbf | 2019-08-08 14:52:24 -0400 | [diff] [blame] | 188 | Log.d(TAG, "Deleted recording " + uri); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 189 | break; |
| 190 | } |
| 191 | return Service.START_STICKY; |
| 192 | } |
| 193 | |
| 194 | @Override |
| 195 | public IBinder onBind(Intent intent) { |
| 196 | return null; |
| 197 | } |
| 198 | |
| 199 | @Override |
| 200 | public void onCreate() { |
| 201 | super.onCreate(); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 202 | } |
| 203 | |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 204 | @VisibleForTesting |
| 205 | protected ScreenMediaRecorder getRecorder() { |
| 206 | return mRecorder; |
| 207 | } |
| 208 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 209 | /** |
| 210 | * Begin the recording session |
| 211 | */ |
| 212 | private void startRecording() { |
| 213 | try { |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 214 | getRecorder().start(); |
Beth Thibodeau | 77c2545 | 2020-01-09 14:33:47 -0500 | [diff] [blame] | 215 | mController.updateState(true); |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 216 | createRecordingNotification(); |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 217 | mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START); |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 218 | } catch (IOException | RemoteException e) { |
| 219 | Toast.makeText(this, |
| 220 | R.string.screenrecord_start_error, Toast.LENGTH_LONG) |
| 221 | .show(); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 222 | e.printStackTrace(); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 223 | } |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 224 | } |
| 225 | |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 226 | @VisibleForTesting |
| 227 | protected void createRecordingNotification() { |
Beth Thibodeau | 630225c | 2020-02-04 17:16:45 -0500 | [diff] [blame] | 228 | Resources res = getResources(); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 229 | NotificationChannel channel = new NotificationChannel( |
| 230 | CHANNEL_ID, |
| 231 | getString(R.string.screenrecord_name), |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 232 | NotificationManager.IMPORTANCE_DEFAULT); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 233 | channel.setDescription(getString(R.string.screenrecord_channel_description)); |
| 234 | channel.enableVibration(true); |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 235 | mNotificationManager.createNotificationChannel(channel); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 236 | |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 237 | Bundle extras = new Bundle(); |
| 238 | extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, |
Beth Thibodeau | 630225c | 2020-02-04 17:16:45 -0500 | [diff] [blame] | 239 | res.getString(R.string.screenrecord_name)); |
| 240 | |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 241 | String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE |
Jay Aliomer | 246a25e | 2020-05-26 22:57:34 -0400 | [diff] [blame] | 242 | ? res.getString(R.string.screenrecord_ongoing_screen_only) |
| 243 | : res.getString(R.string.screenrecord_ongoing_screen_and_audio); |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 244 | |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 245 | |
| 246 | Intent stopIntent = getNotificationIntent(this); |
| 247 | Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID) |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 248 | .setSmallIcon(R.drawable.ic_screenrecord) |
Beth Thibodeau | 630225c | 2020-02-04 17:16:45 -0500 | [diff] [blame] | 249 | .setContentTitle(notificationTitle) |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 250 | .setContentText(getResources().getString(R.string.screenrecord_stop_text)) |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 251 | .setUsesChronometer(true) |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 252 | .setColorized(true) |
| 253 | .setColor(getResources().getColor(R.color.GM2_red_700)) |
| 254 | .setOngoing(true) |
| 255 | .setContentIntent( |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 256 | PendingIntent.getService(this, REQUEST_CODE, stopIntent, |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 257 | PendingIntent.FLAG_UPDATE_CURRENT)) |
| 258 | .addExtras(extras); |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 259 | startForeground(NOTIFICATION_RECORDING_ID, builder.build()); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 260 | } |
| 261 | |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 262 | @VisibleForTesting |
| 263 | protected Notification createProcessingNotification() { |
| 264 | Resources res = getApplicationContext().getResources(); |
| 265 | String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE |
| 266 | ? res.getString(R.string.screenrecord_ongoing_screen_only) |
| 267 | : res.getString(R.string.screenrecord_ongoing_screen_and_audio); |
| 268 | Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID) |
| 269 | .setContentTitle(notificationTitle) |
| 270 | .setContentText( |
| 271 | getResources().getString(R.string.screenrecord_background_processing_label)) |
| 272 | .setSmallIcon(R.drawable.ic_screenrecord); |
| 273 | return builder.build(); |
| 274 | } |
| 275 | |
| 276 | @VisibleForTesting |
| 277 | protected Notification createSaveNotification(ScreenMediaRecorder.SavedRecording recording) { |
Jay Aliomer | 57e2aa4 | 2020-06-04 15:28:09 -0400 | [diff] [blame] | 278 | Uri uri = recording.getUri(); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 279 | Intent viewIntent = new Intent(Intent.ACTION_VIEW) |
| 280 | .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION) |
Beth Thibodeau | eb48d0a | 2019-07-24 15:23:54 -0400 | [diff] [blame] | 281 | .setDataAndType(uri, "video/mp4"); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 282 | |
| 283 | Notification.Action shareAction = new Notification.Action.Builder( |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 284 | Icon.createWithResource(this, R.drawable.ic_screenrecord), |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 285 | getResources().getString(R.string.screenrecord_share_label), |
| 286 | PendingIntent.getService( |
| 287 | this, |
| 288 | REQUEST_CODE, |
Beth Thibodeau | eb48d0a | 2019-07-24 15:23:54 -0400 | [diff] [blame] | 289 | getShareIntent(this, uri.toString()), |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 290 | PendingIntent.FLAG_UPDATE_CURRENT)) |
| 291 | .build(); |
| 292 | |
| 293 | Notification.Action deleteAction = new Notification.Action.Builder( |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 294 | Icon.createWithResource(this, R.drawable.ic_screenrecord), |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 295 | getResources().getString(R.string.screenrecord_delete_label), |
| 296 | PendingIntent.getService( |
| 297 | this, |
| 298 | REQUEST_CODE, |
Beth Thibodeau | eb48d0a | 2019-07-24 15:23:54 -0400 | [diff] [blame] | 299 | getDeleteIntent(this, uri.toString()), |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 300 | PendingIntent.FLAG_UPDATE_CURRENT)) |
| 301 | .build(); |
| 302 | |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 303 | Bundle extras = new Bundle(); |
| 304 | extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, |
| 305 | getResources().getString(R.string.screenrecord_name)); |
| 306 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 307 | Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID) |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 308 | .setSmallIcon(R.drawable.ic_screenrecord) |
Beth Thibodeau | 630225c | 2020-02-04 17:16:45 -0500 | [diff] [blame] | 309 | .setContentTitle(getResources().getString(R.string.screenrecord_save_message)) |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 310 | .setContentIntent(PendingIntent.getActivity( |
| 311 | this, |
| 312 | REQUEST_CODE, |
| 313 | viewIntent, |
Beth Thibodeau | 4cecd35 | 2020-06-15 13:24:18 -0400 | [diff] [blame] | 314 | PendingIntent.FLAG_IMMUTABLE)) |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 315 | .addAction(shareAction) |
| 316 | .addAction(deleteAction) |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 317 | .setAutoCancel(true) |
| 318 | .addExtras(extras); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 319 | |
| 320 | // Add thumbnail if available |
Jay Aliomer | 57e2aa4 | 2020-06-04 15:28:09 -0400 | [diff] [blame] | 321 | Bitmap thumbnailBitmap = recording.getThumbnail(); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 322 | if (thumbnailBitmap != null) { |
| 323 | Notification.BigPictureStyle pictureStyle = new Notification.BigPictureStyle() |
| 324 | .bigPicture(thumbnailBitmap) |
| 325 | .bigLargeIcon((Bitmap) null); |
| 326 | builder.setLargeIcon(thumbnailBitmap).setStyle(pictureStyle); |
| 327 | } |
| 328 | return builder.build(); |
| 329 | } |
| 330 | |
| 331 | private void stopRecording() { |
Beth Thibodeau | 28b4489 | 2020-01-22 13:56:37 -0500 | [diff] [blame] | 332 | setTapsVisible(mOriginalShowTaps); |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 333 | if (getRecorder() != null) { |
| 334 | getRecorder().end(); |
| 335 | saveRecording(); |
| 336 | } else { |
| 337 | Log.e(TAG, "stopRecording called, but recorder was null"); |
| 338 | } |
Beth Thibodeau | 77c2545 | 2020-01-09 14:33:47 -0500 | [diff] [blame] | 339 | mController.updateState(false); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 340 | } |
| 341 | |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 342 | private void saveRecording() { |
| 343 | mNotificationManager.notify(NOTIFICATION_PROCESSING_ID, createProcessingNotification()); |
Beth Thibodeau | 11e6cbf | 2019-08-08 14:52:24 -0400 | [diff] [blame] | 344 | |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 345 | mLongExecutor.execute(() -> { |
| 346 | try { |
| 347 | Log.d(TAG, "saving recording"); |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 348 | Notification notification = createSaveNotification(getRecorder().save()); |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 349 | if (!mController.isRecording()) { |
| 350 | Log.d(TAG, "showing saved notification"); |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 351 | mNotificationManager.notify(NOTIFICATION_VIEW_ID, notification); |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 352 | } |
| 353 | } catch (IOException e) { |
| 354 | Log.e(TAG, "Error saving screen recording: " + e.getMessage()); |
| 355 | Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) |
| 356 | .show(); |
| 357 | } finally { |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 358 | mNotificationManager.cancel(NOTIFICATION_PROCESSING_ID); |
Jay Aliomer | 0bd491a | 2020-03-16 14:34:10 -0400 | [diff] [blame] | 359 | } |
| 360 | }); |
Beth Thibodeau | 11e6cbf | 2019-08-08 14:52:24 -0400 | [diff] [blame] | 361 | } |
| 362 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 363 | private void setTapsVisible(boolean turnOn) { |
| 364 | int value = turnOn ? 1 : 0; |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 365 | Settings.System.putInt(getContentResolver(), Settings.System.SHOW_TOUCHES, value); |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 366 | } |
| 367 | |
Beth Thibodeau | 77c2545 | 2020-01-09 14:33:47 -0500 | [diff] [blame] | 368 | /** |
| 369 | * Get an intent to stop the recording service. |
| 370 | * @param context Context from the requesting activity |
| 371 | * @return |
| 372 | */ |
| 373 | public static Intent getStopIntent(Context context) { |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 374 | return new Intent(context, RecordingService.class).setAction(ACTION_STOP); |
| 375 | } |
| 376 | |
Beth Thibodeau | abb338f | 2020-03-03 16:17:24 -0500 | [diff] [blame] | 377 | /** |
| 378 | * Get the recording notification content intent |
| 379 | * @param context |
| 380 | * @return |
| 381 | */ |
| 382 | protected static Intent getNotificationIntent(Context context) { |
| 383 | return new Intent(context, RecordingService.class).setAction(ACTION_STOP_NOTIF); |
| 384 | } |
| 385 | |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 386 | private static Intent getShareIntent(Context context, String path) { |
| 387 | return new Intent(context, RecordingService.class).setAction(ACTION_SHARE) |
| 388 | .putExtra(EXTRA_PATH, path); |
| 389 | } |
| 390 | |
| 391 | private static Intent getDeleteIntent(Context context, String path) { |
| 392 | return new Intent(context, RecordingService.class).setAction(ACTION_DELETE) |
| 393 | .putExtra(EXTRA_PATH, path); |
| 394 | } |
Beth Thibodeau | 26fefde | 2020-02-21 16:04:41 -0500 | [diff] [blame] | 395 | |
| 396 | @Override |
| 397 | public void onInfo(MediaRecorder mr, int what, int extra) { |
| 398 | Log.d(TAG, "Media recorder info: " + what); |
| 399 | onStartCommand(getStopIntent(this), 0, 0); |
| 400 | } |
Beth Thibodeau | 5898ac4 | 2018-10-26 13:00:09 -0400 | [diff] [blame] | 401 | } |