diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 5b6155180e0ad..a7ef5e6f58f0f 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -329,6 +329,7 @@ diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java index 32ef063a55be1..0c34b27d348e6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -22,13 +22,13 @@ import android.text.TextUtils; import android.util.Log; import android.widget.Switch; -import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.screenrecord.RecordingController; +import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import javax.inject.Inject; @@ -39,19 +39,17 @@ public class ScreenRecordTile extends QSTileImpl implements RecordingController.RecordingStateChangeCallback { private static final String TAG = "ScreenRecordTile"; private RecordingController mController; - private ActivityStarter mActivityStarter; + private KeyguardDismissUtil mKeyguardDismissUtil; private long mMillisUntilFinished = 0; private Callback mCallback = new Callback(); - private UiEventLogger mUiEventLogger; @Inject public ScreenRecordTile(QSHost host, RecordingController controller, - ActivityStarter activityStarter, UiEventLogger uiEventLogger) { + KeyguardDismissUtil keyguardDismissUtil) { super(host); mController = controller; mController.observe(this, mCallback); - mActivityStarter = activityStarter; - mUiEventLogger = uiEventLogger; + mKeyguardDismissUtil = keyguardDismissUtil; } @Override @@ -69,7 +67,7 @@ public class ScreenRecordTile extends QSTileImpl } else if (mController.isRecording()) { stopRecording(); } else { - startCountdown(); + mUiHandler.post(() -> showPrompt()); } refreshState(); } @@ -114,11 +112,15 @@ public class ScreenRecordTile extends QSTileImpl return mContext.getString(R.string.quick_settings_screen_record_label); } - private void startCountdown() { - // Close QS, otherwise the permission dialog appears beneath it + private void showPrompt() { + // Close QS, otherwise the dialog appears beneath it getHost().collapsePanels(); Intent intent = mController.getPromptIntent(); - mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); + ActivityStarter.OnDismissAction dismissAction = () -> { + mContext.startActivity(intent); + return false; + }; + mKeyguardDismissUtil.executeWhenUnlocked(dismissAction, false); } private void cancelCountdown() { diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java index b253635e9bfa7..82ac1f6f6a335 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java @@ -17,12 +17,17 @@ package com.android.systemui.screenrecord; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.os.CountDownTimer; +import android.os.UserHandle; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.statusbar.policy.CallbackController; import java.util.ArrayList; @@ -41,21 +46,30 @@ public class RecordingController private static final String SYSUI_SCREENRECORD_LAUNCHER = "com.android.systemui.screenrecord.ScreenRecordDialog"; - private final Context mContext; private boolean mIsStarting; private boolean mIsRecording; private PendingIntent mStopIntent; private CountDownTimer mCountDownTimer = null; + private BroadcastDispatcher mBroadcastDispatcher; private ArrayList mListeners = new ArrayList<>(); + @VisibleForTesting + protected final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mStopIntent != null) { + stopRecording(); + } + } + }; + /** * Create a new RecordingController - * @param context Context for the controller */ @Inject - public RecordingController(Context context) { - mContext = context; + public RecordingController(BroadcastDispatcher broadcastDispatcher) { + mBroadcastDispatcher = broadcastDispatcher; } /** @@ -99,6 +113,9 @@ public class RecordingController } try { startIntent.send(); + IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_SWITCHED); + mBroadcastDispatcher.registerReceiver(mUserChangeReceiver, userFilter, null, + UserHandle.ALL); Log.d(TAG, "sent start intent"); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Pending intent was cancelled: " + e.getMessage()); @@ -146,11 +163,16 @@ public class RecordingController */ public void stopRecording() { try { - mStopIntent.send(); + if (mStopIntent != null) { + mStopIntent.send(); + } else { + Log.e(TAG, "Stop intent was null"); + } updateState(false); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Error stopping: " + e.getMessage()); } + mBroadcastDispatcher.unregisterReceiver(mUserChangeReceiver); } /** diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index 87597263168a1..476ec798a35f1 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -32,6 +32,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.widget.Toast; @@ -40,6 +41,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.LongRunning; +import com.android.systemui.settings.CurrentUserContextTracker; import java.io.IOException; import java.util.concurrent.Executor; @@ -58,7 +60,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis private static final String TAG = "RecordingService"; private static final String CHANNEL_ID = "screen_record"; private static final String EXTRA_RESULT_CODE = "extra_resultCode"; - private static final String EXTRA_DATA = "extra_data"; private static final String EXTRA_PATH = "extra_path"; private static final String EXTRA_AUDIO_SOURCE = "extra_useAudio"; private static final String EXTRA_SHOW_TAPS = "extra_showTaps"; @@ -79,14 +80,17 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis private final Executor mLongExecutor; private final UiEventLogger mUiEventLogger; private final NotificationManager mNotificationManager; + private final CurrentUserContextTracker mUserContextTracker; @Inject public RecordingService(RecordingController controller, @LongRunning Executor executor, - UiEventLogger uiEventLogger, NotificationManager notificationManager) { + UiEventLogger uiEventLogger, NotificationManager notificationManager, + CurrentUserContextTracker userContextTracker) { mController = controller; mLongExecutor = executor; mUiEventLogger = uiEventLogger; mNotificationManager = notificationManager; + mUserContextTracker = userContextTracker; } /** @@ -95,8 +99,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis * @param context Context from the requesting activity * @param resultCode The result code from {@link android.app.Activity#onActivityResult(int, int, * android.content.Intent)} - * @param data The data from {@link android.app.Activity#onActivityResult(int, int, - * android.content.Intent)} * @param audioSource The ordinal value of the audio source * {@link com.android.systemui.screenrecord.ScreenRecordingAudioSource} * @param showTaps True to make touches visible while recording @@ -118,6 +120,8 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis String action = intent.getAction(); Log.d(TAG, "onStartCommand " + action); + int mCurrentUserId = mUserContextTracker.getCurrentUserContext().getUserId(); + UserHandle currentUser = new UserHandle(mCurrentUserId); switch (action) { case ACTION_START: mAudioSource = ScreenRecordingAudioSource @@ -132,8 +136,8 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis setTapsVisible(mShowTaps); mRecorder = new ScreenMediaRecorder( - getApplicationContext(), - getUserId(), + mUserContextTracker.getCurrentUserContext(), + mCurrentUserId, mAudioSource, this ); @@ -148,7 +152,14 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis } else { mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE); } - stopRecording(); + // Check user ID - we may be getting a stop intent after user switch, in which case + // we want to post the notifications for that user, which is NOT current user + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + if (userId == -1) { + userId = mUserContextTracker.getCurrentUserContext().getUserId(); + } + Log.d(TAG, "notifying for user " + userId); + stopRecording(userId); mNotificationManager.cancel(NOTIFICATION_RECORDING_ID); stopSelf(); break; @@ -165,7 +176,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); // Remove notification - mNotificationManager.cancel(NOTIFICATION_VIEW_ID); + mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser); startActivity(Intent.createChooser(shareIntent, shareLabel) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); @@ -184,7 +195,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis Toast.LENGTH_LONG).show(); // Remove notification - mNotificationManager.cancel(NOTIFICATION_VIEW_ID); + mNotificationManager.cancelAsUser(null, NOTIFICATION_VIEW_ID, currentUser); Log.d(TAG, "Deleted recording " + uri); break; } @@ -215,11 +226,12 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis mController.updateState(true); createRecordingNotification(); mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START); - } catch (IOException | RemoteException e) { + } catch (IOException | RemoteException | IllegalStateException e) { Toast.makeText(this, R.string.screenrecord_start_error, Toast.LENGTH_LONG) .show(); e.printStackTrace(); + mController.updateState(false); } } @@ -242,7 +254,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis ? res.getString(R.string.screenrecord_ongoing_screen_only) : res.getString(R.string.screenrecord_ongoing_screen_and_audio); - Intent stopIntent = getNotificationIntent(this); Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_screenrecord) @@ -254,7 +265,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis .setOngoing(true) .setContentIntent( PendingIntent.getService(this, REQUEST_CODE, stopIntent, - PendingIntent.FLAG_UPDATE_CURRENT)) + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) .addExtras(extras); startForeground(NOTIFICATION_RECORDING_ID, builder.build()); } @@ -265,11 +276,17 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE ? res.getString(R.string.screenrecord_ongoing_screen_only) : res.getString(R.string.screenrecord_ongoing_screen_and_audio); + + Bundle extras = new Bundle(); + extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, + res.getString(R.string.screenrecord_name)); + Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID) .setContentTitle(notificationTitle) .setContentText( getResources().getString(R.string.screenrecord_background_processing_label)) - .setSmallIcon(R.drawable.ic_screenrecord); + .setSmallIcon(R.drawable.ic_screenrecord) + .addExtras(extras); return builder.build(); } @@ -287,7 +304,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis this, REQUEST_CODE, getShareIntent(this, uri.toString()), - PendingIntent.FLAG_UPDATE_CURRENT)) + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) .build(); Notification.Action deleteAction = new Notification.Action.Builder( @@ -297,7 +314,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis this, REQUEST_CODE, getDeleteIntent(this, uri.toString()), - PendingIntent.FLAG_UPDATE_CURRENT)) + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) .build(); Bundle extras = new Bundle(); @@ -328,34 +345,36 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis return builder.build(); } - private void stopRecording() { + private void stopRecording(int userId) { setTapsVisible(mOriginalShowTaps); if (getRecorder() != null) { getRecorder().end(); - saveRecording(); + saveRecording(userId); } else { Log.e(TAG, "stopRecording called, but recorder was null"); } mController.updateState(false); } - private void saveRecording() { - mNotificationManager.notify(NOTIFICATION_PROCESSING_ID, createProcessingNotification()); + private void saveRecording(int userId) { + UserHandle currentUser = new UserHandle(userId); + mNotificationManager.notifyAsUser(null, NOTIFICATION_PROCESSING_ID, + createProcessingNotification(), currentUser); mLongExecutor.execute(() -> { try { Log.d(TAG, "saving recording"); Notification notification = createSaveNotification(getRecorder().save()); if (!mController.isRecording()) { - Log.d(TAG, "showing saved notification"); - mNotificationManager.notify(NOTIFICATION_VIEW_ID, notification); + mNotificationManager.notifyAsUser(null, NOTIFICATION_VIEW_ID, notification, + currentUser); } } catch (IOException e) { Log.e(TAG, "Error saving screen recording: " + e.getMessage()); Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) .show(); } finally { - mNotificationManager.cancel(NOTIFICATION_PROCESSING_ID); + mNotificationManager.cancelAsUser(null, NOTIFICATION_PROCESSING_ID, currentUser); } }); } @@ -371,7 +390,9 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis * @return */ public static Intent getStopIntent(Context context) { - return new Intent(context, RecordingService.class).setAction(ACTION_STOP); + return new Intent(context, RecordingService.class) + .setAction(ACTION_STOP) + .putExtra(Intent.EXTRA_USER_HANDLE, context.getUserId()); } /** diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java index edbc3cfdece5d..df03c3e08f087 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java @@ -16,7 +16,6 @@ package com.android.systemui.screenrecord; -import android.content.Context; import android.media.AudioAttributes; import android.media.AudioFormat; import android.media.AudioPlaybackCaptureConfiguration; @@ -39,7 +38,6 @@ public class ScreenInternalAudioRecorder { private static String TAG = "ScreenAudioRecorder"; private static final int TIMEOUT = 500; private static final float MIC_VOLUME_SCALE = 1.4f; - private final Context mContext; private AudioRecord mAudioRecord; private AudioRecord mAudioRecordMic; private Config mConfig = new Config(); @@ -49,17 +47,14 @@ public class ScreenInternalAudioRecorder { private long mPresentationTime; private long mTotalBytes; private MediaMuxer mMuxer; - private String mOutFile; private boolean mMic; private int mTrackId = -1; - public ScreenInternalAudioRecorder(String outFile, Context context, - MediaProjection mp, boolean includeMicInput) throws IOException { + public ScreenInternalAudioRecorder(String outFile, MediaProjection mp, boolean includeMicInput) + throws IOException { mMic = includeMicInput; - mOutFile = outFile; mMuxer = new MediaMuxer(outFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); - mContext = context; mMediaProjection = mp; Log.d(TAG, "creating audio file " + outFile); setupSimple(); @@ -266,8 +261,9 @@ public class ScreenInternalAudioRecorder { /** * start recording + * @throws IllegalStateException if recording fails to initialize */ - public void start() { + public void start() throws IllegalStateException { if (mThread != null) { Log.e(TAG, "a recording is being done in parallel or stop is not called"); } @@ -276,8 +272,7 @@ public class ScreenInternalAudioRecorder { Log.d(TAG, "channel count " + mAudioRecord.getChannelCount()); mCodec.start(); if (mAudioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) { - Log.e(TAG, "Error starting audio recording"); - return; + throw new IllegalStateException("Audio recording failed to start"); } mThread.start(); } diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java index 1c7d987afff29..1a9abb9cf27d4 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java @@ -166,7 +166,7 @@ public class ScreenMediaRecorder { mAudioSource == MIC_AND_INTERNAL) { mTempAudioFile = File.createTempFile("temp", ".aac", mContext.getCacheDir()); - mAudio = new ScreenInternalAudioRecorder(mTempAudioFile.getAbsolutePath(), mContext, + mAudio = new ScreenInternalAudioRecorder(mTempAudioFile.getAbsolutePath(), mMediaProjection, mAudioSource == MIC_AND_INTERNAL); } @@ -175,7 +175,7 @@ public class ScreenMediaRecorder { /** * Start screen recording */ - void start() throws IOException, RemoteException { + void start() throws IOException, RemoteException, IllegalStateException { Log.d(TAG, "start recording"); prepare(); mMediaRecorder.start(); @@ -205,7 +205,7 @@ public class ScreenMediaRecorder { } } - private void recordInternalAudio() { + private void recordInternalAudio() throws IllegalStateException { if (mAudioSource == INTERNAL || mAudioSource == MIC_AND_INTERNAL) { mAudio.start(); } diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java index 8347def2d4302..dc47ab4dff631 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java @@ -23,16 +23,19 @@ import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.NONE; import android.app.Activity; import android.app.PendingIntent; +import android.content.Context; import android.os.Bundle; import android.view.Gravity; import android.view.ViewGroup; import android.view.Window; +import android.view.WindowManager; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.Spinner; import android.widget.Switch; import com.android.systemui.R; +import com.android.systemui.settings.CurrentUserContextTracker; import java.util.ArrayList; import java.util.List; @@ -48,16 +51,17 @@ public class ScreenRecordDialog extends Activity { private static final String TAG = "ScreenRecordDialog"; private final RecordingController mController; + private final CurrentUserContextTracker mCurrentUserContextTracker; private Switch mTapsSwitch; private Switch mAudioSwitch; private Spinner mOptions; private List mModes; - private int mSelected; - @Inject - public ScreenRecordDialog(RecordingController controller) { + public ScreenRecordDialog(RecordingController controller, + CurrentUserContextTracker currentUserContextTracker) { mController = controller; + mCurrentUserContextTracker = currentUserContextTracker; } @Override @@ -68,6 +72,7 @@ public class ScreenRecordDialog extends Activity { // Inflate the decor view, so the attributes below are not overwritten by the theme. window.getDecorView(); window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + window.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS); window.setGravity(Gravity.TOP); setTitle(R.string.screenrecord_name); @@ -100,24 +105,24 @@ public class ScreenRecordDialog extends Activity { mOptions.setOnItemClickListenerInt((parent, view, position, id) -> { mAudioSwitch.setChecked(true); }); - } private void requestScreenCapture() { + Context userContext = mCurrentUserContextTracker.getCurrentUserContext(); boolean showTaps = mTapsSwitch.isChecked(); ScreenRecordingAudioSource audioMode = mAudioSwitch.isChecked() ? (ScreenRecordingAudioSource) mOptions.getSelectedItem() : NONE; - PendingIntent startIntent = PendingIntent.getForegroundService(this, + PendingIntent startIntent = PendingIntent.getForegroundService(userContext, RecordingService.REQUEST_CODE, RecordingService.getStartIntent( - ScreenRecordDialog.this, RESULT_OK, + userContext, RESULT_OK, audioMode.ordinal(), showTaps), - PendingIntent.FLAG_UPDATE_CURRENT); - PendingIntent stopIntent = PendingIntent.getService(this, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + PendingIntent stopIntent = PendingIntent.getService(userContext, RecordingService.REQUEST_CODE, - RecordingService.getStopIntent(this), - PendingIntent.FLAG_UPDATE_CURRENT); + RecordingService.getStopIntent(userContext), + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); mController.startCountdown(DELAY_MS, INTERVAL_MS, startIntent, stopIntent); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 06d35a36e3c40..5bb8fab8a62e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -688,8 +688,8 @@ public class PhoneStatusBarPolicy if (DEBUG) Log.d(TAG, "screenrecord: hiding icon during countdown"); mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false)); // Reset talkback priority - mIconController.setIconAccessibilityLiveRegion(mSlotScreenRecord, - View.ACCESSIBILITY_LIVE_REGION_NONE); + mHandler.post(() -> mIconController.setIconAccessibilityLiveRegion(mSlotScreenRecord, + View.ACCESSIBILITY_LIVE_REGION_NONE)); } @Override @@ -698,7 +698,7 @@ public class PhoneStatusBarPolicy mIconController.setIcon(mSlotScreenRecord, R.drawable.stat_sys_screen_record, mResources.getString(R.string.screenrecord_ongoing_screen_only)); - mIconController.setIconVisibility(mSlotScreenRecord, true); + mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, true)); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java index e5024595d97e2..5a68238799423 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java @@ -29,13 +29,12 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.qs.QSTileHost; import com.android.systemui.screenrecord.RecordingController; +import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import org.junit.Before; import org.junit.Test; @@ -44,18 +43,16 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class ScreenRecordTileTest extends SysuiTestCase { @Mock private RecordingController mController; @Mock - private ActivityStarter mActivityStarter; - @Mock private QSTileHost mHost; @Mock - private UiEventLogger mUiEventLogger; + private KeyguardDismissUtil mKeyguardDismissUtil; private TestableLooper mTestableLooper; private ScreenRecordTile mTile; @@ -67,11 +64,10 @@ public class ScreenRecordTileTest extends SysuiTestCase { mTestableLooper = TestableLooper.get(this); mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); mController = mDependency.injectMockDependency(RecordingController.class); - mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class); when(mHost.getContext()).thenReturn(mContext); - mTile = new ScreenRecordTile(mHost, mController, mActivityStarter, mUiEventLogger); + mTile = new ScreenRecordTile(mHost, mController, mKeyguardDismissUtil); } // Test that the tile is inactive and labeled correctly when the controller is neither starting @@ -89,6 +85,7 @@ public class ScreenRecordTileTest extends SysuiTestCase { mContext.getString(R.string.quick_settings_screen_record_start))); mTile.handleClick(); + mTestableLooper.processAllMessages(); verify(mController, times(1)).getPromptIntent(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java index b877c7fa6859f..11ef3e33f9d0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java @@ -22,12 +22,14 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.Mockito.verify; import android.app.PendingIntent; +import android.content.Intent; import android.os.Looper; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; import org.junit.Before; import org.junit.Test; @@ -45,14 +47,18 @@ import org.mockito.MockitoAnnotations; public class RecordingControllerTest extends SysuiTestCase { @Mock - RecordingController.RecordingStateChangeCallback mCallback; + private RecordingController.RecordingStateChangeCallback mCallback; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; - RecordingController mController; + private RecordingController mController; + + private static final int USER_ID = 10; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mController = new RecordingController(mContext); + mController = new RecordingController(mBroadcastDispatcher); mController.addCallback(mCallback); } @@ -121,4 +127,27 @@ public class RecordingControllerTest extends SysuiTestCase { assertFalse(mController.isRecording()); verify(mCallback).onRecordingEnd(); } + + // Test that switching users will stop an ongoing recording + @Test + public void testUserChange() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + // If we are recording + PendingIntent startIntent = Mockito.mock(PendingIntent.class); + PendingIntent stopIntent = Mockito.mock(PendingIntent.class); + mController.startCountdown(0, 0, startIntent, stopIntent); + mController.updateState(true); + + // and user is changed + Intent intent = new Intent(Intent.ACTION_USER_SWITCHED) + .putExtra(Intent.EXTRA_USER_HANDLE, USER_ID); + mController.mUserChangeReceiver.onReceive(mContext, intent); + + // Ensure that the recording was stopped + verify(mCallback).onRecordingEnd(); + assertFalse(mController.isRecording()); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java index 283a47ca3622f..e98b6b69ee768 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java @@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; +import com.android.systemui.settings.CurrentUserContextTracker; import org.junit.Before; import org.junit.Test; @@ -58,6 +59,8 @@ public class RecordingServiceTest extends SysuiTestCase { private Notification mNotification; @Mock private Executor mExecutor; + @Mock + private CurrentUserContextTracker mUserContextTracker; private RecordingService mRecordingService; @@ -65,7 +68,7 @@ public class RecordingServiceTest extends SysuiTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mRecordingService = Mockito.spy(new RecordingService(mController, mExecutor, mUiEventLogger, - mNotificationManager)); + mNotificationManager, mUserContextTracker)); // Return actual context info doReturn(mContext).when(mRecordingService).getApplicationContext(); @@ -80,6 +83,8 @@ public class RecordingServiceTest extends SysuiTestCase { doNothing().when(mRecordingService).startForeground(anyInt(), any()); doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder(); + + doReturn(mContext).when(mUserContextTracker).getCurrentUserContext(); } @Test