Loading packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionUtils.kt 0 → 100644 +39 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.mediaprojection import android.content.pm.PackageManager import com.android.systemui.util.Utils /** Various utility methods related to media projection. */ object MediaProjectionUtils { /** * Returns true iff projecting to the given [packageName] means that we're casting media to a * *different* device (as opposed to sharing media to some application on *this* device). */ fun packageHasCastingCapabilities( packageManager: PackageManager, packageName: String ): Boolean { // The [isHeadlessRemoteDisplayProvider] check approximates whether a projection is to a // different device or the same device, because headless remote display packages are the // only kinds of packages that do cast-to-other-device. This isn't exactly perfect, // because it means that any projection by those headless remote display packages will be // marked as going to a different device, even if that isn't always true. See b/321078669. return Utils.isHeadlessRemoteDisplayProvider(packageManager, packageName) } } packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java +46 −25 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import android.content.DialogInterface; import android.content.Intent; 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; Loading @@ -50,10 +49,8 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.text.BidiFormatter; import android.text.SpannableString; import android.text.TextPaint; import android.text.TextUtils; import android.text.style.StyleSpan; import android.util.Log; import android.view.Window; Loading @@ -61,6 +58,7 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger; import com.android.systemui.mediaprojection.MediaProjectionServiceHelper; import com.android.systemui.mediaprojection.MediaProjectionUtils; import com.android.systemui.mediaprojection.SessionCreationSource; import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity; import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver; Loading @@ -68,12 +66,13 @@ import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDi 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; import dagger.Lazy; import java.util.function.Consumer; import javax.inject.Inject; import dagger.Lazy; public class MediaProjectionPermissionActivity extends Activity implements DialogInterface.OnClickListener { private static final String TAG = "MediaProjectionPermissionActivity"; Loading Loading @@ -189,30 +188,14 @@ public class MediaProjectionPermissionActivity extends Activity final String appName = extractAppName(aInfo, packageManager); final boolean hasCastingCapabilities = Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName); MediaProjectionUtils.INSTANCE.packageHasCastingCapabilities( packageManager, mPackageName); // Using application context for the dialog, instead of the activity context, so we get // the correct screen width when in split screen. Context dialogContext = getApplicationContext(); final boolean overrideDisableSingleAppOption = CompatChanges.isChangeEnabled( OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION, mPackageName, getHostUserHandle()); MediaProjectionPermissionDialogDelegate delegate = new MediaProjectionPermissionDialogDelegate( dialogContext, getMediaProjectionConfig(), dialog -> { ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption(); grantMediaProjectionPermission(selectedOption.getMode()); }, () -> finish(RECORD_CANCEL, /* projection= */ null), hasCastingCapabilities, appName, overrideDisableSingleAppOption, mUid, mMediaProjectionMetricsLogger); BaseMediaProjectionPermissionDialogDelegate<AlertDialog> delegate = createPermissionDialogDelegate(appName, hasCastingCapabilities, dialogContext); mDialog = new AlertDialogWithDelegate( dialogContext, R.style.Theme_SystemUI_Dialog, delegate); Loading Loading @@ -274,6 +257,44 @@ public class MediaProjectionPermissionActivity extends Activity return appName; } private BaseMediaProjectionPermissionDialogDelegate<AlertDialog> createPermissionDialogDelegate( String appName, boolean hasCastingCapabilities, Context dialogContext) { final boolean overrideDisableSingleAppOption = CompatChanges.isChangeEnabled( OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION, mPackageName, getHostUserHandle()); MediaProjectionConfig mediaProjectionConfig = getMediaProjectionConfig(); Consumer<BaseMediaProjectionPermissionDialogDelegate<AlertDialog>> onStartRecordingClicked = dialog -> { ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption(); grantMediaProjectionPermission(selectedOption.getMode()); }; Runnable onCancelClicked = () -> finish(RECORD_CANCEL, /* projection= */ null); if (hasCastingCapabilities) { return new SystemCastPermissionDialogDelegate( dialogContext, mediaProjectionConfig, onStartRecordingClicked, onCancelClicked, appName, overrideDisableSingleAppOption, mUid, mMediaProjectionMetricsLogger); } else { return new ShareToAppPermissionDialogDelegate( dialogContext, mediaProjectionConfig, onStartRecordingClicked, onCancelClicked, appName, overrideDisableSingleAppOption, mUid, mMediaProjectionMetricsLogger); } } @Override protected void onDestroy() { super.onDestroy(); Loading packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionUtils.kt 0 → 100644 +47 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.mediaprojection.permission import android.content.Context import android.media.projection.MediaProjectionConfig import com.android.systemui.res.R /** Various utility methods related to media projection permissions. */ object MediaProjectionPermissionUtils { fun getSingleAppDisabledText( context: Context, appName: String, mediaProjectionConfig: MediaProjectionConfig?, overrideDisableSingleAppOption: Boolean, ): String? { // The single app option should only be disabled if the client has setup a // MediaProjection with MediaProjectionConfig#createConfigForDefaultDisplay AND // it hasn't been overridden by the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override. val singleAppOptionDisabled = !overrideDisableSingleAppOption && mediaProjectionConfig?.regionToCapture == MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY return if (singleAppOptionDisabled) { context.getString( R.string.media_projection_entry_app_permission_dialog_single_app_disabled, appName, ) } else { null } } } packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt→packages/SystemUI/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegate.kt +25 −48 Original line number Diff line number Diff line Loading @@ -23,13 +23,16 @@ import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger import com.android.systemui.res.R import java.util.function.Consumer /** Dialog to select screen recording options */ class MediaProjectionPermissionDialogDelegate( /** * Dialog to select screen recording options for sharing the screen to another app on the same * device. */ class ShareToAppPermissionDialogDelegate( context: Context, mediaProjectionConfig: MediaProjectionConfig?, private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>, private val onStartRecordingClicked: Consumer<BaseMediaProjectionPermissionDialogDelegate<AlertDialog>>, private val onCancelClicked: Runnable, private val hasCastingCapabilities: Boolean, appName: String, forceShowPartialScreenshare: Boolean, hostUid: Int, Loading @@ -39,24 +42,18 @@ class MediaProjectionPermissionDialogDelegate( createOptionList( context, appName, hasCastingCapabilities, mediaProjectionConfig, forceShowPartialScreenshare overrideDisableSingleAppOption = forceShowPartialScreenshare, ), appName, hostUid, mediaProjectionMetricsLogger mediaProjectionMetricsLogger, ) { 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 (hasCastingCapabilities) { setDialogTitle(R.string.media_projection_entry_cast_permission_dialog_title) setStartButtonText(R.string.media_projection_entry_cast_permission_dialog_continue) } else { setDialogTitle(R.string.media_projection_entry_app_permission_dialog_title) setStartButtonText(R.string.media_projection_entry_app_permission_dialog_continue) } 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. Loading @@ -73,55 +70,35 @@ class MediaProjectionPermissionDialogDelegate( private fun createOptionList( context: Context, appName: String, hasCastingCapabilities: Boolean, mediaProjectionConfig: MediaProjectionConfig?, overrideDisableSingleAppOption: Boolean = false, overrideDisableSingleAppOption: Boolean, ): List<ScreenShareOption> { val singleAppWarningText = if (hasCastingCapabilities) { R.string.media_projection_entry_cast_permission_dialog_warning_single_app } else { R.string.media_projection_entry_app_permission_dialog_warning_single_app } val entireScreenWarningText = if (hasCastingCapabilities) { R.string.media_projection_entry_cast_permission_dialog_warning_entire_screen } else { R.string.media_projection_entry_app_permission_dialog_warning_entire_screen } // The single app option should only be disabled if the client has setup a // MediaProjection with MediaProjectionConfig#createConfigForDefaultDisplay AND // it hasn't been overridden by the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override. val singleAppOptionDisabled = !overrideDisableSingleAppOption && mediaProjectionConfig?.regionToCapture == MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY val singleAppDisabledText = if (singleAppOptionDisabled) { context.getString( R.string.media_projection_entry_app_permission_dialog_single_app_disabled, appName MediaProjectionPermissionUtils.getSingleAppDisabledText( context, appName, mediaProjectionConfig, overrideDisableSingleAppOption, ) } else { null } val options = listOf( ScreenShareOption( mode = SINGLE_APP, spinnerText = R.string.screen_share_permission_dialog_option_single_app, warningText = singleAppWarningText, warningText = R.string .media_projection_entry_app_permission_dialog_warning_single_app, spinnerDisabledText = singleAppDisabledText, ), ScreenShareOption( mode = ENTIRE_SCREEN, spinnerText = R.string.screen_share_permission_dialog_option_entire_screen, warningText = entireScreenWarningText warningText = R.string .media_projection_entry_app_permission_dialog_warning_entire_screen, ) ) return if (singleAppOptionDisabled) { return if (singleAppDisabledText != null) { // Make sure "Entire screen" is the first option when "Single App" is disabled. options.reversed() } else { Loading packages/SystemUI/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegate.kt 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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.mediaprojection.permission.MediaProjectionPermissionUtils.getSingleAppDisabledText import com.android.systemui.res.R import java.util.function.Consumer /** Dialog to select screen recording options for casting the screen to a different device. */ class SystemCastPermissionDialogDelegate( context: Context, mediaProjectionConfig: MediaProjectionConfig?, private val onStartRecordingClicked: Consumer<BaseMediaProjectionPermissionDialogDelegate<AlertDialog>>, private val onCancelClicked: Runnable, appName: String, forceShowPartialScreenshare: Boolean, hostUid: Int, mediaProjectionMetricsLogger: MediaProjectionMetricsLogger, ) : BaseMediaProjectionPermissionDialogDelegate<AlertDialog>( createOptionList( context, appName, mediaProjectionConfig, overrideDisableSingleAppOption = forceShowPartialScreenshare, ), appName, hostUid, mediaProjectionMetricsLogger, ) { override fun onCreate(dialog: AlertDialog, savedInstanceState: Bundle?) { super.onCreate(dialog, savedInstanceState) // TODO(b/270018943): Handle the case of System sharing (not recording nor casting) setDialogTitle(R.string.media_projection_entry_cast_permission_dialog_title) setStartButtonText(R.string.media_projection_entry_cast_permission_dialog_continue) 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.accept(this) dialog.dismiss() } setCancelButtonOnClickListener { onCancelClicked.run() dialog.dismiss() } } companion object { private fun createOptionList( context: Context, appName: String, mediaProjectionConfig: MediaProjectionConfig?, overrideDisableSingleAppOption: Boolean, ): List<ScreenShareOption> { val singleAppDisabledText = getSingleAppDisabledText( context, appName, mediaProjectionConfig, overrideDisableSingleAppOption ) val options = listOf( ScreenShareOption( mode = SINGLE_APP, spinnerText = R.string.screen_share_permission_dialog_option_single_app, warningText = R.string .media_projection_entry_cast_permission_dialog_warning_single_app, spinnerDisabledText = singleAppDisabledText, ), ScreenShareOption( mode = ENTIRE_SCREEN, spinnerText = R.string.screen_share_permission_dialog_option_entire_screen, warningText = R.string .media_projection_entry_cast_permission_dialog_warning_entire_screen, ) ) return if (singleAppDisabledText != null) { // Make sure "Entire screen" is the first option when "Single App" is disabled. options.reversed() } else { options } } } } Loading
packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionUtils.kt 0 → 100644 +39 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.mediaprojection import android.content.pm.PackageManager import com.android.systemui.util.Utils /** Various utility methods related to media projection. */ object MediaProjectionUtils { /** * Returns true iff projecting to the given [packageName] means that we're casting media to a * *different* device (as opposed to sharing media to some application on *this* device). */ fun packageHasCastingCapabilities( packageManager: PackageManager, packageName: String ): Boolean { // The [isHeadlessRemoteDisplayProvider] check approximates whether a projection is to a // different device or the same device, because headless remote display packages are the // only kinds of packages that do cast-to-other-device. This isn't exactly perfect, // because it means that any projection by those headless remote display packages will be // marked as going to a different device, even if that isn't always true. See b/321078669. return Utils.isHeadlessRemoteDisplayProvider(packageManager, packageName) } }
packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java +46 −25 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import android.content.DialogInterface; import android.content.Intent; 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; Loading @@ -50,10 +49,8 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.text.BidiFormatter; import android.text.SpannableString; import android.text.TextPaint; import android.text.TextUtils; import android.text.style.StyleSpan; import android.util.Log; import android.view.Window; Loading @@ -61,6 +58,7 @@ import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger; import com.android.systemui.mediaprojection.MediaProjectionServiceHelper; import com.android.systemui.mediaprojection.MediaProjectionUtils; import com.android.systemui.mediaprojection.SessionCreationSource; import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity; import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver; Loading @@ -68,12 +66,13 @@ import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDi 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; import dagger.Lazy; import java.util.function.Consumer; import javax.inject.Inject; import dagger.Lazy; public class MediaProjectionPermissionActivity extends Activity implements DialogInterface.OnClickListener { private static final String TAG = "MediaProjectionPermissionActivity"; Loading Loading @@ -189,30 +188,14 @@ public class MediaProjectionPermissionActivity extends Activity final String appName = extractAppName(aInfo, packageManager); final boolean hasCastingCapabilities = Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName); MediaProjectionUtils.INSTANCE.packageHasCastingCapabilities( packageManager, mPackageName); // Using application context for the dialog, instead of the activity context, so we get // the correct screen width when in split screen. Context dialogContext = getApplicationContext(); final boolean overrideDisableSingleAppOption = CompatChanges.isChangeEnabled( OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION, mPackageName, getHostUserHandle()); MediaProjectionPermissionDialogDelegate delegate = new MediaProjectionPermissionDialogDelegate( dialogContext, getMediaProjectionConfig(), dialog -> { ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption(); grantMediaProjectionPermission(selectedOption.getMode()); }, () -> finish(RECORD_CANCEL, /* projection= */ null), hasCastingCapabilities, appName, overrideDisableSingleAppOption, mUid, mMediaProjectionMetricsLogger); BaseMediaProjectionPermissionDialogDelegate<AlertDialog> delegate = createPermissionDialogDelegate(appName, hasCastingCapabilities, dialogContext); mDialog = new AlertDialogWithDelegate( dialogContext, R.style.Theme_SystemUI_Dialog, delegate); Loading Loading @@ -274,6 +257,44 @@ public class MediaProjectionPermissionActivity extends Activity return appName; } private BaseMediaProjectionPermissionDialogDelegate<AlertDialog> createPermissionDialogDelegate( String appName, boolean hasCastingCapabilities, Context dialogContext) { final boolean overrideDisableSingleAppOption = CompatChanges.isChangeEnabled( OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION, mPackageName, getHostUserHandle()); MediaProjectionConfig mediaProjectionConfig = getMediaProjectionConfig(); Consumer<BaseMediaProjectionPermissionDialogDelegate<AlertDialog>> onStartRecordingClicked = dialog -> { ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption(); grantMediaProjectionPermission(selectedOption.getMode()); }; Runnable onCancelClicked = () -> finish(RECORD_CANCEL, /* projection= */ null); if (hasCastingCapabilities) { return new SystemCastPermissionDialogDelegate( dialogContext, mediaProjectionConfig, onStartRecordingClicked, onCancelClicked, appName, overrideDisableSingleAppOption, mUid, mMediaProjectionMetricsLogger); } else { return new ShareToAppPermissionDialogDelegate( dialogContext, mediaProjectionConfig, onStartRecordingClicked, onCancelClicked, appName, overrideDisableSingleAppOption, mUid, mMediaProjectionMetricsLogger); } } @Override protected void onDestroy() { super.onDestroy(); Loading
packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionUtils.kt 0 → 100644 +47 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.mediaprojection.permission import android.content.Context import android.media.projection.MediaProjectionConfig import com.android.systemui.res.R /** Various utility methods related to media projection permissions. */ object MediaProjectionPermissionUtils { fun getSingleAppDisabledText( context: Context, appName: String, mediaProjectionConfig: MediaProjectionConfig?, overrideDisableSingleAppOption: Boolean, ): String? { // The single app option should only be disabled if the client has setup a // MediaProjection with MediaProjectionConfig#createConfigForDefaultDisplay AND // it hasn't been overridden by the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override. val singleAppOptionDisabled = !overrideDisableSingleAppOption && mediaProjectionConfig?.regionToCapture == MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY return if (singleAppOptionDisabled) { context.getString( R.string.media_projection_entry_app_permission_dialog_single_app_disabled, appName, ) } else { null } } }
packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt→packages/SystemUI/src/com/android/systemui/mediaprojection/permission/ShareToAppPermissionDialogDelegate.kt +25 −48 Original line number Diff line number Diff line Loading @@ -23,13 +23,16 @@ import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger import com.android.systemui.res.R import java.util.function.Consumer /** Dialog to select screen recording options */ class MediaProjectionPermissionDialogDelegate( /** * Dialog to select screen recording options for sharing the screen to another app on the same * device. */ class ShareToAppPermissionDialogDelegate( context: Context, mediaProjectionConfig: MediaProjectionConfig?, private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>, private val onStartRecordingClicked: Consumer<BaseMediaProjectionPermissionDialogDelegate<AlertDialog>>, private val onCancelClicked: Runnable, private val hasCastingCapabilities: Boolean, appName: String, forceShowPartialScreenshare: Boolean, hostUid: Int, Loading @@ -39,24 +42,18 @@ class MediaProjectionPermissionDialogDelegate( createOptionList( context, appName, hasCastingCapabilities, mediaProjectionConfig, forceShowPartialScreenshare overrideDisableSingleAppOption = forceShowPartialScreenshare, ), appName, hostUid, mediaProjectionMetricsLogger mediaProjectionMetricsLogger, ) { 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 (hasCastingCapabilities) { setDialogTitle(R.string.media_projection_entry_cast_permission_dialog_title) setStartButtonText(R.string.media_projection_entry_cast_permission_dialog_continue) } else { setDialogTitle(R.string.media_projection_entry_app_permission_dialog_title) setStartButtonText(R.string.media_projection_entry_app_permission_dialog_continue) } 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. Loading @@ -73,55 +70,35 @@ class MediaProjectionPermissionDialogDelegate( private fun createOptionList( context: Context, appName: String, hasCastingCapabilities: Boolean, mediaProjectionConfig: MediaProjectionConfig?, overrideDisableSingleAppOption: Boolean = false, overrideDisableSingleAppOption: Boolean, ): List<ScreenShareOption> { val singleAppWarningText = if (hasCastingCapabilities) { R.string.media_projection_entry_cast_permission_dialog_warning_single_app } else { R.string.media_projection_entry_app_permission_dialog_warning_single_app } val entireScreenWarningText = if (hasCastingCapabilities) { R.string.media_projection_entry_cast_permission_dialog_warning_entire_screen } else { R.string.media_projection_entry_app_permission_dialog_warning_entire_screen } // The single app option should only be disabled if the client has setup a // MediaProjection with MediaProjectionConfig#createConfigForDefaultDisplay AND // it hasn't been overridden by the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override. val singleAppOptionDisabled = !overrideDisableSingleAppOption && mediaProjectionConfig?.regionToCapture == MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY val singleAppDisabledText = if (singleAppOptionDisabled) { context.getString( R.string.media_projection_entry_app_permission_dialog_single_app_disabled, appName MediaProjectionPermissionUtils.getSingleAppDisabledText( context, appName, mediaProjectionConfig, overrideDisableSingleAppOption, ) } else { null } val options = listOf( ScreenShareOption( mode = SINGLE_APP, spinnerText = R.string.screen_share_permission_dialog_option_single_app, warningText = singleAppWarningText, warningText = R.string .media_projection_entry_app_permission_dialog_warning_single_app, spinnerDisabledText = singleAppDisabledText, ), ScreenShareOption( mode = ENTIRE_SCREEN, spinnerText = R.string.screen_share_permission_dialog_option_entire_screen, warningText = entireScreenWarningText warningText = R.string .media_projection_entry_app_permission_dialog_warning_entire_screen, ) ) return if (singleAppOptionDisabled) { return if (singleAppDisabledText != null) { // Make sure "Entire screen" is the first option when "Single App" is disabled. options.reversed() } else { Loading
packages/SystemUI/src/com/android/systemui/mediaprojection/permission/SystemCastPermissionDialogDelegate.kt 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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.mediaprojection.permission.MediaProjectionPermissionUtils.getSingleAppDisabledText import com.android.systemui.res.R import java.util.function.Consumer /** Dialog to select screen recording options for casting the screen to a different device. */ class SystemCastPermissionDialogDelegate( context: Context, mediaProjectionConfig: MediaProjectionConfig?, private val onStartRecordingClicked: Consumer<BaseMediaProjectionPermissionDialogDelegate<AlertDialog>>, private val onCancelClicked: Runnable, appName: String, forceShowPartialScreenshare: Boolean, hostUid: Int, mediaProjectionMetricsLogger: MediaProjectionMetricsLogger, ) : BaseMediaProjectionPermissionDialogDelegate<AlertDialog>( createOptionList( context, appName, mediaProjectionConfig, overrideDisableSingleAppOption = forceShowPartialScreenshare, ), appName, hostUid, mediaProjectionMetricsLogger, ) { override fun onCreate(dialog: AlertDialog, savedInstanceState: Bundle?) { super.onCreate(dialog, savedInstanceState) // TODO(b/270018943): Handle the case of System sharing (not recording nor casting) setDialogTitle(R.string.media_projection_entry_cast_permission_dialog_title) setStartButtonText(R.string.media_projection_entry_cast_permission_dialog_continue) 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.accept(this) dialog.dismiss() } setCancelButtonOnClickListener { onCancelClicked.run() dialog.dismiss() } } companion object { private fun createOptionList( context: Context, appName: String, mediaProjectionConfig: MediaProjectionConfig?, overrideDisableSingleAppOption: Boolean, ): List<ScreenShareOption> { val singleAppDisabledText = getSingleAppDisabledText( context, appName, mediaProjectionConfig, overrideDisableSingleAppOption ) val options = listOf( ScreenShareOption( mode = SINGLE_APP, spinnerText = R.string.screen_share_permission_dialog_option_single_app, warningText = R.string .media_projection_entry_cast_permission_dialog_warning_single_app, spinnerDisabledText = singleAppDisabledText, ), ScreenShareOption( mode = ENTIRE_SCREEN, spinnerText = R.string.screen_share_permission_dialog_option_entire_screen, warningText = R.string .media_projection_entry_cast_permission_dialog_warning_entire_screen, ) ) return if (singleAppDisabledText != null) { // Make sure "Entire screen" is the first option when "Single App" is disabled. options.reversed() } else { options } } } }