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