Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 386cc806 authored by Matt Pietal's avatar Matt Pietal Committed by Automerger Merge Worker
Browse files

Merge "Controls UI - Fix action on unlock" into rvc-dev am: 627b49ad am: 4e385c1b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11753731

Change-Id: I0c87b63aa5363ff22ad243f069b631b3d44769a5
parents e0ddf1d3 4e385c1b
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -54,6 +54,28 @@ interface ControlActionCoordinator {
     */
    fun drag(isEdge: Boolean)

    /**
     * Send a request to update the value of a device using the [FloatAction].
     *
     * @param cvh [ControlViewHolder] for the control
     * @param templateId id of the control's template, as given by the service
     * @param newValue value to set for the device
     */
    fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float)

    /**
     * Actions may have been put on hold while the device is unlocked. Invoke this action if
     * present.
     */
    fun runPendingAction(controlId: String)

    /**
     * User interaction with a control may be blocked for a period of time while actions are being
     * executed by the application.  When the response returns, run this method to enable further
     * user interaction.
     */
    fun enableActionOnTouch(controlId: String)

    /**
     * All long presses will be shown in a 3/4 height bottomsheet panel, in order for the user to
     * retain context with their favorited controls in the power menu.
+61 −16
Original line number Diff line number Diff line
@@ -21,11 +21,13 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.annotation.MainThread
import android.os.Vibrator
import android.os.VibrationEffect
import android.service.controls.Control
import android.service.controls.actions.BooleanAction
import android.service.controls.actions.CommandAction
import android.service.controls.actions.FloatAction
import android.util.Log
import android.view.HapticFeedbackConstants
import com.android.systemui.dagger.qualifiers.Main
@@ -49,7 +51,12 @@ class ControlActionCoordinatorImpl @Inject constructor(
) : ControlActionCoordinator {
    private var dialog: Dialog? = null
    private val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
    private var lastAction: (() -> Unit)? = null
    private var pendingAction: Action? = null
    private var actionsInProgress = mutableSetOf<String>()

    companion object {
        private const val RESPONSE_TIMEOUT_IN_MILLIS = 3000L
    }

    override fun closeDialogs() {
        dialog?.dismiss()
@@ -57,54 +64,84 @@ class ControlActionCoordinatorImpl @Inject constructor(
    }

    override fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
        bouncerOrRun {
        bouncerOrRun(Action(cvh.cws.ci.controlId, {
            cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
            cvh.action(BooleanAction(templateId, !isChecked))
        }
        }, true /* blockable */))
    }

    override fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
        bouncerOrRun {
        val blockable = cvh.usePanel()
        bouncerOrRun(Action(cvh.cws.ci.controlId, {
            cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
            if (cvh.usePanel()) {
                showDialog(cvh, control.getAppIntent().getIntent())
            } else {
                cvh.action(CommandAction(templateId))
            }
        }
        }, blockable))
    }

    override fun drag(isEdge: Boolean) {
        bouncerOrRun {
        if (isEdge) {
            vibrate(Vibrations.rangeEdgeEffect)
        } else {
            vibrate(Vibrations.rangeMiddleEffect)
        }
    }

    override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) {
        bouncerOrRun(Action(cvh.cws.ci.controlId, {
            cvh.action(FloatAction(templateId, newValue))
        }, true /* blockable */))
    }

    override fun longPress(cvh: ControlViewHolder) {
        bouncerOrRun {
        bouncerOrRun(Action(cvh.cws.ci.controlId, {
            // Long press snould only be called when there is valid control state, otherwise ignore
            cvh.cws.control?.let {
                cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
                showDialog(cvh, it.getAppIntent().getIntent())
            }
        }, false /* blockable */))
    }

    override fun runPendingAction(controlId: String) {
        if (pendingAction?.controlId == controlId) {
            pendingAction?.invoke()
            pendingAction = null
        }
    }

    private fun bouncerOrRun(f: () -> Unit) {
    @MainThread
    override fun enableActionOnTouch(controlId: String) {
        actionsInProgress.remove(controlId)
    }

    private fun shouldRunAction(controlId: String) =
        if (actionsInProgress.add(controlId)) {
            uiExecutor.executeDelayed({
                actionsInProgress.remove(controlId)
            }, RESPONSE_TIMEOUT_IN_MILLIS)
            true
        } else {
            false
        }

    private fun bouncerOrRun(action: Action) {
        if (!keyguardStateController.isUnlocked()) {
            context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))

            // pending actions will only run after the control state has been refreshed
            pendingAction = action

            activityStarter.dismissKeyguardThenExecute({
                Log.d(ControlsUiController.TAG, "Device unlocked, invoking controls action")
                globalActionsComponent.handleShowGlobalActionsMenu()
                f()
                true
            }, null, true)
            }, { pendingAction = null }, true /* afterKeyguardGone */)
        } else {
            f()
            action.invoke()
        }
    }

@@ -133,4 +170,12 @@ class ControlActionCoordinatorImpl @Inject constructor(
            }
        }
    }

    inner class Action(val controlId: String, val f: () -> Unit, val blockable: Boolean) {
        fun invoke() {
            if (!blockable || shouldRunAction(controlId)) {
                f.invoke()
            }
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -156,6 +156,8 @@ class ControlViewHolder(
                controlActionCoordinator.longPress(this@ControlViewHolder)
                true
            })

            controlActionCoordinator.runPendingAction(cws.ci.controlId)
        }

        isLoading = false
@@ -164,6 +166,8 @@ class ControlViewHolder(
    }

    fun actionResponse(@ControlAction.ResponseResult response: Int) {
        controlActionCoordinator.enableActionOnTouch(cws.ci.controlId)

        // OK responses signal normal behavior, and the app will provide control updates
        val failedAttempt = lastChallengeDialog != null
        when (response) {
+2 −3
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.service.controls.Control
import android.service.controls.actions.FloatAction
import android.service.controls.templates.ControlTemplate
import android.service.controls.templates.RangeTemplate
import android.service.controls.templates.TemperatureControlTemplate
@@ -293,8 +292,8 @@ class ToggleRangeBehavior : Behavior {
        cvh.setStatusTextSize(context.getResources()
                .getDimensionPixelSize(R.dimen.control_status_normal).toFloat())
        cvh.setStatusText("$currentStatusText $currentRangeValue", /* immediately */ true)
        cvh.action(FloatAction(rangeTemplate.getTemplateId(),
            findNearestStep(levelToRangeValue(clipLayer.getLevel()))))
        cvh.controlActionCoordinator.setValue(cvh, rangeTemplate.getTemplateId(),
            findNearestStep(levelToRangeValue(clipLayer.getLevel())))
    }

    fun findNearestStep(value: Float): Float {