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

Commit 0a4e23ae authored by Christian Göllner's avatar Christian Göllner Committed by Automerger Merge Worker
Browse files

Merge "Implementing keyboard indicator dialog" into tm-qpr-dev am: 19f6c52f

parents 83c4acd0 19f6c52f
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
<vector android:height="11dp" android:viewportHeight="12"
    android:viewportWidth="22" android:width="20.166666dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <group>
        <clip-path android:pathData="M0,0.5h22v11h-22z"/>
        <path android:fillColor="#231F20" android:pathData="M6.397,9.908H0V11.5H6.397V9.908Z"/>
        <path android:fillColor="#231F20" android:pathData="M14.199,9.908H7.801V11.5H14.199V9.908Z"/>
        <path android:fillColor="#231F20" android:pathData="M11.858,0.5H10.142V6.434H11.858V0.5Z"/>
        <path android:fillColor="#231F20" android:pathData="M8.348,7.129L3.885,2.975L3.823,2.932L2.668,4.003L2.621,4.046L7.084,8.2L7.146,8.243L8.301,7.172L8.348,7.129Z"/>
        <path android:fillColor="#231F20" android:pathData="M18.224,2.975L18.177,2.932L13.653,7.129L14.807,8.2L14.854,8.243L19.379,4.046L18.224,2.975Z"/>
        <path android:fillColor="#231F20" android:pathData="M22,9.908H15.603V11.5H22V9.908Z"/>
    </group>
</vector>
+5 −0
Original line number Diff line number Diff line
@@ -207,6 +207,11 @@
    <color name="control_thumbnail_shadow_color">@*android:color/black</color>
    <color name="controls_task_view_bg">#CC191C1D</color>

    <!-- Keyboard backlight indicator-->
    <color name="backlight_indicator_step_filled">#F6E388</color>
    <color name="backlight_indicator_step_empty">#494740</color>
    <color name="backlight_indicator_background">#32302A</color>

    <!-- Docked misalignment message -->
    <color name="misalignment_text_color">#F28B82</color>

+13 −0
Original line number Diff line number Diff line
@@ -1653,6 +1653,19 @@
    <dimen name="media_output_broadcast_info_summary_height">20dp</dimen>
    <dimen name="media_output_broadcast_info_edit">18dp</dimen>

    <!-- Keyboard backlight indicator-->
    <dimen name="backlight_indicator_root_corner_radius">48dp</dimen>
    <dimen name="backlight_indicator_root_vertical_padding">8dp</dimen>
    <dimen name="backlight_indicator_root_horizontal_padding">4dp</dimen>
    <dimen name="backlight_indicator_icon_width">22dp</dimen>
    <dimen name="backlight_indicator_icon_height">11dp</dimen>
    <dimen name="backlight_indicator_icon_left_margin">2dp</dimen>
    <dimen name="backlight_indicator_step_width">52dp</dimen>
    <dimen name="backlight_indicator_step_height">40dp</dimen>
    <dimen name="backlight_indicator_step_horizontal_margin">4dp</dimen>
    <dimen name="backlight_indicator_step_small_radius">4dp</dimen>
    <dimen name="backlight_indicator_step_large_radius">48dp</dimen>

    <!-- Broadcast dialog -->
    <dimen name="broadcast_dialog_title_img_margin_top">18dp</dimen>
    <dimen name="broadcast_dialog_title_text_size">24sp</dimen>
+9 −2
Original line number Diff line number Diff line
@@ -46,8 +46,15 @@ constructor(
            viewModel.dialogContent.collect { dialogViewModel ->
                if (dialogViewModel != null) {
                    if (dialog == null) {
                        dialog = KeyboardBacklightDialog(context, dialogViewModel)
                        // pass viewModel and show
                        dialog =
                            KeyboardBacklightDialog(
                                context,
                                initialCurrentLevel = dialogViewModel.currentValue,
                                initialMaxLevel = dialogViewModel.maxValue
                            )
                        dialog?.show()
                    } else {
                        dialog?.updateState(dialogViewModel.currentValue, dialogViewModel.maxValue)
                    }
                } else {
                    dialog?.dismiss()
+248 −4
Original line number Diff line number Diff line
@@ -17,16 +17,260 @@

package com.android.systemui.keyboard.backlight.ui.view

import android.annotation.ColorInt
import android.app.Dialog
import android.content.Context
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.os.Bundle
import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogContentViewModel
import android.view.Gravity
import android.view.Window
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.LinearLayout.LayoutParams
import android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
import com.android.systemui.R
import com.android.systemui.util.children

class KeyboardBacklightDialog(context: Context, val viewModel: BacklightDialogContentViewModel) :
    Dialog(context) {
class KeyboardBacklightDialog(
    context: Context,
    initialCurrentLevel: Int,
    initialMaxLevel: Int,
) : Dialog(context) {

    private data class RootProperties(
        val cornerRadius: Float,
        val verticalPadding: Int,
        val horizontalPadding: Int,
    )

    private data class BacklightIconProperties(
        val width: Int,
        val height: Int,
        val leftMargin: Int,
    )

    private data class StepViewProperties(
        val width: Int,
        val height: Int,
        val horizontalMargin: Int,
        val smallRadius: Float,
        val largeRadius: Float,
    )

    private var currentLevel: Int = 0
    private var maxLevel: Int = 0

    private lateinit var rootView: LinearLayout

    private var dialogBottomMargin = 208
    private lateinit var rootProperties: RootProperties
    private lateinit var iconProperties: BacklightIconProperties
    private lateinit var stepProperties: StepViewProperties
    @ColorInt var filledRectangleColor: Int = 0
    @ColorInt var emptyRectangleColor: Int = 0
    @ColorInt var backgroundColor: Int = 0

    init {
        currentLevel = initialCurrentLevel
        maxLevel = initialMaxLevel
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        setUpWindowProperties(this)
        setWindowTitle()
        updateResources()
        rootView = buildRootView()
        setContentView(rootView)
        super.onCreate(savedInstanceState)
        // TODO(b/268650355) Implement the dialog
        updateState(currentLevel, maxLevel, forceRefresh = true)
    }

    private fun updateResources() {
        context.resources.apply {
            filledRectangleColor = getColor(R.color.backlight_indicator_step_filled)
            emptyRectangleColor = getColor(R.color.backlight_indicator_step_empty)
            backgroundColor = getColor(R.color.backlight_indicator_background)
            rootProperties =
                RootProperties(
                    cornerRadius =
                        getDimensionPixelSize(R.dimen.backlight_indicator_root_corner_radius)
                            .toFloat(),
                    verticalPadding =
                        getDimensionPixelSize(R.dimen.backlight_indicator_root_vertical_padding),
                    horizontalPadding =
                        getDimensionPixelSize(R.dimen.backlight_indicator_root_horizontal_padding)
                )
            iconProperties =
                BacklightIconProperties(
                    width = getDimensionPixelSize(R.dimen.backlight_indicator_icon_width),
                    height = getDimensionPixelSize(R.dimen.backlight_indicator_icon_height),
                    leftMargin =
                        getDimensionPixelSize(R.dimen.backlight_indicator_icon_left_margin),
                )
            stepProperties =
                StepViewProperties(
                    width = getDimensionPixelSize(R.dimen.backlight_indicator_step_width),
                    height = getDimensionPixelSize(R.dimen.backlight_indicator_step_height),
                    horizontalMargin =
                        getDimensionPixelSize(R.dimen.backlight_indicator_step_horizontal_margin),
                    smallRadius =
                        getDimensionPixelSize(R.dimen.backlight_indicator_step_small_radius)
                            .toFloat(),
                    largeRadius =
                        getDimensionPixelSize(R.dimen.backlight_indicator_step_large_radius)
                            .toFloat(),
                )
        }
    }

    fun updateState(current: Int, max: Int, forceRefresh: Boolean = false) {
        if (maxLevel != max || forceRefresh) {
            maxLevel = max
            rootView.removeAllViews()
            buildStepViews().forEach { rootView.addView(it) }
        }
        currentLevel = current
        updateLevel()
    }

    private fun updateLevel() {
        rootView.children.forEachIndexed(
            action = { index, v ->
                val drawable = v.background as ShapeDrawable
                if (index <= currentLevel) {
                    updateColor(drawable, filledRectangleColor)
                } else {
                    updateColor(drawable, emptyRectangleColor)
                }
            }
        )
    }

    private fun updateColor(drawable: ShapeDrawable, @ColorInt color: Int) {
        if (drawable.paint.color != color) {
            drawable.paint.color = color
            drawable.invalidateSelf()
        }
    }

    private fun buildRootView(): LinearLayout {
        val linearLayout =
            LinearLayout(context).apply {
                orientation = LinearLayout.HORIZONTAL
                layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
                setPadding(
                    /* left= */ rootProperties.horizontalPadding,
                    /* top= */ rootProperties.verticalPadding,
                    /* right= */ rootProperties.horizontalPadding,
                    /* bottom= */ rootProperties.verticalPadding
                )
            }
        val drawable =
            ShapeDrawable(
                RoundRectShape(
                    /* outerRadii= */ FloatArray(8) { rootProperties.cornerRadius },
                    /* inset= */ null,
                    /* innerRadii= */ null
                )
            )
        drawable.paint.color = backgroundColor
        linearLayout.background = drawable
        return linearLayout
    }

    private fun buildStepViews(): List<FrameLayout> {
        val stepViews = (0..maxLevel).map { i -> createStepViewAt(i) }
        stepViews[0].addView(createBacklightIconView())
        return stepViews
    }

    private fun createStepViewAt(i: Int): FrameLayout {
        return FrameLayout(context).apply {
            layoutParams =
                FrameLayout.LayoutParams(stepProperties.width, stepProperties.height).apply {
                    setMargins(
                        /* left= */ stepProperties.horizontalMargin,
                        /* top= */ 0,
                        /* right= */ stepProperties.horizontalMargin,
                        /* bottom= */ 0
                    )
                }
            val drawable =
                ShapeDrawable(
                    RoundRectShape(
                        /* outerRadii= */ radiiForIndex(i, maxLevel),
                        /* inset= */ null,
                        /* innerRadii= */ null
                    )
                )
            drawable.paint.color = emptyRectangleColor
            background = drawable
        }
    }

    private fun createBacklightIconView(): ImageView {
        return ImageView(context).apply {
            setImageResource(R.drawable.ic_keyboard_backlight)
            layoutParams =
                FrameLayout.LayoutParams(iconProperties.width, iconProperties.height).apply {
                    gravity = Gravity.CENTER
                    leftMargin = iconProperties.leftMargin
                }
        }
    }

    private fun setWindowTitle() {
        val attrs = window.attributes
        // TODO(b/271796169): check if title needs to be a translatable resource.
        attrs.title = "KeyboardBacklightDialog"
        attrs?.y = dialogBottomMargin
        window.attributes = attrs
    }

    private fun setUpWindowProperties(dialog: Dialog) {
        val window = dialog.window
        window.requestFeature(Window.FEATURE_NO_TITLE) // otherwise fails while creating actionBar
        window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
        window.addFlags(
            WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM or
                WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
        )
        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
        window.setBackgroundDrawableResource(android.R.color.transparent)
        window.setGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
        setCanceledOnTouchOutside(true)
    }

    private fun radiiForIndex(i: Int, last: Int): FloatArray {
        val smallRadius = stepProperties.smallRadius
        val largeRadius = stepProperties.largeRadius
        return when (i) {
            0 -> // left radii bigger
            floatArrayOf(
                    largeRadius,
                    largeRadius,
                    smallRadius,
                    smallRadius,
                    smallRadius,
                    smallRadius,
                    largeRadius,
                    largeRadius
                )
            last -> // right radii bigger
            floatArrayOf(
                    smallRadius,
                    smallRadius,
                    largeRadius,
                    largeRadius,
                    largeRadius,
                    largeRadius,
                    smallRadius,
                    smallRadius
                )
            else -> FloatArray(8) { smallRadius } // all radii equal
        }
    }
}