blob: 1f07e37d2ad046be0429ad02e3e62d210f24be4c [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,
53 useRetryStrings: Boolean
54 ): Dialog? {
Matt Pietalb7da66c2020-03-06 10:49:31 -050055 val lastAction = cvh.lastAction
56 if (lastAction == null) {
57 Log.e(ControlsUiController.TAG,
58 "PIN Dialog attempted but no last action is set. Will not show")
59 return null
60 }
Matt Pietal94316e92020-04-22 10:58:32 -040061 val res = cvh.context.resources
62 val (title, instructions) = if (useRetryStrings) {
63 Pair(
64 res.getString(R.string.controls_pin_wrong),
65 R.string.controls_pin_instructions_retry
66 )
67 } else {
68 Pair(
69 res.getString(R.string.controls_pin_verify, cvh.title.getText()),
70 R.string.controls_pin_instructions
71 )
72 }
Matt Pietalea87e742020-03-26 13:28:02 -040073 val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
Matt Pietal94316e92020-04-22 10:58:32 -040074 setTitle(title)
Matt Pietalb7da66c2020-03-06 10:49:31 -050075 setView(R.layout.controls_dialog_pin)
76 setPositiveButton(
77 android.R.string.ok,
78 DialogInterface.OnClickListener { dialog, _ ->
79 if (dialog is Dialog) {
80 dialog.requireViewById<EditText>(R.id.controls_pin_input)
81 val pin = dialog.requireViewById<EditText>(R.id.controls_pin_input)
82 .getText().toString()
83 cvh.action(addChallengeValue(lastAction, pin))
84 dialog.dismiss()
85 }
86 })
87 setNegativeButton(
88 android.R.string.cancel,
89 DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() }
90 )
91 }
92 return builder.create().apply {
93 getWindow().apply {
Matt Pietalea87e742020-03-26 13:28:02 -040094 setType(WINDOW_TYPE)
Matt Pietalb7da66c2020-03-06 10:49:31 -050095 setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
96 }
97 setOnShowListener(DialogInterface.OnShowListener { _ ->
98 val editText = requireViewById<EditText>(R.id.controls_pin_input)
Matt Pietal94316e92020-04-22 10:58:32 -040099 editText.setHint(instructions)
Matt Pietalea87e742020-03-26 13:28:02 -0400100 val useAlphaCheckBox = requireViewById<CheckBox>(R.id.controls_pin_use_alpha)
101 useAlphaCheckBox.setChecked(useAlphaNumeric)
102 setInputType(editText, useAlphaCheckBox.isChecked())
103 requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { _ ->
104 setInputType(editText, useAlphaCheckBox.isChecked())
Matt Pietalb7da66c2020-03-06 10:49:31 -0500105 }
106 editText.requestFocus()
107 })
108 }
109 }
110
Matt Pietalea87e742020-03-26 13:28:02 -0400111 /**
112 * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_ACK] response type.
113 */
114 fun createConfirmationDialog(cvh: ControlViewHolder): Dialog? {
115 val lastAction = cvh.lastAction
116 if (lastAction == null) {
117 Log.e(ControlsUiController.TAG,
118 "Confirmation Dialog attempted but no last action is set. Will not show")
119 return null
120 }
121 val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
122 val res = cvh.context.resources
123 setMessage(res.getString(
124 R.string.controls_confirmation_message, cvh.title.getText()))
125 setPositiveButton(
126 android.R.string.ok,
127 DialogInterface.OnClickListener { dialog, _ ->
128 cvh.action(addChallengeValue(lastAction, "true"))
129 dialog.dismiss()
130 })
131 setNegativeButton(
132 android.R.string.cancel,
133 DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() }
134 )
135 }
136 return builder.create().apply {
137 getWindow().apply {
138 setType(WINDOW_TYPE)
139 }
140 }
141 }
142
143 private fun setInputType(editText: EditText, useTextInput: Boolean) {
144 if (useTextInput) {
145 editText.setInputType(
146 InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD)
147 } else {
148 editText.setInputType(
149 InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD)
150 }
151 }
152
Matt Pietalb7da66c2020-03-06 10:49:31 -0500153 private fun addChallengeValue(action: ControlAction, challengeValue: String): ControlAction {
154 val id = action.getTemplateId()
155 return when (action) {
156 is BooleanAction -> BooleanAction(id, action.getNewState(), challengeValue)
157 is FloatAction -> FloatAction(id, action.getNewValue(), challengeValue)
158 is CommandAction -> CommandAction(id, challengeValue)
159 is ModeAction -> ModeAction(id, action.getNewMode(), challengeValue)
160 else -> throw IllegalStateException("'action' is not a known type: $action")
161 }
162 }
163}