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

Commit 1a5a6aee authored by Chris Göllner's avatar Chris Göllner
Browse files

Disable partial screen sharing when media projection config is provided

An app can specify a particular display to capture by setting a new
screen capture intent extra.
When this extra is set, we should not show partial screen sharing - and
only allow the app to do display capture.

Fixes: 260248709
Test: atest PlatformScenarioTests:MediaProjectionPermissionTest
Change-Id: Ie91756179431bb84c718c51b7b478631bdd913d9
parent 8ecd6992
Loading
Loading
Loading
Loading
+26 −9
Original line number Diff line number Diff line
@@ -13,15 +13,32 @@
  See the License for the specific language governing permissions and
  limitations under the License.
  -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="@dimen/screenrecord_spinner_height"
    android:paddingEnd="@dimen/screenrecord_spinner_text_padding_end"
    android:paddingStart="@dimen/screenrecord_spinner_text_padding_start"
    android:gravity="center_vertical"
    android:orientation="vertical">

    <TextView
        android:id="@android:id/text1"
    android:textAppearance="?android:attr/textAppearanceMedium"
    android:textColor="?androidprv:attr/textColorOnAccent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="marquee"
        android:singleLine="true"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="?androidprv:attr/textColorOnAccent" />

    <TextView
        android:id="@android:id/text2"
        android:layout_width="match_parent"
    android:layout_height="@dimen/screenrecord_spinner_height"
    android:gravity="center_vertical"
        android:layout_height="wrap_content"
        android:ellipsize="marquee"
    android:paddingStart="@dimen/screenrecord_spinner_text_padding_start"
    android:paddingEnd="@dimen/screenrecord_spinner_text_padding_end"/>
 No newline at end of file
        android:singleLine="true"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="?androidprv:attr/colorError" />

</LinearLayout>
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
@@ -1102,6 +1102,8 @@
    <string name="media_projection_entry_app_permission_dialog_warning_single_app">When you’re sharing, recording, or casting an app, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
    <!-- 1P/3P apps media projection permission button to continue with app selection or recording [CHAR LIMIT=60] -->
    <string name="media_projection_entry_app_permission_dialog_continue">Start</string>
    <!-- 1P/3P apps disabled the single app projection option. [CHAR LIMIT=NONE] -->
    <string name="media_projection_entry_app_permission_dialog_single_app_disabled"><xliff:g id="app_name" example="Meet">%1$s</xliff:g> has disabled this option</string>

    <!-- Casting that launched by SysUI (i.e. when there is no app name) -->
    <!-- System casting media projection permission dialog title. [CHAR LIMIT=100] -->
+18 −5
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
import android.media.projection.IMediaProjection;
import android.media.projection.MediaProjectionConfig;
import android.media.projection.MediaProjectionManager;
import android.media.projection.ReviewGrantedConsentResult;
import android.os.Bundle;
@@ -208,9 +209,11 @@ public class MediaProjectionPermissionActivity extends Activity
        // the correct screen width when in split screen.
        Context dialogContext = getApplicationContext();
        if (isPartialScreenSharingEnabled()) {
            mDialog = new MediaProjectionPermissionDialog(dialogContext, () -> {
                ScreenShareOption selectedOption =
                        ((MediaProjectionPermissionDialog) mDialog).getSelectedScreenShareOption();
            mDialog = new MediaProjectionPermissionDialog(dialogContext, getMediaProjectionConfig(),
                    () -> {
                        MediaProjectionPermissionDialog dialog =
                                (MediaProjectionPermissionDialog) mDialog;
                        ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption();
                        grantMediaProjectionPermission(selectedOption.getMode());
                    }, () -> finish(RECORD_CANCEL, /* projection= */ null), appName);
        } else {
@@ -348,6 +351,16 @@ public class MediaProjectionPermissionActivity extends Activity
        }
    }

    @Nullable
    private MediaProjectionConfig getMediaProjectionConfig() {
        Intent intent = getIntent();
        if (intent == null) {
            return null;
        }
        return intent.getParcelableExtra(
                MediaProjectionManager.EXTRA_MEDIA_PROJECTION_CONFIG);
    }

    private boolean isPartialScreenSharingEnabled() {
        return mFeatureFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING);
    }
+36 −9
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ package com.android.systemui.screenrecord
import android.content.Context
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewStub
import android.view.WindowManager
import android.widget.AdapterView
@@ -35,7 +37,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialog

/** Base permission dialog for screen share and recording */
open class BaseScreenSharePermissionDialog(
    context: Context?,
    context: Context,
    private val screenShareOptions: List<ScreenShareOption>,
    private val appName: String?,
    @DrawableRes private val dialogIconDrawable: Int? = null,
@@ -82,14 +84,7 @@ open class BaseScreenSharePermissionDialog(
        get() = context.getString(selectedScreenShareOption.warningText, appName)

    private fun initScreenShareSpinner() {
        val options = screenShareOptions.map { context.getString(it.spinnerText) }.toTypedArray()
        val adapter =
            ArrayAdapter(
                context.applicationContext,
                R.layout.screen_share_dialog_spinner_text,
                options
            )
        adapter.setDropDownViewResource(R.layout.screen_share_dialog_spinner_item_text)
        val adapter = OptionsAdapter(context.applicationContext, screenShareOptions)
        screenShareModeSpinner = requireViewById(R.id.screen_share_mode_spinner)
        screenShareModeSpinner.adapter = adapter
        screenShareModeSpinner.onItemSelectedListener = this
@@ -131,3 +126,35 @@ open class BaseScreenSharePermissionDialog(
        stub.inflate()
    }
}

private class OptionsAdapter(
    context: Context,
    private val options: List<ScreenShareOption>,
) :
    ArrayAdapter<String>(
        context,
        R.layout.screen_share_dialog_spinner_text,
        options.map { context.getString(it.spinnerText) }
    ) {

    override fun isEnabled(position: Int): Boolean {
        return options[position].spinnerDisabledText == null
    }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
        val inflater = LayoutInflater.from(parent.context)
        val view = inflater.inflate(R.layout.screen_share_dialog_spinner_item_text, parent, false)
        val titleTextView = view.findViewById<TextView>(android.R.id.text1)
        val errorTextView = view.findViewById<TextView>(android.R.id.text2)
        titleTextView.text = getItem(position)
        errorTextView.text = options[position].spinnerDisabledText
        if (isEnabled(position)) {
            errorTextView.visibility = View.GONE
            titleTextView.isEnabled = true
        } else {
            errorTextView.visibility = View.VISIBLE
            titleTextView.isEnabled = false
        }
        return view
    }
}
+29 −4
Original line number Diff line number Diff line
@@ -16,16 +16,23 @@
package com.android.systemui.screenrecord

import android.content.Context
import android.media.projection.MediaProjectionConfig
import android.os.Bundle
import com.android.systemui.R

/** Dialog to select screen recording options */
class MediaProjectionPermissionDialog(
    context: Context?,
    context: Context,
    mediaProjectionConfig: MediaProjectionConfig?,
    private val onStartRecordingClicked: Runnable,
    private val onCancelClicked: Runnable,
    private val appName: String?
) : BaseScreenSharePermissionDialog(context, createOptionList(appName), appName) {
) :
    BaseScreenSharePermissionDialog(
        context,
        createOptionList(context, appName, mediaProjectionConfig),
        appName
    ) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // TODO(b/270018943): Handle the case of System sharing (not recording nor casting)
@@ -49,7 +56,11 @@ class MediaProjectionPermissionDialog(
    }

    companion object {
        private fun createOptionList(appName: String?): List<ScreenShareOption> {
        private fun createOptionList(
            context: Context,
            appName: String?,
            mediaProjectionConfig: MediaProjectionConfig?
        ): List<ScreenShareOption> {
            val singleAppWarningText =
                if (appName == null) {
                    R.string.media_projection_entry_cast_permission_dialog_warning_single_app
@@ -63,6 +74,19 @@ class MediaProjectionPermissionDialog(
                    R.string.media_projection_entry_app_permission_dialog_warning_entire_screen
                }

            val singleAppDisabledText =
                if (
                    appName != null &&
                        mediaProjectionConfig?.regionToCapture ==
                            MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY
                ) {
                    context.getString(
                        R.string.media_projection_entry_app_permission_dialog_single_app_disabled,
                        appName
                    )
                } else {
                    null
                }
            return listOf(
                ScreenShareOption(
                    mode = ENTIRE_SCREEN,
@@ -72,7 +96,8 @@ class MediaProjectionPermissionDialog(
                ScreenShareOption(
                    mode = SINGLE_APP,
                    spinnerText = R.string.screen_share_permission_dialog_option_single_app,
                    warningText = singleAppWarningText
                    warningText = singleAppWarningText,
                    spinnerDisabledText = singleAppDisabledText,
                )
            )
        }
Loading