diff options
| author | 2024-11-08 18:29:50 +0000 | |
|---|---|---|
| committer | 2024-12-02 12:20:54 +0000 | |
| commit | 8f07c2afd32f08aff4b903a3aa44b0f19e590176 (patch) | |
| tree | 978f4608ab27b4409b770ab5475d58c45b48076b | |
| parent | 02d89d420912e1b15812525d69783f56c7c51c3a (diff) | |
Update ScreenRecorder to handle StopReason
Ensuring that the screen recorder and other dependent components (privacy chip, qs tile, etc.) all pass the correct stop reason through the logic
Bug: 341319250
Flag: EXEMPT bugfix
Test: atest CastTileTest
Test: atest MediaRouterRepositoryTest
Test: atest RecordingServiceTest
Test: atest ScreenRecordRepositoryTest
Test: atest ScreenRecordTileTest
Test: atest ScreenRecordTileUserActionInteractorTest
Change-Id: I2735a19b8d9240114edd3efa28b3688f8ecf603d
24 files changed, 120 insertions, 54 deletions
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java index f7f10df5786a..4f7132ad9ab2 100644 --- a/media/java/android/media/projection/MediaProjection.java +++ b/media/java/android/media/projection/MediaProjection.java @@ -324,6 +324,19 @@ public final class MediaProjection { } /** + * Stops projection. + * @hide + */ + public void stop(@StopReason int stopReason) { + try { + Log.d(TAG, "Content Recording: stopping projection"); + mImpl.stop(stopReason); + } catch (RemoteException e) { + Log.e(TAG, "Unable to stop projection", e); + } + } + + /** * Get the underlying IMediaProjection. * @hide */ diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepositoryTest.kt index 77be8c718b14..6ec38ba171c3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepositoryTest.kt @@ -16,8 +16,9 @@ package com.android.systemui.mediarouter.data.repository -import androidx.test.filters.SmallTest +import android.media.projection.StopReason import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.Kosmos @@ -101,7 +102,7 @@ class MediaRouterRepositoryTest : SysuiTestCase() { origin = CastDevice.CastOrigin.MediaRouter, ) - underTest.stopCasting(device) + underTest.stopCasting(device, StopReason.STOP_UNKNOWN) assertThat(castController.lastStoppedDevice).isEqualTo(device) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java index 9f12b189d76a..31a627fe0667 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java @@ -20,6 +20,7 @@ import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; @@ -30,6 +31,7 @@ import static org.mockito.Mockito.when; import android.media.MediaRouter; import android.media.MediaRouter.RouteInfo; import android.media.projection.MediaProjectionInfo; +import android.media.projection.StopReason; import android.os.Handler; import android.service.quicksettings.Tile; import android.testing.TestableLooper; @@ -336,7 +338,8 @@ public class CastTileTest extends SysuiTestCase { mCastTile.handleClick(null /* view */); mTestableLooper.processAllMessages(); - verify(mController, times(1)).stopCasting(same(device)); + verify(mController, times(1)) + .stopCasting(same(device), eq(StopReason.STOP_QS_TILE)); } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java index 53708fd417e1..6ebe8309bf69 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java @@ -23,11 +23,13 @@ import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Dialog; +import android.media.projection.StopReason; import android.os.Handler; import android.service.quicksettings.Tile; import android.testing.TestableLooper; @@ -214,7 +216,7 @@ public class ScreenRecordTileTest extends SysuiTestCase { mTile.handleClick(null /* view */); - verify(mController, times(1)).stopRecording(); + verify(mController, times(1)).stopRecording(eq(StopReason.STOP_QS_TILE)); } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt index 0b56d7b64aab..778c73fd8638 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.qs.tiles.impl.screenrecord.domain.interactor import android.app.Dialog +import android.media.projection.StopReason import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -92,7 +93,7 @@ class ScreenRecordTileUserActionInteractorTest : SysuiTestCase() { underTest.handleInput(QSTileInputTestKtx.click(recordingModel)) - verify(recordingController).stopRecording() + verify(recordingController).stopRecording(eq(StopReason.STOP_QS_TILE)) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java index a6a1d4a05dc7..50fa9d29659d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java @@ -41,6 +41,7 @@ import android.app.ActivityOptions.LaunchCookie; import android.app.Notification; import android.app.NotificationManager; import android.content.Intent; +import android.media.projection.StopReason; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; @@ -199,16 +200,16 @@ public class RecordingServiceTest extends SysuiTestCase { public void testOnSystemRequestedStop_recordingInProgress_endsRecording() throws IOException { doReturn(true).when(mController).isRecording(); - mRecordingService.onStopped(); + mRecordingService.onStopped(StopReason.STOP_UNKNOWN); - verify(mScreenMediaRecorder).end(); + verify(mScreenMediaRecorder).end(eq(StopReason.STOP_UNKNOWN)); } @Test public void testOnSystemRequestedStop_recordingInProgress_updatesState() { doReturn(true).when(mController).isRecording(); - mRecordingService.onStopped(); + mRecordingService.onStopped(StopReason.STOP_UNKNOWN); assertUpdateState(false); } @@ -218,18 +219,18 @@ public class RecordingServiceTest extends SysuiTestCase { throws IOException { doReturn(false).when(mController).isRecording(); - mRecordingService.onStopped(); + mRecordingService.onStopped(StopReason.STOP_UNKNOWN); - verify(mScreenMediaRecorder, never()).end(); + verify(mScreenMediaRecorder, never()).end(StopReason.STOP_UNKNOWN); } @Test public void testOnSystemRequestedStop_recorderEndThrowsRuntimeException_releasesRecording() throws IOException { doReturn(true).when(mController).isRecording(); - doThrow(new RuntimeException()).when(mScreenMediaRecorder).end(); + doThrow(new RuntimeException()).when(mScreenMediaRecorder).end(StopReason.STOP_UNKNOWN); - mRecordingService.onStopped(); + mRecordingService.onStopped(StopReason.STOP_UNKNOWN); verify(mScreenMediaRecorder).release(); } @@ -238,7 +239,7 @@ public class RecordingServiceTest extends SysuiTestCase { public void testOnSystemRequestedStop_whenRecordingInProgress_showsNotifications() { doReturn(true).when(mController).isRecording(); - mRecordingService.onStopped(); + mRecordingService.onStopped(StopReason.STOP_UNKNOWN); // Processing notification ArgumentCaptor<Notification> notifCaptor = ArgumentCaptor.forClass(Notification.class); @@ -271,9 +272,9 @@ public class RecordingServiceTest extends SysuiTestCase { public void testOnSystemRequestedStop_recorderEndThrowsRuntimeException_showsErrorNotification() throws IOException { doReturn(true).when(mController).isRecording(); - doThrow(new RuntimeException()).when(mScreenMediaRecorder).end(); + doThrow(new RuntimeException()).when(mScreenMediaRecorder).end(anyInt()); - mRecordingService.onStopped(); + mRecordingService.onStopped(StopReason.STOP_UNKNOWN); verify(mRecordingService).createErrorSavingNotification(any()); ArgumentCaptor<Notification> notifCaptor = ArgumentCaptor.forClass(Notification.class); @@ -289,9 +290,9 @@ public class RecordingServiceTest extends SysuiTestCase { public void testOnSystemRequestedStop_recorderEndThrowsOOMError_releasesRecording() throws IOException { doReturn(true).when(mController).isRecording(); - doThrow(new OutOfMemoryError()).when(mScreenMediaRecorder).end(); + doThrow(new OutOfMemoryError()).when(mScreenMediaRecorder).end(anyInt()); - assertThrows(Throwable.class, () -> mRecordingService.onStopped()); + assertThrows(Throwable.class, () -> mRecordingService.onStopped(StopReason.STOP_UNKNOWN)); verify(mScreenMediaRecorder).release(); } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt index aceea909e595..ade5941d010d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.screenrecord.data.repository +import android.media.projection.StopReason import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -31,6 +32,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever @@ -126,8 +128,8 @@ class ScreenRecordRepositoryTest : SysuiTestCase() { @Test fun stopRecording_invokesController() = testScope.runTest { - underTest.stopRecording() + underTest.stopRecording(StopReason.STOP_PRIVACY_CHIP) - verify(recordingController).stopRecording() + verify(recordingController).stopRecording(eq(StopReason.STOP_PRIVACY_CHIP)) } } diff --git a/packages/SystemUI/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepository.kt b/packages/SystemUI/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepository.kt index debb667bbb15..a19c9b30f68d 100644 --- a/packages/SystemUI/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepository.kt @@ -16,6 +16,7 @@ package com.android.systemui.mediarouter.data.repository +import android.media.projection.StopReason import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.LogBuffer @@ -40,7 +41,7 @@ interface MediaRouterRepository { val castDevices: StateFlow<List<CastDevice>> /** Stops the cast to the given device. */ - fun stopCasting(device: CastDevice) + fun stopCasting(device: CastDevice, @StopReason stopReason: Int) } @SysUISingleton @@ -67,8 +68,8 @@ constructor( .map { it.filter { device -> device.origin == CastDevice.CastOrigin.MediaRouter } } .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList()) - override fun stopCasting(device: CastDevice) { - castController.stopCasting(device) + override fun stopCasting(device: CastDevice, @StopReason stopReason: Int) { + castController.stopCasting(device, stopReason) } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 8a72e8db7216..00b4524e94ab 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.app.Dialog; import android.content.Intent; import android.media.MediaRouter.RouteInfo; +import android.media.projection.StopReason; import android.os.Handler; import android.os.Looper; import android.provider.Settings; @@ -183,7 +184,7 @@ public class CastTile extends QSTileImpl<BooleanState> { }); } } else { - mController.stopCasting(activeDevices.get(0)); + mController.stopCasting(activeDevices.get(0), StopReason.STOP_QS_TILE); } } 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 f3be340f4951..564d1667a3d4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles; import android.app.Dialog; import android.content.Intent; +import android.media.projection.StopReason; import android.os.Handler; import android.os.Looper; import android.service.quicksettings.Tile; @@ -225,7 +226,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> } private void stopRecording() { - mController.stopRecording(); + mController.stopRecording(StopReason.STOP_QS_TILE); } private final class Callback implements RecordingController.RecordingStateChangeCallback { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt index 85aa6745e438..94534479db57 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.qs.tiles.impl.screenrecord.domain.interactor +import android.media.projection.StopReason import android.util.Log import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.DialogCuj @@ -61,7 +62,9 @@ constructor( Log.d(TAG, "Cancelling countdown") withContext(backgroundContext) { recordingController.cancelCountdown() } } - is ScreenRecordModel.Recording -> screenRecordRepository.stopRecording() + is ScreenRecordModel.Recording -> { + screenRecordRepository.stopRecording(StopReason.STOP_QS_TILE) + } is ScreenRecordModel.DoingNothing -> withContext(mainContext) { showPrompt(action.expandable, user.identifier) diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java index d7463f8f0c36..9ee99e45ceeb 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java @@ -23,6 +23,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.media.projection.StopReason; import android.os.Bundle; import android.os.CountDownTimer; import android.os.Process; @@ -58,6 +59,7 @@ public class RecordingController private boolean mIsStarting; private boolean mIsRecording; private PendingIntent mStopIntent; + private @StopReason int mStopReason = StopReason.STOP_UNKNOWN; private final Bundle mInteractiveBroadcastOption; private CountDownTimer mCountDownTimer = null; private final Executor mMainExecutor; @@ -83,7 +85,7 @@ public class RecordingController new UserTracker.Callback() { @Override public void onUserChanged(int newUser, @NonNull Context userContext) { - stopRecording(); + stopRecording(StopReason.STOP_USER_SWITCH); } }; @@ -240,9 +242,11 @@ public class RecordingController } /** - * Stop the recording + * Stop the recording and sets the stop reason to be used by the RecordingService + * @param stopReason the method of the recording stopped (i.e. QS tile, status bar chip, etc.) */ - public void stopRecording() { + public void stopRecording(@StopReason int stopReason) { + mStopReason = stopReason; try { if (mStopIntent != null) { mRecordingControllerLogger.logRecordingStopped(); @@ -277,6 +281,10 @@ public class RecordingController } } + public @StopReason int getStopReason() { + return mStopReason; + } + @Override public void addCallback(@NonNull RecordingStateChangeCallback listener) { mListeners.add(listener); diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index 8c207d13d50e..f7b52719a4f4 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.drawable.Icon; import android.media.MediaRecorder; +import android.media.projection.StopReason; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -78,6 +79,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList private static final String EXTRA_SHOW_TAPS = "extra_showTaps"; private static final String EXTRA_CAPTURE_TARGET = "extra_captureTarget"; private static final String EXTRA_DISPLAY_ID = "extra_displayId"; + private static final String EXTRA_STOP_REASON = "extra_stopReason"; protected static final String ACTION_START = "com.android.systemui.screenrecord.START"; protected static final String ACTION_SHOW_START_NOTIF = @@ -242,7 +244,8 @@ public class RecordingService extends Service implements ScreenMediaRecorderList // 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, USER_ID_NOT_SPECIFIED); - stopService(userId); + int stopReason = intent.getIntExtra(EXTRA_STOP_REASON, mController.getStopReason()); + stopService(userId, stopReason); break; case ACTION_SHARE: @@ -486,11 +489,11 @@ public class RecordingService extends Service implements ScreenMediaRecorderList getTag(), notificationIdForGroup, groupNotif, currentUser); } - private void stopService() { - stopService(USER_ID_NOT_SPECIFIED); + private void stopService(@StopReason int stopReason) { + stopService(USER_ID_NOT_SPECIFIED, stopReason); } - private void stopService(int userId) { + private void stopService(int userId, @StopReason int stopReason) { if (userId == USER_ID_NOT_SPECIFIED) { userId = mUserContextTracker.getUserContext().getUserId(); } @@ -499,7 +502,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList setTapsVisible(mOriginalShowTaps); try { if (getRecorder() != null) { - getRecorder().end(); + getRecorder().end(stopReason); } saveRecording(userId); } catch (RuntimeException exception) { @@ -598,7 +601,8 @@ public class RecordingService extends Service implements ScreenMediaRecorderList * @return */ protected Intent getNotificationIntent(Context context) { - return new Intent(context, this.getClass()).setAction(ACTION_STOP_NOTIF); + return new Intent(context, this.getClass()).setAction(ACTION_STOP_NOTIF) + .putExtra(EXTRA_STOP_REASON, StopReason.STOP_HOST_APP); } private Intent getShareIntent(Context context, Uri path) { @@ -610,14 +614,17 @@ public class RecordingService extends Service implements ScreenMediaRecorderList @Override public void onInfo(MediaRecorder mr, int what, int extra) { Log.d(getTag(), "Media recorder info: " + what); - onStartCommand(getStopIntent(this), 0, 0); + // Stop due to record reaching size limits so log as stopping due to error + Intent stopIntent = getStopIntent(this); + stopIntent.putExtra(EXTRA_STOP_REASON, StopReason.STOP_ERROR); + onStartCommand(stopIntent, 0, 0); } @Override - public void onStopped() { + public void onStopped(@StopReason int stopReason) { if (mController.isRecording()) { Log.d(getTag(), "Stopping recording because the system requested the stop"); - stopService(); + stopService(stopReason); } } } diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java index 2ca0621635a7..f4455bfb7048 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java @@ -41,6 +41,7 @@ import android.media.projection.IMediaProjection; import android.media.projection.IMediaProjectionManager; import android.media.projection.MediaProjection; import android.media.projection.MediaProjectionManager; +import android.media.projection.StopReason; import android.net.Uri; import android.os.Handler; import android.os.IBinder; @@ -300,7 +301,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback { /** * End screen recording, throws an exception if stopping recording failed */ - void end() throws IOException { + void end(@StopReason int stopReason) throws IOException { Closer closer = new Closer(); // MediaRecorder might throw RuntimeException if stopped immediately after starting @@ -309,7 +310,17 @@ public class ScreenMediaRecorder extends MediaProjection.Callback { closer.register(mMediaRecorder::release); closer.register(mInputSurface::release); closer.register(mVirtualDisplay::release); - closer.register(mMediaProjection::stop); + closer.register(() -> { + if (stopReason == StopReason.STOP_UNKNOWN) { + // Attempt to call MediaProjection#stop() even if it might have already been called. + // If projection has already been stopped, then nothing will happen. Else, stop + // will be logged as a manually requested stop from host app. + mMediaProjection.stop(); + } else { + // In any other case, the stop reason is related to the recorder, so pass it on here + mMediaProjection.stop(stopReason); + } + }); closer.register(this::stopInternalAudioRecording); closer.close(); @@ -323,7 +334,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback { @Override public void onStop() { Log.d(TAG, "The system notified about stopping the projection"); - mListener.onStopped(); + mListener.onStopped(StopReason.STOP_UNKNOWN); } private void stopInternalAudioRecording() { @@ -453,7 +464,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback { * For example, this might happen when doing partial screen sharing of an app * and the app that is being captured is closed. */ - void onStopped(); + void onStopped(@StopReason int stopReason); } /** diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt index 9eeb3b9576d8..b6b8ffa11495 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt @@ -16,6 +16,7 @@ package com.android.systemui.screenrecord.data.repository +import android.media.projection.StopReason import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.screenrecord.RecordingController @@ -41,7 +42,7 @@ interface ScreenRecordRepository { val screenRecordState: Flow<ScreenRecordModel> /** Stops the recording. */ - suspend fun stopRecording() + suspend fun stopRecording(@StopReason stopReason: Int) } @SysUISingleton @@ -95,7 +96,7 @@ constructor( } } - override suspend fun stopRecording() { - withContext(bgCoroutineContext) { recordingController.stopRecording() } + override suspend fun stopRecording(@StopReason stopReason: Int) { + withContext(bgCoroutineContext) { recordingController.stopRecording(stopReason) } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt index b3dbf299e7cc..229cef910c6e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.chips.casttootherdevice.domain.interactor +import android.media.projection.StopReason import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.LogBuffer @@ -65,7 +66,9 @@ constructor( /** Stops the currently active MediaRouter cast. */ fun stopCasting() { - activeCastDevice.value?.let { mediaRouterRepository.stopCasting(it) } + activeCastDevice.value?.let { + mediaRouterRepository.stopCasting(it, StopReason.STOP_PRIVACY_CHIP) + } } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt index f5952f4804fc..0b5e669b5fca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.chips.screenrecord.domain.interactor +import android.media.projection.StopReason import com.android.systemui.Flags import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -140,7 +141,7 @@ constructor( /** Stops the recording. */ fun stopRecording() { - scope.launch { screenRecordRepository.stopRecording() } + scope.launch { screenRecordRepository.stopRecording(StopReason.STOP_PRIVACY_CHIP) } } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java index a3dcc3b6f851..ece5a3facdf4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.policy; +import android.media.projection.StopReason; import com.android.systemui.Dumpable; import com.android.systemui.statusbar.policy.CastController.Callback; @@ -26,7 +27,7 @@ public interface CastController extends CallbackController<Callback>, Dumpable { void setCurrentUserId(int currentUserId); List<CastDevice> getCastDevices(); void startCasting(CastDevice device); - void stopCasting(CastDevice device); + void stopCasting(CastDevice device, @StopReason int stopReason); /** * @return whether we have a connected device. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java index 52f80fbf50fd..ab208506f203 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java @@ -185,13 +185,13 @@ public class CastControllerImpl implements CastController { } @Override - public void stopCasting(CastDevice device) { + public void stopCasting(CastDevice device, @StopReason int stopReason) { final boolean isProjection = device.getTag() instanceof MediaProjectionInfo; mLogger.logStopCasting(isProjection); if (isProjection) { final MediaProjectionInfo projection = (MediaProjectionInfo) device.getTag(); if (Objects.equals(mProjectionManager.getActiveProjectionInfo(), projection)) { - mProjectionManager.stopActiveProjection(StopReason.STOP_QS_TILE); + mProjectionManager.stopActiveProjection(stopReason); } else { mLogger.logStopCastingNoProjection(projection); } 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 afff4858499a..a17f100904be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java @@ -36,6 +36,7 @@ import android.app.Dialog; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.media.projection.StopReason; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -154,7 +155,7 @@ public class RecordingControllerTest extends SysuiTestCase { PendingIntent stopIntent = Mockito.mock(PendingIntent.class); mController.startCountdown(0, 0, startIntent, stopIntent); - mController.stopRecording(); + mController.stopRecording(StopReason.STOP_UNKNOWN); assertFalse(mController.isStarting()); assertFalse(mController.isRecording()); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediarouter/data/repository/FakeMediaRouterRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediarouter/data/repository/FakeMediaRouterRepository.kt index 8aa7a03710cb..d5637cbe36b5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediarouter/data/repository/FakeMediaRouterRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediarouter/data/repository/FakeMediaRouterRepository.kt @@ -16,6 +16,7 @@ package com.android.systemui.mediarouter.data.repository +import android.media.projection.StopReason import com.android.systemui.statusbar.policy.CastDevice import kotlinx.coroutines.flow.MutableStateFlow @@ -25,7 +26,7 @@ class FakeMediaRouterRepository : MediaRouterRepository { var lastStoppedDevice: CastDevice? = null private set - override fun stopCasting(device: CastDevice) { + override fun stopCasting(device: CastDevice, @StopReason stopReason: Int) { lastStoppedDevice = device } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt index 30b4763118a7..4c9e1740b3b5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt @@ -16,6 +16,7 @@ package com.android.systemui.screenrecord.data.repository +import android.media.projection.StopReason import com.android.systemui.screenrecord.data.model.ScreenRecordModel import kotlinx.coroutines.flow.MutableStateFlow @@ -25,7 +26,7 @@ class FakeScreenRecordRepository : ScreenRecordRepository { var stopRecordingInvoked = false - override suspend fun stopRecording() { + override suspend fun stopRecording(@StopReason stopReason: Int) { stopRecordingInvoked = true } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeCastController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeCastController.kt index 2df0c7a5386e..da6b2ae46d2d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeCastController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeCastController.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.policy +import android.media.projection.StopReason import java.io.PrintWriter class FakeCastController : CastController { @@ -45,7 +46,7 @@ class FakeCastController : CastController { override fun startCasting(device: CastDevice?) {} - override fun stopCasting(device: CastDevice?) { + override fun stopCasting(device: CastDevice?, @StopReason stopReason: Int) { lastStoppedDevice = device } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckerCastController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckerCastController.java index 2249bc0b667f..857dc8584be9 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckerCastController.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckerCastController.java @@ -16,6 +16,7 @@ package com.android.systemui.utils.leaks; +import android.media.projection.StopReason; import android.testing.LeakCheck; import com.android.systemui.statusbar.policy.CastController; @@ -51,7 +52,7 @@ public class LeakCheckerCastController extends BaseLeakChecker<Callback> impleme } @Override - public void stopCasting(CastDevice device) { + public void stopCasting(CastDevice device, @StopReason int stopReason) { } |