diff --git a/packages/SystemUI/res/layout/controls_dialog_pin.xml b/packages/SystemUI/res/layout/controls_dialog_pin.xml
new file mode 100644
index 0000000000000..b77d6fa6a9567
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_dialog_pin.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5b28479ab5caf..caf22fe16bebc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2646,4 +2646,11 @@
Add to favorites
%s suggested this control to add to your favorites.
+
+
+ PIN contains letters or symbols
+
+ Verify device PIN
+
+ Enter PIN
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
new file mode 100644
index 0000000000000..2494fd119670c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.content.DialogInterface
+import android.service.controls.actions.BooleanAction
+import android.service.controls.actions.CommandAction
+import android.service.controls.actions.ControlAction
+import android.service.controls.actions.FloatAction
+import android.service.controls.actions.ModeAction
+import android.text.InputType
+import android.util.Log
+import android.view.WindowManager
+import android.widget.CheckBox
+import android.widget.EditText
+
+import com.android.systemui.R
+
+/**
+ * Creates all dialogs for challengeValues that can occur from a call to
+ * {@link ControlsProviderService#performControlAction}. The types of challenge
+ * responses are listed in {@link ControlAction.ResponseResult}.
+ */
+object ChallengeDialogs {
+
+ fun createPinDialog(cvh: ControlViewHolder): Dialog? {
+ val lastAction = cvh.lastAction
+ if (lastAction == null) {
+ Log.e(ControlsUiController.TAG,
+ "PIN Dialog attempted but no last action is set. Will not show")
+ return null
+ }
+ val builder = AlertDialog.Builder(
+ cvh.context,
+ android.R.style.Theme_DeviceDefault_Dialog_Alert
+ ).apply {
+ setTitle(R.string.controls_pin_verify)
+ setView(R.layout.controls_dialog_pin)
+ setPositiveButton(
+ android.R.string.ok,
+ DialogInterface.OnClickListener { dialog, _ ->
+ if (dialog is Dialog) {
+ dialog.requireViewById(R.id.controls_pin_input)
+ val pin = dialog.requireViewById(R.id.controls_pin_input)
+ .getText().toString()
+ cvh.action(addChallengeValue(lastAction, pin))
+ dialog.dismiss()
+ }
+ })
+ setNegativeButton(
+ android.R.string.cancel,
+ DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() }
+ )
+ }
+ return builder.create().apply {
+ getWindow().apply {
+ setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+ setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
+ }
+ setOnShowListener(DialogInterface.OnShowListener { _ ->
+ val editText = requireViewById(R.id.controls_pin_input)
+ requireViewById(R.id.controls_pin_use_alpha).setOnClickListener { v ->
+ if ((v as CheckBox).isChecked) {
+ editText.setInputType(
+ InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD)
+ } else {
+ editText.setInputType(
+ InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD)
+ }
+ }
+ editText.requestFocus()
+ })
+ }
+ }
+
+ private fun addChallengeValue(action: ControlAction, challengeValue: String): ControlAction {
+ val id = action.getTemplateId()
+ return when (action) {
+ is BooleanAction -> BooleanAction(id, action.getNewState(), challengeValue)
+ is FloatAction -> FloatAction(id, action.getNewValue(), challengeValue)
+ is CommandAction -> CommandAction(id, challengeValue)
+ is ModeAction -> ModeAction(id, action.getNewMode(), challengeValue)
+ else -> throw IllegalStateException("'action' is not a known type: $action")
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index d56428dbcdbe8..b1b98bc7d044e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -27,7 +27,6 @@ import android.service.controls.templates.ControlTemplate
import android.service.controls.templates.TemperatureControlTemplate
import android.service.controls.templates.ToggleRangeTemplate
import android.service.controls.templates.ToggleTemplate
-import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
@@ -57,6 +56,7 @@ class ControlViewHolder(
lateinit var cws: ControlWithState
var cancelUpdate: Runnable? = null
var behavior: Behavior? = null
+ var lastAction: ControlAction? = null
init {
val ld = layout.getBackground() as LayerDrawable
@@ -98,7 +98,6 @@ class ControlViewHolder(
fun actionResponse(@ControlAction.ResponseResult response: Int) {
// TODO: b/150931809 - handle response codes
- Log.d(ControlsUiController.TAG, "Received response code: $response")
}
fun setTransientStatus(tempStatus: String) {
@@ -115,6 +114,7 @@ class ControlViewHolder(
}
fun action(action: ControlAction) {
+ lastAction = action
controlsController.action(cws.componentName, cws.ci, action)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index eaf57ff208e5e..ca6619b59c4dc 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -18,6 +18,7 @@ package com.android.systemui.controls.ui
import android.accounts.Account
import android.accounts.AccountManager
+import android.app.Dialog
import android.content.ComponentName
import android.content.Context
import android.content.Intent
@@ -28,6 +29,7 @@ import android.graphics.drawable.LayerDrawable
import android.os.IBinder
import android.service.controls.Control
import android.service.controls.TokenProvider
+import android.service.controls.actions.ControlAction
import android.util.Log
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
@@ -49,8 +51,8 @@ import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.R
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.R
import dagger.Lazy
@@ -152,7 +154,7 @@ class ControlsUiControllerImpl @Inject constructor (
private lateinit var parent: ViewGroup
private lateinit var lastItems: List
private var popup: ListPopupWindow? = null
-
+ private var activeDialog: Dialog? = null
private val addControlsItem: SelectionItem
init {
@@ -388,6 +390,7 @@ class ControlsUiControllerImpl @Inject constructor (
override fun hide() {
Log.d(ControlsUiController.TAG, "hide()")
popup?.dismiss()
+ activeDialog?.dismiss()
controlsController.get().unsubscribe()
context.unbindService(tokenProviderConnection)
@@ -418,7 +421,15 @@ class ControlsUiControllerImpl @Inject constructor (
override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) {
val key = ControlKey(componentName, controlId)
uiExecutor.execute {
- controlViewsById.get(key)?.actionResponse(response)
+ controlViewsById.get(key)?.let { cvh ->
+ when (response) {
+ ControlAction.RESPONSE_CHALLENGE_PIN -> {
+ activeDialog = ChallengeDialogs.createPinDialog(cvh)
+ activeDialog?.show()
+ }
+ else -> cvh.actionResponse(response)
+ }
+ }
}
}