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

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

Merge "Animate ranges and toggles" into rvc-dev am: 75c2e161

Change-Id: I4a0579927df17d6ffde14c5ac10902c322746b32
parents 9e35c850 75c2e161
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -54,6 +54,11 @@ public class Interpolators {
    public static final Interpolator PANEL_CLOSE_ACCELERATED
    public static final Interpolator PANEL_CLOSE_ACCELERATED
            = new PathInterpolator(0.3f, 0, 0.5f, 1);
            = new PathInterpolator(0.3f, 0, 0.5f, 1);
    public static final Interpolator BOUNCE = new BounceInterpolator();
    public static final Interpolator BOUNCE = new BounceInterpolator();
    /**
     * For state transitions on the control panel that lives in GlobalActions.
     */
    public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
            1.0f);


    /**
    /**
     * Interpolator to be used when animating a move based on a click. Pair with enough duration.
     * Interpolator to be used when animating a move based on a click. Pair with enough duration.
+2 −6
Original line number Original line Diff line number Diff line
@@ -24,12 +24,11 @@ import android.service.controls.actions.BooleanAction
import android.service.controls.actions.CommandAction
import android.service.controls.actions.CommandAction
import android.util.Log
import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.HapticFeedbackConstants

import com.android.systemui.R
import com.android.systemui.R


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


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


@@ -40,9 +39,6 @@ object ControlActionCoordinator {


    fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
    fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
        cvh.action(BooleanAction(templateId, !isChecked))
        cvh.action(BooleanAction(templateId, !isChecked))

        val nextLevel = if (isChecked) MIN_LEVEL else MAX_LEVEL
        cvh.clipLayer.setLevel(nextLevel)
    }
    }


    fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
    fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
+35 −10
Original line number Original line Diff line number Diff line
@@ -16,6 +16,9 @@


package com.android.systemui.controls.ui
package com.android.systemui.controls.ui


import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.content.Context
import android.graphics.drawable.ClipDrawable
import android.graphics.drawable.ClipDrawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.GradientDrawable
@@ -32,11 +35,11 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ImageView
import android.widget.TextView
import android.widget.TextView

import com.android.internal.graphics.ColorUtils
import com.android.systemui.Interpolators
import com.android.systemui.R
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.R

import kotlin.reflect.KClass
import kotlin.reflect.KClass


/**
/**
@@ -53,15 +56,17 @@ class ControlViewHolder(
) {
) {


    companion object {
    companion object {
        const val STATE_ANIMATION_DURATION = 700L
        private const val UPDATE_DELAY_IN_MILLIS = 3000L
        private const val UPDATE_DELAY_IN_MILLIS = 3000L
        private const val ALPHA_ENABLED = (255.0 * 0.2).toInt()
        private const val ALPHA_ENABLED = (255.0 * 0.2).toInt()
        private const val ALPHA_DISABLED = 255
        private const val ALPHA_DISABLED = 0
        private val FORCE_PANEL_DEVICES = setOf(
        private val FORCE_PANEL_DEVICES = setOf(
            DeviceTypes.TYPE_THERMOSTAT,
            DeviceTypes.TYPE_THERMOSTAT,
            DeviceTypes.TYPE_CAMERA
            DeviceTypes.TYPE_CAMERA
        )
        )
    }
    }


    private var stateAnimator: ValueAnimator? = null
    val icon: ImageView = layout.requireViewById(R.id.icon)
    val icon: ImageView = layout.requireViewById(R.id.icon)
    val status: TextView = layout.requireViewById(R.id.status)
    val status: TextView = layout.requireViewById(R.id.status)
    val title: TextView = layout.requireViewById(R.id.title)
    val title: TextView = layout.requireViewById(R.id.title)
@@ -79,6 +84,7 @@ class ControlViewHolder(
        val ld = layout.getBackground() as LayerDrawable
        val ld = layout.getBackground() as LayerDrawable
        ld.mutate()
        ld.mutate()
        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
        clipLayer.alpha = ALPHA_DISABLED
        // needed for marquee to start
        // needed for marquee to start
        status.setSelected(true)
        status.setSelected(true)
    }
    }
@@ -160,30 +166,49 @@ class ControlViewHolder(
        }
        }
    }
    }


    internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0) {
    internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0, animated: Boolean = true) {
        setEnabled(enabled)
        setEnabled(enabled)


        val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset)
        val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset)


        val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
        val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
        val (bg, alpha) = if (enabled) {
        val (bg, newAlpha) = if (enabled) {
            Pair(ri.enabledBackground, ALPHA_ENABLED)
            Pair(ri.enabledBackground, ALPHA_ENABLED)
        } else {
        } else {
            Pair(R.color.control_default_background, ALPHA_DISABLED)
            Pair(R.color.control_default_background, ALPHA_DISABLED)
        }
        }


        status.setTextColor(fg)
        status.setTextColor(fg)

        icon.setImageDrawable(ri.icon)
        icon.setImageDrawable(ri.icon)


        // do not color app icons
        // do not color app icons
        if (deviceType != DeviceTypes.TYPE_ROUTINE) {
        if (deviceType != DeviceTypes.TYPE_ROUTINE) {
            icon.setImageTintList(fg)
            icon.imageTintList = fg
        }
        }


        (clipLayer.getDrawable() as GradientDrawable).apply {
        (clipLayer.getDrawable() as GradientDrawable).apply {
            setColor(context.getResources().getColor(bg, context.getTheme()))
            val newColor = context.resources.getColor(bg, context.theme)
            setAlpha(alpha)
            stateAnimator?.cancel()
            if (animated) {
                val oldColor = color?.defaultColor ?: newColor
                stateAnimator = ValueAnimator.ofInt(clipLayer.alpha, newAlpha).apply {
                    addUpdateListener {
                        alpha = it.animatedValue as Int
                        setColor(ColorUtils.blendARGB(oldColor, newColor, it.animatedFraction))
                    }
                    addListener(object : AnimatorListenerAdapter() {
                        override fun onAnimationEnd(animation: Animator?) {
                            stateAnimator = null
                        }
                    })
                    duration = STATE_ANIMATION_DURATION
                    interpolator = Interpolators.CONTROL_STATE
                    start()
                }
            } else {
                alpha = newAlpha
                setColor(newColor)
            }
        }
        }
    }
    }


+3 −5
Original line number Original line Diff line number Diff line
@@ -18,12 +18,10 @@ package com.android.systemui.controls.ui


import android.graphics.drawable.Drawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.graphics.drawable.LayerDrawable
import android.view.View
import android.service.controls.Control
import android.service.controls.Control
import android.service.controls.templates.ToggleTemplate
import android.service.controls.templates.ToggleTemplate

import android.view.View
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL
import com.android.systemui.controls.ui.ControlActionCoordinator.MAX_LEVEL
import com.android.systemui.controls.ui.ControlActionCoordinator.MAX_LEVEL


class ToggleBehavior : Behavior {
class ToggleBehavior : Behavior {
@@ -34,7 +32,7 @@ class ToggleBehavior : Behavior {


    override fun initialize(cvh: ControlViewHolder) {
    override fun initialize(cvh: ControlViewHolder) {
        this.cvh = cvh
        this.cvh = cvh
        cvh.applyRenderInfo(false)
        cvh.applyRenderInfo(false /* enabled */, 0 /* offset */, false /* animated */)


        cvh.layout.setOnClickListener(View.OnClickListener() {
        cvh.layout.setOnClickListener(View.OnClickListener() {
            ControlActionCoordinator.toggle(cvh, template.getTemplateId(), template.isChecked())
            ControlActionCoordinator.toggle(cvh, template.getTemplateId(), template.isChecked())
@@ -49,9 +47,9 @@ class ToggleBehavior : Behavior {


        val ld = cvh.layout.getBackground() as LayerDrawable
        val ld = cvh.layout.getBackground() as LayerDrawable
        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
        clipLayer.level = MAX_LEVEL


        val checked = template.isChecked()
        val checked = template.isChecked()
        clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL)
        cvh.applyRenderInfo(checked)
        cvh.applyRenderInfo(checked)
    }
    }
}
}
+60 −29
Original line number Original line Diff line number Diff line
@@ -16,11 +16,20 @@


package com.android.systemui.controls.ui
package com.android.systemui.controls.ui


import android.os.Bundle
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
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.RangeTemplate
import android.service.controls.templates.ToggleRangeTemplate
import android.util.Log
import android.util.Log
import android.util.MathUtils
import android.util.TypedValue
import android.view.GestureDetector
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.MotionEvent
@@ -29,19 +38,14 @@ import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.TextView
import android.widget.TextView
import android.service.controls.Control
import com.android.systemui.Interpolators
import android.service.controls.actions.FloatAction
import android.service.controls.templates.RangeTemplate
import android.service.controls.templates.ToggleRangeTemplate
import android.util.TypedValue

import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL
import com.android.systemui.controls.ui.ControlActionCoordinator.MAX_LEVEL
import com.android.systemui.controls.ui.ControlActionCoordinator.MAX_LEVEL

import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL
import java.util.IllegalFormatException
import java.util.IllegalFormatException


class ToggleRangeBehavior : Behavior {
class ToggleRangeBehavior : Behavior {
    private var rangeAnimator: ValueAnimator? = null
    lateinit var clipLayer: Drawable
    lateinit var clipLayer: Drawable
    lateinit var template: ToggleRangeTemplate
    lateinit var template: ToggleRangeTemplate
    lateinit var control: Control
    lateinit var control: Control
@@ -61,20 +65,21 @@ class ToggleRangeBehavior : Behavior {
        status = cvh.status
        status = cvh.status
        context = status.getContext()
        context = status.getContext()


        cvh.applyRenderInfo(false)
        cvh.applyRenderInfo(false /* enabled */, 0 /* offset */, false /* animated */)


        val gestureListener = ToggleRangeGestureListener(cvh.layout)
        val gestureListener = ToggleRangeGestureListener(cvh.layout)
        val gestureDetector = GestureDetector(context, gestureListener)
        val gestureDetector = GestureDetector(context, gestureListener)
        cvh.layout.setOnTouchListener { v: View, e: MotionEvent ->
        cvh.layout.setOnTouchListener { v: View, e: MotionEvent ->
            if (gestureDetector.onTouchEvent(e)) {
            if (gestureDetector.onTouchEvent(e)) {
                return@setOnTouchListener true
                // Don't return true to let the state list change to "pressed"
                return@setOnTouchListener false
            }
            }


            if (e.getAction() == MotionEvent.ACTION_UP && gestureListener.isDragging) {
            if (e.getAction() == MotionEvent.ACTION_UP && gestureListener.isDragging) {
                v.getParent().requestDisallowInterceptTouchEvent(false)
                v.getParent().requestDisallowInterceptTouchEvent(false)
                gestureListener.isDragging = false
                gestureListener.isDragging = false
                endUpdateRange()
                endUpdateRange()
                return@setOnTouchListener true
                return@setOnTouchListener false
            }
            }


            return@setOnTouchListener false
            return@setOnTouchListener false
@@ -87,17 +92,18 @@ class ToggleRangeBehavior : Behavior {
        currentStatusText = control.getStatusText()
        currentStatusText = control.getStatusText()
        status.setText(currentStatusText)
        status.setText(currentStatusText)


        // ControlViewHolder sets a long click listener, but we want to handle touch in
        // here instead, otherwise we'll have state conflicts.
        cvh.layout.setOnLongClickListener(null)

        val ld = cvh.layout.getBackground() as LayerDrawable
        val ld = cvh.layout.getBackground() as LayerDrawable
        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
        clipLayer.setLevel(MIN_LEVEL)


        template = control.getControlTemplate() as ToggleRangeTemplate
        template = control.getControlTemplate() as ToggleRangeTemplate
        rangeTemplate = template.getRange()
        rangeTemplate = template.getRange()


        val checked = template.isChecked()
        val checked = template.isChecked()
        val currentRatio = rangeTemplate.getCurrentValue() /
        updateRange(rangeToLevelValue(rangeTemplate.currentValue), checked, /* isDragging */ false)
                (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
        updateRange(currentRatio, checked, /* isDragging */ false)


        cvh.applyRenderInfo(checked)
        cvh.applyRenderInfo(checked)


@@ -146,9 +152,8 @@ class ToggleRangeBehavior : Behavior {
                        } else {
                        } else {
                            val value = arguments.getFloat(
                            val value = arguments.getFloat(
                                AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)
                                AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)
                            val ratioDiff = (value - rangeTemplate.getCurrentValue()) /
                            val level = rangeToLevelValue(value - rangeTemplate.getCurrentValue())
                                (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
                            updateRange(level, template.isChecked(), /* isDragging */ false)
                            updateRange(ratioDiff, template.isChecked(), /* isDragging */ false)
                            endUpdateRange()
                            endUpdateRange()
                            true
                            true
                        }
                        }
@@ -172,13 +177,30 @@ class ToggleRangeBehavior : Behavior {
                .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat())
                .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat())
    }
    }


    fun updateRange(ratioDiff: Float, checked: Boolean, isDragging: Boolean) {
    fun updateRange(level: Int, checked: Boolean, isDragging: Boolean) {
        val changeAmount = if (checked) (MAX_LEVEL * ratioDiff).toInt() else MIN_LEVEL
        val newLevel = if (checked) Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, level)) else MIN_LEVEL
        val newLevel = Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, clipLayer.getLevel() + changeAmount))

        clipLayer.setLevel(newLevel)
        rangeAnimator?.cancel()
        if (isDragging) {
            clipLayer.level = newLevel
        } else {
            rangeAnimator = ValueAnimator.ofInt(cvh.clipLayer.level, newLevel).apply {
                addUpdateListener {
                    cvh.clipLayer.level = it.animatedValue as Int
                }
                addListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationEnd(animation: Animator?) {
                        rangeAnimator = null
                    }
                })
                duration = ControlViewHolder.STATE_ANIMATION_DURATION
                interpolator = Interpolators.CONTROL_STATE
                start()
            }
        }


        if (checked) {
        if (checked) {
            val newValue = levelToRangeValue(clipLayer.getLevel())
            val newValue = levelToRangeValue(newLevel)
            currentRangeValue = format(rangeTemplate.getFormatString().toString(),
            currentRangeValue = format(rangeTemplate.getFormatString().toString(),
                    DEFAULT_FORMAT, newValue)
                    DEFAULT_FORMAT, newValue)
            val text = if (isDragging) {
            val text = if (isDragging) {
@@ -206,9 +228,13 @@ class ToggleRangeBehavior : Behavior {
    }
    }


    private fun levelToRangeValue(i: Int): Float {
    private fun levelToRangeValue(i: Int): Float {
        val ratio = i.toFloat() / MAX_LEVEL
        return MathUtils.constrainedMap(rangeTemplate.minValue, rangeTemplate.maxValue,
        return rangeTemplate.getMinValue() +
                MIN_LEVEL.toFloat(), MAX_LEVEL.toFloat(), i.toFloat())
            (ratio * (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue()))
    }

    private fun rangeToLevelValue(i: Float): Int {
        return MathUtils.constrainedMap(MIN_LEVEL.toFloat(), MAX_LEVEL.toFloat(),
                rangeTemplate.minValue, rangeTemplate.maxValue, i).toInt()
    }
    }


    fun endUpdateRange() {
    fun endUpdateRange() {
@@ -247,6 +273,9 @@ class ToggleRangeBehavior : Behavior {
        }
        }


        override fun onLongPress(e: MotionEvent) {
        override fun onLongPress(e: MotionEvent) {
            if (isDragging) {
                return
            }
            ControlActionCoordinator.longPress(this@ToggleRangeBehavior.cvh)
            ControlActionCoordinator.longPress(this@ToggleRangeBehavior.cvh)
        }
        }


@@ -265,8 +294,10 @@ class ToggleRangeBehavior : Behavior {
                isDragging = true
                isDragging = true
            }
            }


            this@ToggleRangeBehavior.updateRange(-xDiff / v.getWidth(),
            val ratioDiff = -xDiff / v.width
                /* checked */ true, /* isDragging */ true)
            val changeAmount = ((MAX_LEVEL - MIN_LEVEL) * ratioDiff).toInt()
            this@ToggleRangeBehavior.updateRange(clipLayer.level + changeAmount,
                    checked = true, isDragging = true)
            return true
            return true
        }
        }


Loading