1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.systemui.mediaprojection.permission
17 
18 import android.app.AlertDialog
19 import android.content.Context
20 import android.media.projection.MediaProjectionConfig
21 import android.os.Bundle
22 import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
23 import com.android.systemui.res.R
24 import java.util.function.Consumer
25 
26 /** Dialog to select screen recording options */
27 class MediaProjectionPermissionDialogDelegate(
28     context: Context,
29     mediaProjectionConfig: MediaProjectionConfig?,
30     private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>,
31     private val onCancelClicked: Runnable,
32     private val appName: String?,
33     private val forceShowPartialScreenshare: Boolean,
34     hostUid: Int,
35     mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
36 ) :
37     BaseMediaProjectionPermissionDialogDelegate<AlertDialog>(
38         createOptionList(context, appName, mediaProjectionConfig, forceShowPartialScreenshare),
39         appName,
40         hostUid,
41         mediaProjectionMetricsLogger
42     ) {
onCreatenull43     override fun onCreate(dialog: AlertDialog, savedInstanceState: Bundle?) {
44         super.onCreate(dialog, savedInstanceState)
45         // TODO(b/270018943): Handle the case of System sharing (not recording nor casting)
46         if (appName == null) {
47             setDialogTitle(R.string.media_projection_entry_cast_permission_dialog_title)
48             setStartButtonText(R.string.media_projection_entry_cast_permission_dialog_continue)
49         } else {
50             setDialogTitle(R.string.media_projection_entry_app_permission_dialog_title)
51             setStartButtonText(R.string.media_projection_entry_app_permission_dialog_continue)
52         }
53         setStartButtonOnClickListener {
54             // Note that it is important to run this callback before dismissing, so that the
55             // callback can disable the dialog exit animation if it wants to.
56             onStartRecordingClicked.accept(this)
57             dialog.dismiss()
58         }
59         setCancelButtonOnClickListener {
60             onCancelClicked.run()
61             dialog.dismiss()
62         }
63     }
64 
65     companion object {
createOptionListnull66         private fun createOptionList(
67             context: Context,
68             appName: String?,
69             mediaProjectionConfig: MediaProjectionConfig?,
70             overrideDisableSingleAppOption: Boolean = false,
71         ): List<ScreenShareOption> {
72             val singleAppWarningText =
73                 if (appName == null) {
74                     R.string.media_projection_entry_cast_permission_dialog_warning_single_app
75                 } else {
76                     R.string.media_projection_entry_app_permission_dialog_warning_single_app
77                 }
78             val entireScreenWarningText =
79                 if (appName == null) {
80                     R.string.media_projection_entry_cast_permission_dialog_warning_entire_screen
81                 } else {
82                     R.string.media_projection_entry_app_permission_dialog_warning_entire_screen
83                 }
84 
85             // The single app option should only be disabled if there is an app name provided,
86             // the client has setup a MediaProjection with
87             // MediaProjectionConfig#createConfigForDefaultDisplay, AND it hasn't been overridden by
88             // the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override.
89             val singleAppOptionDisabled =
90                 appName != null &&
91                     !overrideDisableSingleAppOption &&
92                     mediaProjectionConfig?.regionToCapture ==
93                         MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY
94 
95             val singleAppDisabledText =
96                 if (singleAppOptionDisabled) {
97                     context.getString(
98                         R.string.media_projection_entry_app_permission_dialog_single_app_disabled,
99                         appName
100                     )
101                 } else {
102                     null
103                 }
104             val options =
105                 listOf(
106                     ScreenShareOption(
107                         mode = SINGLE_APP,
108                         spinnerText = R.string.screen_share_permission_dialog_option_single_app,
109                         warningText = singleAppWarningText,
110                         spinnerDisabledText = singleAppDisabledText,
111                     ),
112                     ScreenShareOption(
113                         mode = ENTIRE_SCREEN,
114                         spinnerText = R.string.screen_share_permission_dialog_option_entire_screen,
115                         warningText = entireScreenWarningText
116                     )
117                 )
118             return if (singleAppOptionDisabled) {
119                 // Make sure "Entire screen" is the first option when "Single App" is disabled.
120                 options.reversed()
121             } else {
122                 options
123             }
124         }
125     }
126 }
127