blob: b6c09f124f77c5bbc752a61f7d42e9b6de0bd0bf [file] [log] [blame]
Matt Pietalb7da66c2020-03-06 10:49:31 -05001/*
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
17package com.android.systemui.controls.ui
18
19import android.app.AlertDialog
20import android.app.Dialog
21import android.content.DialogInterface
22import android.service.controls.actions.BooleanAction
23import android.service.controls.actions.CommandAction
24import android.service.controls.actions.ControlAction
25import android.service.controls.actions.FloatAction
26import android.service.controls.actions.ModeAction
27import android.text.InputType
28import android.util.Log
29import android.view.WindowManager
30import android.widget.CheckBox
31import android.widget.EditText
32
33import com.android.systemui.R
34
35/**
36 * Creates all dialogs for challengeValues that can occur from a call to
Matt Pietalea87e742020-03-26 13:28:02 -040037 * [ControlsProviderService#performControlAction]. The types of challenge responses are listed in
38 * [ControlAction.ResponseResult].
Matt Pietalb7da66c2020-03-06 10:49:31 -050039 */
40object ChallengeDialogs {
41
Matt Pietalea87e742020-03-26 13:28:02 -040042 private const val WINDOW_TYPE = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
43 private const val STYLE = android.R.style.Theme_DeviceDefault_Dialog_Alert
44
45 /**
46 * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_PIN] and
47 * [ControlAction#RESPONSE_CHALLENGE_PIN] responses, decided by the useAlphaNumeric
48 * parameter.
49 */
Matt Pietal94316e92020-04-22 10:58:32 -040050 fun createPinDialog(
51 cvh: ControlViewHolder,
52 useAlphaNumeric: Boolean,
Matt Pietale4dda8b2020-05-08 09:03:57 -040053 useRetryStrings: Boolean,
54 onCancel: () -> Unit
Matt Pietal94316e92020-04-22 10:58:32 -040055 ): Dialog? {
Matt Pietalb7da66c2020-03-06 10:49:31 -050056 val lastAction = cvh.lastAction
57 if (lastAction == null) {
58 Log.e(ControlsUiController.TAG,
59 "PIN Dialog attempted but no last action is set. Will not show")
60 return null
61 }
Matt Pietal94316e92020-04-22 10:58:32 -040062 val res = cvh.context.resources
63 val (title, instructions) = if (useRetryStrings) {
64 Pair(
65 res.getString(R.string.controls_pin_wrong),
66 R.string.controls_pin_instructions_retry
67 )
68 } else {
69 Pair(
70 res.getString(R.string.controls_pin_verify, cvh.title.getText()),
71 R.string.controls_pin_instructions
72 )
73 }
Matt Pietalea87e742020-03-26 13:28:02 -040074 val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
Matt Pietal94316e92020-04-22 10:58:32 -040075 setTitle(title)
Matt Pietalb7da66c2020-03-06 10:49:31 -050076 setView(R.layout.controls_dialog_pin)
77 setPositiveButton(
78 android.R.string.ok,
79 DialogInterface.OnClickListener { dialog, _ ->
80 if (dialog is Dialog) {
81 dialog.requireViewById<EditText>(R.id.controls_pin_input)
82 val pin = dialog.requireViewById<EditText>(R.id.controls_pin_input)
83 .getText().toString()
84 cvh.action(addChallengeValue(lastAction, pin))
85 dialog.dismiss()
86 }
87 })
88 setNegativeButton(
89 android.R.string.cancel,
Matt Pietale4dda8b2020-05-08 09:03:57 -040090 DialogInterface.OnClickListener { dialog, _ ->
91 onCancel.invoke()
92 dialog.cancel()
93 }
Matt Pietalb7da66c2020-03-06 10:49:31 -050094 )
95 }
96 return builder.create().apply {
97 getWindow().apply {
Matt Pietalea87e742020-03-26 13:28:02 -040098 setType(WINDOW_TYPE)
Matt Pietalb7da66c2020-03-06 10:49:31 -050099 setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
100 }
101 setOnShowListener(DialogInterface.OnShowListener { _ ->
102 val editText = requireViewById<EditText>(R.id.controls_pin_input)
Matt Pietal94316e92020-04-22 10:58:32 -0400103 editText.setHint(instructions)
Matt Pietalea87e742020-03-26 13:28:02 -0400104 val useAlphaCheckBox = requireViewById<CheckBox>(R.id.controls_pin_use_alpha)
105 useAlphaCheckBox.setChecked(useAlphaNumeric)
106 setInputType(editText, useAlphaCheckBox.isChecked())
107 requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { _ ->
108 setInputType(editText, useAlphaCheckBox.isChecked())
Matt Pietalb7da66c2020-03-06 10:49:31 -0500109 }
110 editText.requestFocus()
111 })
112 }
113 }
114
Matt Pietalea87e742020-03-26 13:28:02 -0400115 /**
116 * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_ACK] response type.
117 */
Matt Pietale4dda8b2020-05-08 09:03:57 -0400118 fun createConfirmationDialog(cvh: ControlViewHolder, onCancel: () -> Unit): Dialog? {
Matt Pietalea87e742020-03-26 13:28:02 -0400119 val lastAction = cvh.lastAction
120 if (lastAction == null) {
121 Log.e(ControlsUiController.TAG,
122 "Confirmation Dialog attempted but no last action is set. Will not show")
123 return null
124 }
125 val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
126 val res = cvh.context.resources
127 setMessage(res.getString(
128 R.string.controls_confirmation_message, cvh.title.getText()))
129 setPositiveButton(
130 android.R.string.ok,
131 DialogInterface.OnClickListener { dialog, _ ->
132 cvh.action(addChallengeValue(lastAction, "true"))
133 dialog.dismiss()
134 })
135 setNegativeButton(
136 android.R.string.cancel,
Matt Pietale4dda8b2020-05-08 09:03:57 -0400137 DialogInterface.OnClickListener { dialog, _ ->
138 onCancel.invoke()
139 dialog.cancel()
140 }
Matt Pietalea87e742020-03-26 13:28:02 -0400141 )
142 }
143 return builder.create().apply {
144 getWindow().apply {
145 setType(WINDOW_TYPE)
146 }
147 }
148 }
149
150 private fun setInputType(editText: EditText, useTextInput: Boolean) {
151 if (useTextInput) {
152 editText.setInputType(
153 InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD)
154 } else {
155 editText.setInputType(
156 InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD)
157 }
158 }
159
Matt Pietalb7da66c2020-03-06 10:49:31 -0500160 private fun addChallengeValue(action: ControlAction, challengeValue: String): ControlAction {
161 val id = action.getTemplateId()
162 return when (action) {
163 is BooleanAction -> BooleanAction(id, action.getNewState(), challengeValue)
164 is FloatAction -> FloatAction(id, action.getNewValue(), challengeValue)
165 is CommandAction -> CommandAction(id, challengeValue)
166 is ModeAction -> ModeAction(id, action.getNewMode(), challengeValue)
167 else -> throw IllegalStateException("'action' is not a known type: $action")
168 }
169 }
170}