1 /* <lambda>null2 * 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.ui 18 19 import android.app.AlertDialog 20 import android.app.Dialog 21 import android.content.DialogInterface 22 import android.service.controls.actions.BooleanAction 23 import android.service.controls.actions.CommandAction 24 import android.service.controls.actions.ControlAction 25 import android.service.controls.actions.FloatAction 26 import android.service.controls.actions.ModeAction 27 import android.text.InputType 28 import android.util.Log 29 import android.view.LayoutInflater 30 import android.view.WindowManager 31 import android.view.inputmethod.InputMethodManager 32 import android.widget.CheckBox 33 import android.widget.EditText 34 35 import com.android.systemui.res.R 36 37 /** 38 * Creates all dialogs for challengeValues that can occur from a call to 39 * [ControlsProviderService#performControlAction]. The types of challenge responses are listed in 40 * [ControlAction.ResponseResult]. 41 */ 42 object ChallengeDialogs { 43 44 private const val WINDOW_TYPE = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY 45 private const val STYLE = android.R.style.Theme_DeviceDefault_Dialog_Alert 46 47 /** 48 * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_PIN] and 49 * [ControlAction#RESPONSE_CHALLENGE_PIN] responses, decided by the useAlphaNumeric 50 * parameter. 51 */ 52 fun createPinDialog( 53 cvh: ControlViewHolder, 54 useAlphaNumeric: Boolean, 55 useRetryStrings: Boolean, 56 onCancel: () -> Unit 57 ): Dialog? { 58 val lastAction = cvh.lastAction 59 if (lastAction == null) { 60 Log.e(ControlsUiController.TAG, 61 "PIN Dialog attempted but no last action is set. Will not show") 62 return null 63 } 64 val res = cvh.context.resources 65 val (title, instructions) = if (useRetryStrings) { 66 Pair( 67 res.getString(R.string.controls_pin_wrong), 68 R.string.controls_pin_instructions_retry 69 ) 70 } else { 71 Pair( 72 res.getString(R.string.controls_pin_verify, cvh.title.getText()), 73 R.string.controls_pin_instructions 74 ) 75 } 76 return object : AlertDialog(cvh.context, STYLE) { 77 override fun dismiss() { 78 window?.decorView?.let { 79 // workaround for b/159309083 80 it.context.getSystemService(InputMethodManager::class.java) 81 ?.hideSoftInputFromWindow(it.windowToken, 0) 82 } 83 super.dismiss() 84 } 85 }.apply { 86 setTitle(title) 87 setView(LayoutInflater.from(context).inflate(R.layout.controls_dialog_pin, null)) 88 setButton( 89 DialogInterface.BUTTON_POSITIVE, 90 context.getText(android.R.string.ok), 91 DialogInterface.OnClickListener { dialog, _ -> 92 if (dialog is Dialog) { 93 dialog.requireViewById<EditText>(R.id.controls_pin_input) 94 val pin = dialog.requireViewById<EditText>(R.id.controls_pin_input) 95 .getText().toString() 96 cvh.action(addChallengeValue(lastAction, pin)) 97 dialog.dismiss() 98 } 99 }) 100 setButton( 101 DialogInterface.BUTTON_NEGATIVE, 102 context.getText(android.R.string.cancel), 103 DialogInterface.OnClickListener { dialog, _ -> 104 onCancel.invoke() 105 dialog.cancel() 106 } 107 ) 108 109 window?.setType(WINDOW_TYPE) 110 window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) 111 setOnShowListener(DialogInterface.OnShowListener { _ -> 112 val editText = requireViewById<EditText>(R.id.controls_pin_input) 113 editText.setHint(instructions) 114 val useAlphaCheckBox = requireViewById<CheckBox>(R.id.controls_pin_use_alpha) 115 useAlphaCheckBox.setChecked(useAlphaNumeric) 116 setInputType(editText, useAlphaCheckBox.isChecked()) 117 requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { _ -> 118 setInputType(editText, useAlphaCheckBox.isChecked()) 119 } 120 editText.requestFocus() 121 }) 122 } 123 } 124 125 /** 126 * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_ACK] response type. 127 */ 128 fun createConfirmationDialog(cvh: ControlViewHolder, onCancel: () -> Unit): Dialog? { 129 val lastAction = cvh.lastAction 130 if (lastAction == null) { 131 Log.e(ControlsUiController.TAG, 132 "Confirmation Dialog attempted but no last action is set. Will not show") 133 return null 134 } 135 val builder = AlertDialog.Builder(cvh.context, STYLE).apply { 136 val res = cvh.context.resources 137 setTitle(res.getString( 138 R.string.controls_confirmation_message, cvh.title.getText())) 139 setPositiveButton( 140 android.R.string.ok, 141 DialogInterface.OnClickListener { dialog, _ -> 142 cvh.action(addChallengeValue(lastAction, "true")) 143 dialog.dismiss() 144 }) 145 setNegativeButton( 146 android.R.string.cancel, 147 DialogInterface.OnClickListener { dialog, _ -> 148 onCancel.invoke() 149 dialog.cancel() 150 } 151 ) 152 } 153 return builder.create().apply { 154 window?.setType(WINDOW_TYPE) 155 } 156 } 157 158 private fun setInputType(editText: EditText, useTextInput: Boolean) { 159 if (useTextInput) { 160 editText.setInputType( 161 InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD) 162 } else { 163 editText.setInputType( 164 InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD) 165 } 166 } 167 168 private fun addChallengeValue(action: ControlAction, challengeValue: String): ControlAction { 169 val id = action.getTemplateId() 170 return when (action) { 171 is BooleanAction -> BooleanAction(id, action.getNewState(), challengeValue) 172 is FloatAction -> FloatAction(id, action.getNewValue(), challengeValue) 173 is CommandAction -> CommandAction(id, challengeValue) 174 is ModeAction -> ModeAction(id, action.getNewMode(), challengeValue) 175 else -> throw IllegalStateException("'action' is not a known type: $action") 176 } 177 } 178 } 179