Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 016dce89 authored by Andre Le's avatar Andre Le
Browse files

QSDetailedView: Add view binder to ScreenRecordDetailsViewModel

Add an instance of ScreenRecordPermissionViewBinder and
RecordingController to ScreenRecordDetailsViewModel to control the logic
within the UI of screen record details view. With CL, we can complete
the full flow of start screen recording with any configurations within
the screen record details view.

Bug: b/378514312
Flag: com.android.systemui.qs_tile_detailed_view
Test: ScreenRecordTileTest, ScreenRecordPermissionDialogDelegateTest
Test: Click on screen record tile in the QS -> can start do screen
recording within the details view.

Change-Id: Ifc64cfed4243e885694c0e99edc5f7ab898ce464
parent c84a0332
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -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;
    }
+24 −10
Original line number Diff line number Diff line
@@ -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() },
        )
    }

@@ -54,8 +72,4 @@ class ScreenRecordDetailsViewModel() : TileDetailsViewModel() {
        // No sub-title in this tile.
        return ""
    }

    companion object {
        private val VIEW_MAX_HEIGHT: Dp = 320.dp
    }
}
+27 −3
Original line number Diff line number Diff line
@@ -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";
@@ -118,7 +120,8 @@ public class RecordingController
            MediaProjectionMetricsLogger mediaProjectionMetricsLogger,
            ScreenCaptureDisabledDialogDelegate screenCaptureDisabledDialogDelegate,
            ScreenRecordPermissionDialogDelegate.Factory
                    screenRecordPermissionDialogDelegateFactory) {
                    screenRecordPermissionDialogDelegateFactory,
            ScreenRecordPermissionViewBinder.Factory screenRecordPermissionViewBinderFactory) {
        mMainExecutor = mainExecutor;
        mDevicePolicyResolver = devicePolicyResolver;
        mBroadcastDispatcher = broadcastDispatcher;
@@ -127,6 +130,7 @@ public class RecordingController
        mMediaProjectionMetricsLogger = mediaProjectionMetricsLogger;
        mScreenCaptureDisabledDialogDelegate = screenCaptureDisabledDialogDelegate;
        mScreenRecordPermissionDialogDelegateFactory = screenRecordPermissionDialogDelegateFactory;
        mScreenRecordPermissionViewBinderFactory = screenRecordPermissionViewBinderFactory;

        BroadcastOptions options = BroadcastOptions.makeBasic();
        options.setInteractive(true);
@@ -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();
        }

@@ -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
+35 −0
Original line number Diff line number Diff line
@@ -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,
@@ -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
+29 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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(
@@ -116,7 +123,8 @@ public class RecordingControllerTest extends SysuiTestCase {
                new RecordingControllerLogger(logcatLogBuffer("RecordingControllerTest")),
                mMediaProjectionMetricsLogger,
                mScreenCaptureDisabledDialogDelegate,
                mScreenRecordPermissionDialogDelegateFactory
                mScreenRecordPermissionDialogDelegateFactory,
                mScreenRecordPermissionViewBinderFactory
        );
        mController.addCallback(mCallback);
    }
@@ -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);