Merge "Expand dumpsys coverage to all known factors in empty expanded view issues." into rvc-dev
diff --git a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
index 240222e..6108a32 100644
--- a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
+++ b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
@@ -33,7 +33,6 @@
import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import com.android.internal.os.statsd.StatsConfigUtils;
import com.android.internal.os.statsd.protos.TestAtoms;
import com.android.os.AtomsProto.Atom;
diff --git a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/StatsConfigUtils.java b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/StatsConfigUtils.java
similarity index 98%
rename from apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/StatsConfigUtils.java
rename to apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/StatsConfigUtils.java
index d0d1400..b5afb94 100644
--- a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/StatsConfigUtils.java
+++ b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/StatsConfigUtils.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.os.statsd;
+package com.android.internal.os.statsd.libstats;
import static com.google.common.truth.Truth.assertThat;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index ca03343..02c0763 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -9694,6 +9694,7 @@
UNIFORM = 1;
RARELY_USED = 2;
BOOT_TIME_SAMPLING = 3;
+ UNIFORM_OPS = 4;
}
// sampling strategy used to collect this message
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 9bf2e01..91e75911 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -427,8 +427,7 @@
if (copySources) {
for (int i = 0; i < SIZE; i++) {
InsetsSource source = other.mSources[i];
- if (source == null) continue;
- mSources[i] = new InsetsSource(source);
+ mSources[i] = source != null ? new InsetsSource(source) : null;
}
} else {
for (int i = 0; i < SIZE; i++) {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 86c13a0..fba4675a 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -20,9 +20,6 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.PermissionChecker.PID_UNKNOWN;
-import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
-import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_WORK;
-
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UiThread;
@@ -159,6 +156,9 @@
protected static final String METRICS_CATEGORY_RESOLVER = "intent_resolver";
protected static final String METRICS_CATEGORY_CHOOSER = "intent_chooser";
+ /** Tracks if we should ignore future broadcasts telling us the work profile is enabled */
+ private boolean mWorkProfileHasBeenEnabled = false;
+
@VisibleForTesting
public static boolean ENABLE_TABBED_VIEW = true;
private static final String TAB_TAG_PERSONAL = "personal";
@@ -825,12 +825,23 @@
if (shouldShowTabs()) {
mWorkProfileStateReceiver = createWorkProfileStateReceiver();
registerWorkProfileStateReceiver();
+
+ mWorkProfileHasBeenEnabled = isWorkProfileEnabled();
}
}
+ private boolean isWorkProfileEnabled() {
+ UserHandle workUserHandle = getWorkProfileUserHandle();
+ UserManager userManager = getSystemService(UserManager.class);
+
+ return !userManager.isQuietModeEnabled(workUserHandle)
+ && userManager.isUserUnlocked(workUserHandle);
+ }
+
private void registerWorkProfileStateReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
registerReceiverAsUser(mWorkProfileStateReceiver, UserHandle.ALL, filter, null, null);
}
@@ -1961,17 +1972,29 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!TextUtils.equals(action, Intent.ACTION_USER_UNLOCKED)
- && !TextUtils.equals(action, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
+ && !TextUtils.equals(action, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
+ && !TextUtils.equals(action, Intent.ACTION_MANAGED_PROFILE_AVAILABLE)) {
return;
}
- int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (TextUtils.equals(action, Intent.ACTION_USER_UNLOCKED)
- && userHandle != getWorkProfileUserHandle().getIdentifier()) {
+
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+
+ if (userId != getWorkProfileUserHandle().getIdentifier()) {
return;
}
- if (TextUtils.equals(action, Intent.ACTION_USER_UNLOCKED)) {
+
+ if (isWorkProfileEnabled()) {
+ if (mWorkProfileHasBeenEnabled) {
+ return;
+ }
+
+ mWorkProfileHasBeenEnabled = true;
mMultiProfilePagerAdapter.markWorkProfileEnabledBroadcastReceived();
+ } else {
+ // Must be an UNAVAILABLE broadcast, so we watch for the next availability
+ mWorkProfileHasBeenEnabled = false;
}
+
if (mMultiProfilePagerAdapter.getCurrentUserHandle()
.equals(getWorkProfileUserHandle())) {
mMultiProfilePagerAdapter.rebuildActiveTab(true);
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 7115acf..5260ef8 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -304,6 +304,7 @@
mState.getSource(ITYPE_IME).setVisibleFrame(new Rect(0, 0, 50, 10));
mState.getSource(ITYPE_IME).setVisible(true);
mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
+ mState2.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(0, 0, 100, 100));
mState2.set(mState, true);
assertEquals(mState, mState2);
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 5b61551..a7ef5e6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -329,6 +329,7 @@
<activity android:name=".screenrecord.ScreenRecordDialog"
android:theme="@style/ScreenRecord"
+ android:showForAllUsers="true"
android:excludeFromRecents="true" />
<service android:name=".screenrecord.RecordingService" />
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 32ef063..0c34b27 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.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 @@
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 @@
} else if (mController.isRecording()) {
stopRecording();
} else {
- startCountdown();
+ mUiHandler.post(() -> showPrompt());
}
refreshState();
}
@@ -114,11 +112,15 @@
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 b253635..82ac1f6 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 @@
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<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
- * @param context Context for the controller
*/
@Inject
- public RecordingController(Context context) {
- mContext = context;
+ public RecordingController(BroadcastDispatcher broadcastDispatcher) {
+ mBroadcastDispatcher = broadcastDispatcher;
}
/**
@@ -99,6 +113,9 @@
}
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 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 8759726..476ec79 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.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.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 @@
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 @@
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 @@
* @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 @@
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 @@
setTapsVisible(mShowTaps);
mRecorder = new ScreenMediaRecorder(
- getApplicationContext(),
- getUserId(),
+ mUserContextTracker.getCurrentUserContext(),
+ mCurrentUserId,
mAudioSource,
this
);
@@ -148,7 +152,14 @@
} 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 @@
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 @@
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 @@
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 @@
? 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 @@
.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 @@
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 @@
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 @@
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 @@
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 @@
* @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 edbc3cf..df03c3e 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 @@
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 @@
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 @@
/**
* 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 @@
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 1c7d987..1a9abb9 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 @@
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 @@
/**
* 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 @@
}
}
- 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 8347def..dc47ab4 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 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 @@
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<ScreenRecordingAudioSource> mModes;
- private int mSelected;
-
@Inject
- public ScreenRecordDialog(RecordingController controller) {
+ public ScreenRecordDialog(RecordingController controller,
+ CurrentUserContextTracker currentUserContextTracker) {
mController = controller;
+ mCurrentUserContextTracker = currentUserContextTracker;
}
@Override
@@ -68,6 +72,7 @@
// 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 @@
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 06d35a3..5bb8fab 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 @@
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 @@
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 e502459..5a68238 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 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.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 @@
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 @@
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 b877c7f..11ef3e3 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 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 @@
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 @@
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 283a47c..e98b6b6 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 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 @@
private Notification mNotification;
@Mock
private Executor mExecutor;
+ @Mock
+ private CurrentUserContextTracker mUserContextTracker;
private RecordingService mRecordingService;
@@ -65,7 +68,7 @@
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 @@
doNothing().when(mRecordingService).startForeground(anyInt(), any());
doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder();
+
+ doReturn(mContext).when(mUserContextTracker).getCurrentUserContext();
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ef4d5db..16aa87b 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -1339,14 +1339,15 @@
}
@Test
- @Ignore
public void testPostCancelPostNotifiesListeners() throws Exception {
// WHEN a notification is posted
final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(),
sbn.getNotification(), sbn.getUserId());
+ Thread.sleep(1); // make sure the system clock advances before the next step
// THEN it is canceled
mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId());
+ Thread.sleep(1); // here too
// THEN it is posted again (before the cancel has a chance to finish)
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(),
sbn.getNotification(), sbn.getUserId());