• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.systemui.controls.management
18 
19 import android.app.AlertDialog
20 import android.app.Dialog
21 import android.content.ComponentName
22 import android.content.DialogInterface
23 import android.content.Intent
24 import android.os.Bundle
25 import android.os.UserHandle
26 import android.service.controls.Control
27 import android.service.controls.ControlsProviderService
28 import android.util.Log
29 import android.view.LayoutInflater
30 import android.view.View
31 import android.widget.ImageView
32 import android.widget.TextView
33 import com.android.systemui.R
34 import com.android.systemui.broadcast.BroadcastDispatcher
35 import com.android.systemui.controls.ControlsServiceInfo
36 import com.android.systemui.controls.controller.ControlInfo
37 import com.android.systemui.controls.controller.ControlsController
38 import com.android.systemui.controls.ui.RenderInfo
39 import com.android.systemui.settings.CurrentUserTracker
40 import com.android.systemui.statusbar.phone.SystemUIDialog
41 import com.android.systemui.util.LifecycleActivity
42 import javax.inject.Inject
43 
44 open class ControlsRequestDialog @Inject constructor(
45     private val controller: ControlsController,
46     private val broadcastDispatcher: BroadcastDispatcher,
47     private val controlsListingController: ControlsListingController
48 ) : LifecycleActivity(), DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
49 
50     companion object {
51         private const val TAG = "ControlsRequestDialog"
52     }
53 
54     private lateinit var controlComponent: ComponentName
55     private lateinit var control: Control
56     private var dialog: Dialog? = null
57     private val callback = object : ControlsListingController.ControlsListingCallback {
onServicesUpdatednull58         override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {}
59     }
60 
61     private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
62         private val startingUser = controller.currentUserId
63 
onUserSwitchednull64         override fun onUserSwitched(newUserId: Int) {
65             if (newUserId != startingUser) {
66                 stopTracking()
67                 finish()
68             }
69         }
70     }
71 
onCreatenull72     override fun onCreate(savedInstanceState: Bundle?) {
73         super.onCreate(savedInstanceState)
74 
75         currentUserTracker.startTracking()
76         controlsListingController.addCallback(callback)
77 
78         val requestUser = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL)
79         val currentUser = controller.currentUserId
80 
81         if (requestUser != currentUser) {
82             Log.w(TAG, "Current user ($currentUser) different from request user ($requestUser)")
83             finish()
84         }
85 
86         controlComponent = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME) ?: run {
87             Log.e(TAG, "Request did not contain componentName")
88             finish()
89             return
90         }
91 
92         control = intent.getParcelableExtra(ControlsProviderService.EXTRA_CONTROL) ?: run {
93             Log.e(TAG, "Request did not contain control")
94             finish()
95             return
96         }
97     }
98 
onResumenull99     override fun onResume() {
100         super.onResume()
101         val label = verifyComponentAndGetLabel()
102         if (label == null) {
103             Log.e(TAG, "The component specified (${controlComponent.flattenToString()} " +
104                     "is not a valid ControlsProviderService")
105             finish()
106             return
107         }
108 
109         if (isCurrentFavorite()) {
110             Log.w(TAG, "The control ${control.title} is already a favorite")
111             finish()
112         }
113 
114         dialog = createDialog(label)
115 
116         dialog?.show()
117     }
118 
onDestroynull119     override fun onDestroy() {
120         dialog?.dismiss()
121         currentUserTracker.stopTracking()
122         controlsListingController.removeCallback(callback)
123         super.onDestroy()
124     }
125 
verifyComponentAndGetLabelnull126     private fun verifyComponentAndGetLabel(): CharSequence? {
127         return controlsListingController.getAppLabel(controlComponent)
128     }
129 
isCurrentFavoritenull130     private fun isCurrentFavorite(): Boolean {
131         val favorites = controller.getFavoritesForComponent(controlComponent)
132         return favorites.any { it.controls.any { it.controlId == control.controlId } }
133     }
134 
createDialognull135     fun createDialog(label: CharSequence): Dialog {
136         val renderInfo = RenderInfo.lookup(this, controlComponent, control.deviceType)
137         val frame = LayoutInflater.from(this).inflate(R.layout.controls_dialog, null).apply {
138             requireViewById<ImageView>(R.id.icon).apply {
139                 setImageDrawable(renderInfo.icon)
140                 setImageTintList(
141                         context.resources.getColorStateList(renderInfo.foreground, context.theme))
142             }
143             requireViewById<TextView>(R.id.title).text = control.title
144             requireViewById<TextView>(R.id.subtitle).text = control.subtitle
145             requireViewById<View>(R.id.control).elevation =
146                     resources.getFloat(R.dimen.control_card_elevation)
147         }
148 
149         val dialog = AlertDialog.Builder(this)
150                 .setTitle(getString(R.string.controls_dialog_title))
151                 .setMessage(getString(R.string.controls_dialog_message, label))
152                 .setPositiveButton(R.string.controls_dialog_ok, this)
153                 .setNegativeButton(android.R.string.cancel, this)
154                 .setOnCancelListener(this)
155                 .setView(frame)
156                 .create()
157 
158         SystemUIDialog.registerDismissListener(dialog)
159         dialog.setCanceledOnTouchOutside(true)
160         return dialog
161     }
162 
onCancelnull163     override fun onCancel(dialog: DialogInterface?) {
164         finish()
165     }
166 
onClicknull167     override fun onClick(dialog: DialogInterface?, which: Int) {
168         if (which == Dialog.BUTTON_POSITIVE) {
169             controller.addFavorite(
170                 controlComponent,
171                 control.structure ?: "",
172                 ControlInfo(control.controlId, control.title, control.subtitle, control.deviceType)
173             )
174         }
175         finish()
176     }
177 }
178