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

Commit c6e9c5d5 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Controls UI - Haptics for touch/drag events" into rvc-dev am: 153d5f6b

Change-Id: I3f02f78a501867f457d067417ea06741de8714ea
parents 377a8f6f 153d5f6b
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -18,28 +18,46 @@ package com.android.systemui.controls.ui

import android.app.Dialog
import android.content.Intent
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.view.HapticFeedbackConstants
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.util.concurrency.DelayableExecutor

object ControlActionCoordinator {
    const val MIN_LEVEL = 0
    const val MAX_LEVEL = 10000

    private var dialog: Dialog? = null
    private var vibrator: Vibrator? = null

    lateinit var bgExecutor: DelayableExecutor

    fun closeDialog() {
        dialog?.dismiss()
        dialog = null
    }

    /**
     * Create custom vibrations, all intended to create very subtle feedback while interacting
     * with the controls.
     */
    fun initialize(vibrator: Vibrator, bgExecutor: DelayableExecutor) {
        this.vibrator = vibrator
        this.bgExecutor = bgExecutor
    }

    fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
        val effect = if (isChecked) Vibrations.toggleOnEffect else Vibrations.toggleOffEffect
        vibrate(effect)
        cvh.action(BooleanAction(templateId, !isChecked))
    }

    fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
        vibrate(Vibrations.toggleOnEffect)
        if (cvh.usePanel()) {
            showDialog(cvh, control.getAppIntent().getIntent())
        } else {
@@ -47,6 +65,14 @@ object ControlActionCoordinator {
        }
    }

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

    /**
     * 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.
@@ -59,6 +85,12 @@ object ControlActionCoordinator {
        }
    }

    private fun vibrate(effect: VibrationEffect) {
        vibrator?.let {
            bgExecutor.execute { it.vibrate(effect) }
        }
    }

    private fun showDialog(cvh: ControlViewHolder, intent: Intent) {
        dialog = DetailDialog(cvh, intent).also {
            it.setOnDismissListener { _ -> dialog = null }
+6 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.os.Process
import android.os.Vibrator
import android.service.controls.Control
import android.service.controls.actions.ControlAction
import android.util.Log
@@ -109,6 +110,11 @@ class ControlsUiControllerImpl @Inject constructor (

    private lateinit var listingCallback: ControlsListingController.ControlsListingCallback

    init {
        val vibratorService = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
        ControlActionCoordinator.initialize(vibratorService, bgExecutor)
    }

    private fun createCallback(
        onResult: (List<SelectionItem>) -> Unit
    ): ControlsListingController.ControlsListingCallback {
+4 −0
Original line number Diff line number Diff line
@@ -181,9 +181,13 @@ class ToggleRangeBehavior : Behavior {
    fun updateRange(level: Int, checked: Boolean, isDragging: Boolean) {
        val newLevel = if (checked) Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, level)) else MIN_LEVEL

        if (newLevel == clipLayer.level) return

        rangeAnimator?.cancel()
        if (isDragging) {
            clipLayer.level = newLevel
            val isEdge = newLevel == MIN_LEVEL || newLevel == MAX_LEVEL
            ControlActionCoordinator.drag(isEdge)
        } else {
            rangeAnimator = ValueAnimator.ofInt(cvh.clipLayer.level, newLevel).apply {
                addUpdateListener {
+62 −0
Original line number Diff line number Diff line
/*
 * 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.os.VibrationEffect
import android.os.VibrationEffect.Composition.PRIMITIVE_TICK

object Vibrations {
    private const val TOGGLE_TICK_COUNT = 12

    val toggleOnEffect = initToggleOnEffect()
    val toggleOffEffect = initToggleOffEffect()
    val rangeEdgeEffect = initRangeEdgeEffect()
    val rangeMiddleEffect = initRangeMiddleEffect()

    private fun initToggleOnEffect(): VibrationEffect {
        val composition = VibrationEffect.startComposition()
        var i = 0
        while (i++ < TOGGLE_TICK_COUNT) {
            composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 0)
        }
        composition.addPrimitive(PRIMITIVE_TICK, 0.5f, 100)
        return composition.compose()
    }

    private fun initToggleOffEffect(): VibrationEffect {
        val composition = VibrationEffect.startComposition()
        composition.addPrimitive(PRIMITIVE_TICK, 0.5f, 0)
        composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 100)
        var i = 0
        while (i++ < TOGGLE_TICK_COUNT) {
            composition?.addPrimitive(PRIMITIVE_TICK, 0.05f, 0)
        }
        return composition.compose()
    }

    private fun initRangeEdgeEffect(): VibrationEffect {
        val composition = VibrationEffect.startComposition()
        composition.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
        return composition.compose()
    }

    private fun initRangeMiddleEffect(): VibrationEffect {
        val composition = VibrationEffect.startComposition()
        composition.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.1f)
        return composition.compose()
    }
}