Loading packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +3 −2 Original line number Diff line number Diff line Loading @@ -191,8 +191,9 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> @Override public boolean getDetailsViewModel(Consumer<TileDetailsViewModel> callback) { handleClick(() -> callback.accept(new ScreenRecordDetailsViewModel()) handleClick(() -> executeWhenUnlockedKeyguard( () -> callback.accept(new ScreenRecordDetailsViewModel(mController, this::onStartRecordingClicked))) ); return true; } Loading packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt +24 −10 Original line number Diff line number Diff line Loading @@ -17,27 +17,45 @@ package com.android.systemui.qs.tiles.dialog import android.view.LayoutInflater import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import com.android.systemui.plugins.qs.TileDetailsViewModel import com.android.systemui.res.R import com.android.systemui.screenrecord.RecordingController import com.android.systemui.screenrecord.ScreenRecordPermissionViewBinder /** The view model used for the screen record details view in the Quick Settings */ class ScreenRecordDetailsViewModel() : TileDetailsViewModel() { class ScreenRecordDetailsViewModel( private val recordingController: RecordingController, private val onStartRecordingClicked: Runnable, ) : TileDetailsViewModel() { private var viewBinder: ScreenRecordPermissionViewBinder = recordingController.createScreenRecordPermissionViewBinder(onStartRecordingClicked) @Composable override fun GetContentView() { // TODO(b/378514312): Finish implementing this function. if (recordingController.isScreenCaptureDisabled) { // TODO(b/388345506): Show disabled page here. return } AndroidView( modifier = Modifier.fillMaxWidth().heightIn(max = VIEW_MAX_HEIGHT), modifier = Modifier.fillMaxWidth().fillMaxHeight(), factory = { context -> // Inflate with the existing dialog xml layout LayoutInflater.from(context).inflate(R.layout.screen_share_dialog, null) val view = LayoutInflater.from(context).inflate(R.layout.screen_share_dialog, null) viewBinder.bind(view) view // TODO(b/378514473): Revamp the details view according to the spec. }, onRelease = { viewBinder.unbind() }, ) } Loading @@ -54,8 +72,4 @@ class ScreenRecordDetailsViewModel() : TileDetailsViewModel() { // No sub-title in this tile. return "" } companion object { private val VIEW_MAX_HEIGHT: Dp = 320.dp } } packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +27 −3 Original line number Diff line number Diff line Loading @@ -70,6 +70,8 @@ public class RecordingController private final ScreenCaptureDisabledDialogDelegate mScreenCaptureDisabledDialogDelegate; private final ScreenRecordPermissionDialogDelegate.Factory mScreenRecordPermissionDialogDelegateFactory; private final ScreenRecordPermissionViewBinder.Factory mScreenRecordPermissionViewBinderFactory; protected static final String INTENT_UPDATE_STATE = "com.android.systemui.screenrecord.UPDATE_STATE"; Loading Loading @@ -118,7 +120,8 @@ public class RecordingController MediaProjectionMetricsLogger mediaProjectionMetricsLogger, ScreenCaptureDisabledDialogDelegate screenCaptureDisabledDialogDelegate, ScreenRecordPermissionDialogDelegate.Factory screenRecordPermissionDialogDelegateFactory) { screenRecordPermissionDialogDelegateFactory, ScreenRecordPermissionViewBinder.Factory screenRecordPermissionViewBinderFactory) { mMainExecutor = mainExecutor; mDevicePolicyResolver = devicePolicyResolver; mBroadcastDispatcher = broadcastDispatcher; Loading @@ -127,6 +130,7 @@ public class RecordingController mMediaProjectionMetricsLogger = mediaProjectionMetricsLogger; mScreenCaptureDisabledDialogDelegate = screenCaptureDisabledDialogDelegate; mScreenRecordPermissionDialogDelegateFactory = screenRecordPermissionDialogDelegateFactory; mScreenRecordPermissionViewBinderFactory = screenRecordPermissionViewBinderFactory; BroadcastOptions options = BroadcastOptions.makeBasic(); options.setInteractive(true); Loading @@ -151,8 +155,7 @@ public class RecordingController * If screen capturing is currently not allowed it will return a dialog * that warns users about it. */ public Dialog createScreenRecordDialog(@Nullable Runnable onStartRecordingClicked) { if (mDevicePolicyResolver.get() .isScreenCaptureCompletelyDisabled(getHostUserHandle())) { if (isScreenCaptureDisabled()) { return mScreenCaptureDisabledDialogDelegate.createSysUIDialog(); } Loading @@ -164,6 +167,27 @@ public class RecordingController .createDialog(); } /** * Create a view binder that controls the logic of views inside the screen record permission * view. * @param onStartRecordingClicked the callback that is run when the start button is clicked. */ public ScreenRecordPermissionViewBinder createScreenRecordPermissionViewBinder( @Nullable Runnable onStartRecordingClicked ) { return mScreenRecordPermissionViewBinderFactory .create(getHostUserHandle(), getHostUid(), this, onStartRecordingClicked); } /** * Check if screen capture is currently disabled for this device and user. */ public boolean isScreenCaptureDisabled() { return mDevicePolicyResolver.get() .isScreenCaptureCompletelyDisabled(getHostUserHandle()); } /** * Start counting down in preparation to start a recording * @param ms Total time in ms to wait before starting Loading packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionViewBinder.kt +35 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,9 @@ import com.android.systemui.mediaprojection.permission.ScreenShareOption import com.android.systemui.plugins.ActivityStarter import com.android.systemui.res.R import com.android.systemui.settings.UserContextProvider import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject class ScreenRecordPermissionViewBinder( private val hostUserHandle: UserHandle, Loading @@ -68,6 +71,38 @@ class ScreenRecordPermissionViewBinder( mediaProjectionMetricsLogger, defaultSelectedMode, ) { @AssistedInject constructor( @Assisted hostUserHandle: UserHandle, @Assisted hostUid: Int, mediaProjectionMetricsLogger: MediaProjectionMetricsLogger, displayManager: DisplayManager, @Assisted controller: RecordingController, activityStarter: ActivityStarter, userContextProvider: UserContextProvider, @Assisted onStartRecordingClicked: Runnable?, ) : this( hostUserHandle, hostUid, mediaProjectionMetricsLogger, defaultSelectedMode = SINGLE_APP, displayManager, controller, activityStarter, userContextProvider, onStartRecordingClicked, ) @AssistedFactory interface Factory { fun create( hostUserHandle: UserHandle, hostUid: Int, recordingController: RecordingController, onStartRecordingClicked: Runnable?, ): ScreenRecordPermissionViewBinder } private lateinit var tapsSwitch: Switch private lateinit var audioSwitch: Switch private lateinit var tapsView: View Loading packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java +29 −1 Original line number Diff line number Diff line Loading @@ -88,8 +88,13 @@ public class RecordingControllerTest extends SysuiTestCase { private ScreenRecordPermissionDialogDelegate.Factory mScreenRecordPermissionDialogDelegateFactory; @Mock private ScreenRecordPermissionViewBinder.Factory mScreenRecordPermissionViewBinderFactory; @Mock private ScreenRecordPermissionDialogDelegate mScreenRecordPermissionDialogDelegate; @Mock private ScreenRecordPermissionViewBinder mScreenRecordPermissionViewBinder; @Mock private SystemUIDialog mScreenRecordSystemUIDialog; private RecordingController mController; Loading @@ -106,6 +111,8 @@ public class RecordingControllerTest extends SysuiTestCase { .thenReturn(mScreenCaptureDisabledDialog); when(mScreenRecordPermissionDialogDelegateFactory.create(any(), any(), anyInt(), any())) .thenReturn(mScreenRecordPermissionDialogDelegate); when(mScreenRecordPermissionViewBinderFactory.create(any(), anyInt(), any(), any())) .thenReturn(mScreenRecordPermissionViewBinder); when(mScreenRecordPermissionDialogDelegate.createDialog()) .thenReturn(mScreenRecordSystemUIDialog); mController = new RecordingController( Loading @@ -116,7 +123,8 @@ public class RecordingControllerTest extends SysuiTestCase { new RecordingControllerLogger(logcatLogBuffer("RecordingControllerTest")), mMediaProjectionMetricsLogger, mScreenCaptureDisabledDialogDelegate, mScreenRecordPermissionDialogDelegateFactory mScreenRecordPermissionDialogDelegateFactory, mScreenRecordPermissionViewBinderFactory ); mController.addCallback(mCallback); } Loading Loading @@ -237,6 +245,26 @@ public class RecordingControllerTest extends SysuiTestCase { .isInstanceOf(ScreenRecordPermissionDialogDelegate.class); } @Test public void testCreateScreenRecordPermissionViewBinder() { ScreenRecordPermissionViewBinder viewBinder = mController.createScreenRecordPermissionViewBinder( /* onStartRecordingClicked= */ null); assertThat(viewBinder).isEqualTo(mScreenRecordPermissionViewBinder); } @Test public void testScreenCapturingAllowed_returnsFalseIsScreenCaptureDisabled() { when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false); assertFalse(mController.isScreenCaptureDisabled()); } @Test public void testScreenCapturingNotAllowed_returnsTrueIsScreenCaptureDisabled() { when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(true); assertTrue(mController.isScreenCaptureDisabled()); } @Test public void testScreenCapturingAllowed_logsProjectionInitiated() { when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false); Loading Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +3 −2 Original line number Diff line number Diff line Loading @@ -191,8 +191,9 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> @Override public boolean getDetailsViewModel(Consumer<TileDetailsViewModel> callback) { handleClick(() -> callback.accept(new ScreenRecordDetailsViewModel()) handleClick(() -> executeWhenUnlockedKeyguard( () -> callback.accept(new ScreenRecordDetailsViewModel(mController, this::onStartRecordingClicked))) ); return true; } Loading
packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/ScreenRecordDetailsViewModel.kt +24 −10 Original line number Diff line number Diff line Loading @@ -17,27 +17,45 @@ package com.android.systemui.qs.tiles.dialog import android.view.LayoutInflater import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import com.android.systemui.plugins.qs.TileDetailsViewModel import com.android.systemui.res.R import com.android.systemui.screenrecord.RecordingController import com.android.systemui.screenrecord.ScreenRecordPermissionViewBinder /** The view model used for the screen record details view in the Quick Settings */ class ScreenRecordDetailsViewModel() : TileDetailsViewModel() { class ScreenRecordDetailsViewModel( private val recordingController: RecordingController, private val onStartRecordingClicked: Runnable, ) : TileDetailsViewModel() { private var viewBinder: ScreenRecordPermissionViewBinder = recordingController.createScreenRecordPermissionViewBinder(onStartRecordingClicked) @Composable override fun GetContentView() { // TODO(b/378514312): Finish implementing this function. if (recordingController.isScreenCaptureDisabled) { // TODO(b/388345506): Show disabled page here. return } AndroidView( modifier = Modifier.fillMaxWidth().heightIn(max = VIEW_MAX_HEIGHT), modifier = Modifier.fillMaxWidth().fillMaxHeight(), factory = { context -> // Inflate with the existing dialog xml layout LayoutInflater.from(context).inflate(R.layout.screen_share_dialog, null) val view = LayoutInflater.from(context).inflate(R.layout.screen_share_dialog, null) viewBinder.bind(view) view // TODO(b/378514473): Revamp the details view according to the spec. }, onRelease = { viewBinder.unbind() }, ) } Loading @@ -54,8 +72,4 @@ class ScreenRecordDetailsViewModel() : TileDetailsViewModel() { // No sub-title in this tile. return "" } companion object { private val VIEW_MAX_HEIGHT: Dp = 320.dp } }
packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +27 −3 Original line number Diff line number Diff line Loading @@ -70,6 +70,8 @@ public class RecordingController private final ScreenCaptureDisabledDialogDelegate mScreenCaptureDisabledDialogDelegate; private final ScreenRecordPermissionDialogDelegate.Factory mScreenRecordPermissionDialogDelegateFactory; private final ScreenRecordPermissionViewBinder.Factory mScreenRecordPermissionViewBinderFactory; protected static final String INTENT_UPDATE_STATE = "com.android.systemui.screenrecord.UPDATE_STATE"; Loading Loading @@ -118,7 +120,8 @@ public class RecordingController MediaProjectionMetricsLogger mediaProjectionMetricsLogger, ScreenCaptureDisabledDialogDelegate screenCaptureDisabledDialogDelegate, ScreenRecordPermissionDialogDelegate.Factory screenRecordPermissionDialogDelegateFactory) { screenRecordPermissionDialogDelegateFactory, ScreenRecordPermissionViewBinder.Factory screenRecordPermissionViewBinderFactory) { mMainExecutor = mainExecutor; mDevicePolicyResolver = devicePolicyResolver; mBroadcastDispatcher = broadcastDispatcher; Loading @@ -127,6 +130,7 @@ public class RecordingController mMediaProjectionMetricsLogger = mediaProjectionMetricsLogger; mScreenCaptureDisabledDialogDelegate = screenCaptureDisabledDialogDelegate; mScreenRecordPermissionDialogDelegateFactory = screenRecordPermissionDialogDelegateFactory; mScreenRecordPermissionViewBinderFactory = screenRecordPermissionViewBinderFactory; BroadcastOptions options = BroadcastOptions.makeBasic(); options.setInteractive(true); Loading @@ -151,8 +155,7 @@ public class RecordingController * If screen capturing is currently not allowed it will return a dialog * that warns users about it. */ public Dialog createScreenRecordDialog(@Nullable Runnable onStartRecordingClicked) { if (mDevicePolicyResolver.get() .isScreenCaptureCompletelyDisabled(getHostUserHandle())) { if (isScreenCaptureDisabled()) { return mScreenCaptureDisabledDialogDelegate.createSysUIDialog(); } Loading @@ -164,6 +167,27 @@ public class RecordingController .createDialog(); } /** * Create a view binder that controls the logic of views inside the screen record permission * view. * @param onStartRecordingClicked the callback that is run when the start button is clicked. */ public ScreenRecordPermissionViewBinder createScreenRecordPermissionViewBinder( @Nullable Runnable onStartRecordingClicked ) { return mScreenRecordPermissionViewBinderFactory .create(getHostUserHandle(), getHostUid(), this, onStartRecordingClicked); } /** * Check if screen capture is currently disabled for this device and user. */ public boolean isScreenCaptureDisabled() { return mDevicePolicyResolver.get() .isScreenCaptureCompletelyDisabled(getHostUserHandle()); } /** * Start counting down in preparation to start a recording * @param ms Total time in ms to wait before starting Loading
packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionViewBinder.kt +35 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,9 @@ import com.android.systemui.mediaprojection.permission.ScreenShareOption import com.android.systemui.plugins.ActivityStarter import com.android.systemui.res.R import com.android.systemui.settings.UserContextProvider import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject class ScreenRecordPermissionViewBinder( private val hostUserHandle: UserHandle, Loading @@ -68,6 +71,38 @@ class ScreenRecordPermissionViewBinder( mediaProjectionMetricsLogger, defaultSelectedMode, ) { @AssistedInject constructor( @Assisted hostUserHandle: UserHandle, @Assisted hostUid: Int, mediaProjectionMetricsLogger: MediaProjectionMetricsLogger, displayManager: DisplayManager, @Assisted controller: RecordingController, activityStarter: ActivityStarter, userContextProvider: UserContextProvider, @Assisted onStartRecordingClicked: Runnable?, ) : this( hostUserHandle, hostUid, mediaProjectionMetricsLogger, defaultSelectedMode = SINGLE_APP, displayManager, controller, activityStarter, userContextProvider, onStartRecordingClicked, ) @AssistedFactory interface Factory { fun create( hostUserHandle: UserHandle, hostUid: Int, recordingController: RecordingController, onStartRecordingClicked: Runnable?, ): ScreenRecordPermissionViewBinder } private lateinit var tapsSwitch: Switch private lateinit var audioSwitch: Switch private lateinit var tapsView: View Loading
packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java +29 −1 Original line number Diff line number Diff line Loading @@ -88,8 +88,13 @@ public class RecordingControllerTest extends SysuiTestCase { private ScreenRecordPermissionDialogDelegate.Factory mScreenRecordPermissionDialogDelegateFactory; @Mock private ScreenRecordPermissionViewBinder.Factory mScreenRecordPermissionViewBinderFactory; @Mock private ScreenRecordPermissionDialogDelegate mScreenRecordPermissionDialogDelegate; @Mock private ScreenRecordPermissionViewBinder mScreenRecordPermissionViewBinder; @Mock private SystemUIDialog mScreenRecordSystemUIDialog; private RecordingController mController; Loading @@ -106,6 +111,8 @@ public class RecordingControllerTest extends SysuiTestCase { .thenReturn(mScreenCaptureDisabledDialog); when(mScreenRecordPermissionDialogDelegateFactory.create(any(), any(), anyInt(), any())) .thenReturn(mScreenRecordPermissionDialogDelegate); when(mScreenRecordPermissionViewBinderFactory.create(any(), anyInt(), any(), any())) .thenReturn(mScreenRecordPermissionViewBinder); when(mScreenRecordPermissionDialogDelegate.createDialog()) .thenReturn(mScreenRecordSystemUIDialog); mController = new RecordingController( Loading @@ -116,7 +123,8 @@ public class RecordingControllerTest extends SysuiTestCase { new RecordingControllerLogger(logcatLogBuffer("RecordingControllerTest")), mMediaProjectionMetricsLogger, mScreenCaptureDisabledDialogDelegate, mScreenRecordPermissionDialogDelegateFactory mScreenRecordPermissionDialogDelegateFactory, mScreenRecordPermissionViewBinderFactory ); mController.addCallback(mCallback); } Loading Loading @@ -237,6 +245,26 @@ public class RecordingControllerTest extends SysuiTestCase { .isInstanceOf(ScreenRecordPermissionDialogDelegate.class); } @Test public void testCreateScreenRecordPermissionViewBinder() { ScreenRecordPermissionViewBinder viewBinder = mController.createScreenRecordPermissionViewBinder( /* onStartRecordingClicked= */ null); assertThat(viewBinder).isEqualTo(mScreenRecordPermissionViewBinder); } @Test public void testScreenCapturingAllowed_returnsFalseIsScreenCaptureDisabled() { when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false); assertFalse(mController.isScreenCaptureDisabled()); } @Test public void testScreenCapturingNotAllowed_returnsTrueIsScreenCaptureDisabled() { when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(true); assertTrue(mController.isScreenCaptureDisabled()); } @Test public void testScreenCapturingAllowed_logsProjectionInitiated() { when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false); Loading