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

Commit e1dd7544 authored by Chris Göllner's avatar Chris Göllner Committed by Android (Google) Code Review
Browse files

Merge "[Partial Screen Sharing] Fix media projection cts tests on android auto" into main

parents efb191ca 3e71bf75
Loading
Loading
Loading
Loading
+28 −26
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.systemui.mediaprojection.permission

import android.app.AlertDialog
import android.content.Context
import android.os.Bundle
import android.view.Gravity
@@ -28,36 +29,36 @@ import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.Spinner
import android.widget.TextView
import androidx.annotation.CallSuper
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.LayoutRes
import androidx.annotation.StringRes
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.phone.DialogDelegate

/** Base permission dialog for screen share and recording */
open class BaseScreenSharePermissionDialog(
    context: Context,
abstract class BaseMediaProjectionPermissionDialogDelegate<T : AlertDialog>(
    private val screenShareOptions: List<ScreenShareOption>,
    private val appName: String?,
    private val hostUid: Int,
    private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
    @DrawableRes private val dialogIconDrawable: Int? = null,
    @ColorRes private val dialogIconTint: Int? = null,
) : SystemUIDialog(context), AdapterView.OnItemSelectedListener {
) : DialogDelegate<T>, AdapterView.OnItemSelectedListener {
    private lateinit var dialogTitle: TextView
    private lateinit var startButton: TextView
    private lateinit var cancelButton: TextView
    private lateinit var warning: TextView
    private lateinit var screenShareModeSpinner: Spinner
    private var hasCancelBeenLogged: Boolean = false
    protected lateinit var dialog: AlertDialog
    var selectedScreenShareOption: ScreenShareOption = screenShareOptions.first()

    override fun dismiss() {
        super.dismiss()

        // Dismiss can be called multiple times and we only want to log once.
    @CallSuper
    override fun onStop(dialog: T) {
        // onStop can be called multiple times and we only want to log once.
        if (hasCancelBeenLogged) {
            return
        }
@@ -66,42 +67,43 @@ open class BaseScreenSharePermissionDialog(
        hasCancelBeenLogged = true
    }

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
        window?.setGravity(Gravity.CENTER)
        setContentView(R.layout.screen_share_dialog)
        dialogTitle = requireViewById(R.id.screen_share_dialog_title)
        warning = requireViewById(R.id.text_warning)
        startButton = requireViewById(android.R.id.button1)
        cancelButton = requireViewById(android.R.id.button2)
    @CallSuper
    override fun onCreate(dialog: T, savedInstanceState: Bundle?) {
        this.dialog = dialog
        dialog.window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
        dialog.window?.setGravity(Gravity.CENTER)
        dialog.setContentView(R.layout.screen_share_dialog)
        dialogTitle = dialog.requireViewById(R.id.screen_share_dialog_title)
        warning = dialog.requireViewById(R.id.text_warning)
        startButton = dialog.requireViewById(android.R.id.button1)
        cancelButton = dialog.requireViewById(android.R.id.button2)
        updateIcon()
        initScreenShareOptions()
        createOptionsView(getOptionsViewLayoutId())
    }

    private fun updateIcon() {
        val icon = requireViewById<ImageView>(R.id.screen_share_dialog_icon)
        val icon = dialog.requireViewById<ImageView>(R.id.screen_share_dialog_icon)
        if (dialogIconTint != null) {
            icon.setColorFilter(context.getColor(dialogIconTint))
            icon.setColorFilter(dialog.context.getColor(dialogIconTint))
        }
        if (dialogIconDrawable != null) {
            icon.setImageDrawable(context.getDrawable(dialogIconDrawable))
            icon.setImageDrawable(dialog.context.getDrawable(dialogIconDrawable))
        }
    }

    protected fun initScreenShareOptions() {
    private fun initScreenShareOptions() {
        selectedScreenShareOption = screenShareOptions.first()
        warning.text = warningText
        initScreenShareSpinner()
    }

    private val warningText: String
        get() = context.getString(selectedScreenShareOption.warningText, appName)
        get() = dialog.context.getString(selectedScreenShareOption.warningText, appName)

    private fun initScreenShareSpinner() {
        val adapter = OptionsAdapter(context.applicationContext, screenShareOptions)
        screenShareModeSpinner = requireViewById(R.id.screen_share_mode_spinner)
        val adapter = OptionsAdapter(dialog.context.applicationContext, screenShareOptions)
        screenShareModeSpinner = dialog.requireViewById(R.id.screen_share_mode_spinner)
        screenShareModeSpinner.adapter = adapter
        screenShareModeSpinner.onItemSelectedListener = this
    }
@@ -115,7 +117,7 @@ open class BaseScreenSharePermissionDialog(

    /** Protected methods for the text updates & functionality */
    protected fun setDialogTitle(@StringRes stringId: Int) {
        val title = context.getString(stringId, appName)
        val title = dialog.context.getString(stringId, appName)
        dialogTitle.text = title
    }

@@ -137,7 +139,7 @@ open class BaseScreenSharePermissionDialog(

    private fun createOptionsView(@LayoutRes layoutId: Int?) {
        if (layoutId == null) return
        val stub = requireViewById<View>(R.id.options_stub) as ViewStub
        val stub = dialog.requireViewById<View>(R.id.options_stub) as ViewStub
        stub.layoutResource = layoutId
        stub.inflate()
    }
+24 −20
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelect
import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver;
import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialog;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.AlertDialogWithDelegate;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.Utils;

@@ -222,22 +223,25 @@ public class MediaProjectionPermissionActivity extends Activity
        // the correct screen width when in split screen.
        Context dialogContext = getApplicationContext();
        if (isPartialScreenSharingEnabled()) {
            mDialog = new MediaProjectionPermissionDialog(
            MediaProjectionPermissionDialogDelegate delegate =
                    new MediaProjectionPermissionDialogDelegate(
                            dialogContext,
                            getMediaProjectionConfig(),
                    () -> {
                        MediaProjectionPermissionDialog dialog =
                                (MediaProjectionPermissionDialog) mDialog;
                        ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption();
                            dialog -> {
                                ScreenShareOption selectedOption =
                                        dialog.getSelectedScreenShareOption();
                                grantMediaProjectionPermission(selectedOption.getMode());
                            },
                            () -> finish(RECORD_CANCEL, /* projection= */ null),
                            appName,
                            mUid,
                            mMediaProjectionMetricsLogger);
            mDialog =
                    new AlertDialogWithDelegate(
                            dialogContext, R.style.Theme_SystemUI_Dialog, delegate);
        } else {
            AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(dialogContext,
                    R.style.Theme_SystemUI_Dialog)
            AlertDialog.Builder dialogBuilder =
                    new AlertDialog.Builder(dialogContext, R.style.Theme_SystemUI_Dialog)
                            .setTitle(dialogTitle)
                            .setIcon(R.drawable.ic_media_projection_permission)
                            .setMessage(dialogText)
+10 −9
Original line number Diff line number Diff line
@@ -15,31 +15,32 @@
 */
package com.android.systemui.mediaprojection.permission

import android.app.AlertDialog
import android.content.Context
import android.media.projection.MediaProjectionConfig
import android.os.Bundle
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.res.R
import java.util.function.Consumer

/** Dialog to select screen recording options */
class MediaProjectionPermissionDialog(
class MediaProjectionPermissionDialogDelegate(
    context: Context,
    mediaProjectionConfig: MediaProjectionConfig?,
    private val onStartRecordingClicked: Runnable,
    private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>,
    private val onCancelClicked: Runnable,
    private val appName: String?,
    hostUid: Int,
    mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
) :
    BaseScreenSharePermissionDialog(
        context,
    BaseMediaProjectionPermissionDialogDelegate<AlertDialog>(
        createOptionList(context, appName, mediaProjectionConfig),
        appName,
        hostUid,
        mediaProjectionMetricsLogger
    ) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    override fun onCreate(dialog: AlertDialog, savedInstanceState: Bundle?) {
        super.onCreate(dialog, savedInstanceState)
        // TODO(b/270018943): Handle the case of System sharing (not recording nor casting)
        if (appName == null) {
            setDialogTitle(R.string.media_projection_entry_cast_permission_dialog_title)
@@ -51,12 +52,12 @@ class MediaProjectionPermissionDialog(
        setStartButtonOnClickListener {
            // Note that it is important to run this callback before dismissing, so that the
            // callback can disable the dialog exit animation if it wants to.
            onStartRecordingClicked.run()
            dismiss()
            onStartRecordingClicked.accept(this)
            dialog.dismiss()
        }
        setCancelButtonOnClickListener {
            onCancelClicked.run()
            dismiss()
            dialog.dismiss()
        }
    }

+13 −10
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDi
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.CallbackController;

import dagger.Lazy;
@@ -75,6 +76,7 @@ public class RecordingController
    private final UserContextProvider mUserContextProvider;
    private final UserTracker mUserTracker;
    private final MediaProjectionMetricsLogger mMediaProjectionMetricsLogger;
    private final SystemUIDialog.Factory mDialogFactory;

    protected static final String INTENT_UPDATE_STATE =
            "com.android.systemui.screenrecord.UPDATE_STATE";
@@ -120,7 +122,8 @@ public class RecordingController
            UserContextProvider userContextProvider,
            Lazy<ScreenCaptureDevicePolicyResolver> devicePolicyResolver,
            UserTracker userTracker,
            MediaProjectionMetricsLogger mediaProjectionMetricsLogger) {
            MediaProjectionMetricsLogger mediaProjectionMetricsLogger,
            SystemUIDialog.Factory dialogFactory) {
        mMainExecutor = mainExecutor;
        mContext = context;
        mFlags = flags;
@@ -129,6 +132,7 @@ public class RecordingController
        mUserContextProvider = userContextProvider;
        mUserTracker = userTracker;
        mMediaProjectionMetricsLogger = mediaProjectionMetricsLogger;
        mDialogFactory = dialogFactory;

        BroadcastOptions options = BroadcastOptions.makeBasic();
        options.setInteractive(true);
@@ -166,15 +170,14 @@ public class RecordingController
                getHostUid(), SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);

        return flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)
                ? new ScreenRecordPermissionDialog(
                        context,
                ? mDialogFactory.create(new ScreenRecordPermissionDialogDelegate(
                getHostUserHandle(),
                getHostUid(),
                /* controller= */ this,
                activityStarter,
                mUserContextProvider,
                onStartRecordingClicked,
                        mMediaProjectionMetricsLogger)
                mMediaProjectionMetricsLogger))
                : new ScreenRecordDialog(
                        context,
                        /* controller= */ this,
+19 −17
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ package com.android.systemui.screenrecord

import android.app.Activity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Handler
@@ -35,17 +34,17 @@ import androidx.annotation.LayoutRes
import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget
import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity
import com.android.systemui.mediaprojection.permission.BaseScreenSharePermissionDialog
import com.android.systemui.mediaprojection.permission.BaseMediaProjectionPermissionDialogDelegate
import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN
import com.android.systemui.mediaprojection.permission.SINGLE_APP
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 com.android.systemui.statusbar.phone.SystemUIDialog

/** Dialog to select screen recording options */
class ScreenRecordPermissionDialog(
    context: Context,
class ScreenRecordPermissionDialogDelegate(
    private val hostUserHandle: UserHandle,
    private val hostUid: Int,
    private val controller: RecordingController,
@@ -54,8 +53,7 @@ class ScreenRecordPermissionDialog(
    private val onStartRecordingClicked: Runnable?,
    mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
) :
    BaseScreenSharePermissionDialog(
        context,
    BaseMediaProjectionPermissionDialogDelegate<SystemUIDialog>(
        createOptionList(),
        appName = null,
        hostUid = hostUid,
@@ -68,10 +66,10 @@ class ScreenRecordPermissionDialog(
    private lateinit var audioSwitch: Switch
    private lateinit var options: Spinner

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
        super.onCreate(dialog, savedInstanceState)
        setDialogTitle(R.string.screenrecord_permission_dialog_title)
        setTitle(R.string.screenrecord_title)
        dialog.setTitle(R.string.screenrecord_title)
        setStartButtonText(R.string.screenrecord_permission_dialog_continue)
        setStartButtonOnClickListener { v: View? ->
            onStartRecordingClicked?.run()
@@ -79,7 +77,7 @@ class ScreenRecordPermissionDialog(
                requestScreenCapture(/* captureTarget= */ null)
            }
            if (selectedScreenShareOption.mode == SINGLE_APP) {
                val intent = Intent(context, MediaProjectionAppSelectorActivity::class.java)
                val intent = Intent(dialog.context, MediaProjectionAppSelectorActivity::class.java)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

                // We can't start activity for result here so we use result receiver to get
@@ -96,22 +94,26 @@ class ScreenRecordPermissionDialog(
                intent.putExtra(MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_UID, hostUid)
                activityStarter.startActivity(intent, /* dismissShade= */ true)
            }
            dismiss()
            dialog.dismiss()
        }
        setCancelButtonOnClickListener { dismiss() }
        setCancelButtonOnClickListener { dialog.dismiss() }
        initRecordOptionsView()
    }

    @LayoutRes override fun getOptionsViewLayoutId(): Int = R.layout.screen_record_options

    private fun initRecordOptionsView() {
        audioSwitch = requireViewById(R.id.screenrecord_audio_switch)
        tapsSwitch = requireViewById(R.id.screenrecord_taps_switch)
        tapsView = requireViewById(R.id.show_taps)
        audioSwitch = dialog.requireViewById(R.id.screenrecord_audio_switch)
        tapsSwitch = dialog.requireViewById(R.id.screenrecord_taps_switch)
        tapsView = dialog.requireViewById(R.id.show_taps)
        updateTapsViewVisibility()
        options = requireViewById(R.id.screen_recording_options)
        options = dialog.requireViewById(R.id.screen_recording_options)
        val a: ArrayAdapter<*> =
            ScreenRecordingAdapter(context, android.R.layout.simple_spinner_dropdown_item, MODES)
            ScreenRecordingAdapter(
                dialog.context,
                android.R.layout.simple_spinner_dropdown_item,
                MODES
            )
        a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        options.adapter = a
        options.setOnItemClickListenerInt { _: AdapterView<*>?, _: View?, _: Int, _: Long ->
Loading