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.screenrecord
17 
18 import android.content.Context
19 import android.os.Bundle
20 import android.view.Gravity
21 import android.view.LayoutInflater
22 import android.view.View
23 import android.view.ViewGroup
24 import android.view.ViewStub
25 import android.view.WindowManager
26 import android.widget.AdapterView
27 import android.widget.ArrayAdapter
28 import android.widget.ImageView
29 import android.widget.Spinner
30 import android.widget.TextView
31 import androidx.annotation.ColorRes
32 import androidx.annotation.DrawableRes
33 import androidx.annotation.LayoutRes
34 import androidx.annotation.StringRes
35 import com.android.systemui.R
36 import com.android.systemui.statusbar.phone.SystemUIDialog
37 
38 /** Base permission dialog for screen share and recording */
39 open class BaseScreenSharePermissionDialog(
40     context: Context,
41     private val screenShareOptions: List<ScreenShareOption>,
42     private val appName: String?,
43     @DrawableRes private val dialogIconDrawable: Int? = null,
44     @ColorRes private val dialogIconTint: Int? = null
45 ) : SystemUIDialog(context), AdapterView.OnItemSelectedListener {
46     private lateinit var dialogTitle: TextView
47     private lateinit var startButton: TextView
48     private lateinit var cancelButton: TextView
49     private lateinit var warning: TextView
50     private lateinit var screenShareModeSpinner: Spinner
51     var selectedScreenShareOption: ScreenShareOption = screenShareOptions.first()
52 
53     public override fun onCreate(savedInstanceState: Bundle?) {
54         super.onCreate(savedInstanceState)
55         window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
56         window?.setGravity(Gravity.CENTER)
57         setContentView(R.layout.screen_share_dialog)
58         dialogTitle = requireViewById(R.id.screen_share_dialog_title)
59         warning = requireViewById(R.id.text_warning)
60         startButton = requireViewById(android.R.id.button1)
61         cancelButton = requireViewById(android.R.id.button2)
62         updateIcon()
63         initScreenShareOptions()
64         createOptionsView(getOptionsViewLayoutId())
65     }
66 
67     private fun updateIcon() {
68         val icon = requireViewById<ImageView>(R.id.screen_share_dialog_icon)
69         if (dialogIconTint != null) {
70             icon.setColorFilter(context.getColor(dialogIconTint))
71         }
72         if (dialogIconDrawable != null) {
73             icon.setImageDrawable(context.getDrawable(dialogIconDrawable))
74         }
75     }
76 
77     protected fun initScreenShareOptions() {
78         selectedScreenShareOption = screenShareOptions.first()
79         warning.text = warningText
80         initScreenShareSpinner()
81     }
82 
83     private val warningText: String
84         get() = context.getString(selectedScreenShareOption.warningText, appName)
85 
86     private fun initScreenShareSpinner() {
87         val adapter = OptionsAdapter(context.applicationContext, screenShareOptions)
88         screenShareModeSpinner = requireViewById(R.id.screen_share_mode_spinner)
89         screenShareModeSpinner.adapter = adapter
90         screenShareModeSpinner.onItemSelectedListener = this
91     }
92 
93     override fun onItemSelected(adapterView: AdapterView<*>?, view: View, pos: Int, id: Long) {
94         selectedScreenShareOption = screenShareOptions[pos]
95         warning.text = warningText
96     }
97 
98     override fun onNothingSelected(parent: AdapterView<*>?) {}
99 
100     /** Protected methods for the text updates & functionality */
101     protected fun setDialogTitle(@StringRes stringId: Int) {
102         val title = context.getString(stringId, appName)
103         dialogTitle.text = title
104     }
105 
106     protected fun setStartButtonText(@StringRes stringId: Int) {
107         startButton.setText(stringId)
108     }
109 
110     protected fun setStartButtonOnClickListener(listener: View.OnClickListener?) {
111         startButton.setOnClickListener(listener)
112     }
113 
114     protected fun setCancelButtonOnClickListener(listener: View.OnClickListener?) {
115         cancelButton.setOnClickListener(listener)
116     }
117 
118     // Create additional options that is shown under the share mode spinner
119     // Eg. the audio and tap toggles in SysUI Recorder
120     @LayoutRes protected open fun getOptionsViewLayoutId(): Int? = null
121 
122     private fun createOptionsView(@LayoutRes layoutId: Int?) {
123         if (layoutId == null) return
124         val stub = findViewById<View>(R.id.options_stub) as ViewStub
125         stub.layoutResource = layoutId
126         stub.inflate()
127     }
128 }
129 
130 private class OptionsAdapter(
131     context: Context,
132     private val options: List<ScreenShareOption>,
133 ) :
134     ArrayAdapter<String>(
135         context,
136         R.layout.screen_share_dialog_spinner_text,
137         options.map { context.getString(it.spinnerText) }
138     ) {
139 
140     override fun isEnabled(position: Int): Boolean {
141         return options[position].spinnerDisabledText == null
142     }
143 
144     override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
145         val inflater = LayoutInflater.from(parent.context)
146         val view = inflater.inflate(R.layout.screen_share_dialog_spinner_item_text, parent, false)
147         val titleTextView = view.findViewById<TextView>(android.R.id.text1)
148         val errorTextView = view.findViewById<TextView>(android.R.id.text2)
149         titleTextView.text = getItem(position)
150         errorTextView.text = options[position].spinnerDisabledText
151         if (isEnabled(position)) {
152             errorTextView.visibility = View.GONE
153             titleTextView.isEnabled = true
154         } else {
155             errorTextView.visibility = View.VISIBLE
156             titleTextView.isEnabled = false
157         }
158         return view
159     }
160 }
161