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

Commit fe3ef2de authored by Alejandro Nijamkin's avatar Alejandro Nijamkin Committed by Ale Nijamkin
Browse files

[flexiglass] Adds corner "ribbon".

Adds a visual indication to the UI that it's running with Flexglass on.
This should prove useful for debugging as it will let developers know
whether they're looking at Flexiglass UI or not.

To see it, the Flexiglass flags must be on and a system property named
flexi.ribbon must be set to true using:

$ adb shell setprop flexi.ribbon true

The ribbon is added as a generic composable such that it can be reused
by other future features, if needed.

Fix: 299340392
Test: manually verified that the ribbon is turned on and off with
Flexiglass feature flags + system property.
Test: see screenshot on the attached bug.

Change-Id: I54e03644fc46b69d7329ae6d3c32c6549ccf34c2
parent a4290cd6
Loading
Loading
Loading
Loading
+92 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 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.ribbon.ui.composable

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.layout
import com.android.compose.modifiers.thenIf
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.roundToInt
import kotlin.math.sin
import kotlin.math.tan

/**
 * Renders a "ribbon" at the bottom right corner of its container.
 *
 * The [content] is rendered leaning at an angle of [degrees] degrees (between `1` and `89`,
 * inclusive), with an alpha of [alpha] (between `0f` and `1f`, inclusive).
 *
 * The background color of the strip can be modified by passing a value to the [backgroundColor] or
 * `null` to remove the strip background.
 *
 * Note: this function assumes that it's been placed at the bottom right of its parent by its
 * caller. It's the caller's responsibility to meet that assumption by actually placing this
 * composable element at the bottom right.
 */
@Composable
fun BottomRightCornerRibbon(
    content: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    degrees: Int = 45,
    alpha: Float = 0.6f,
    backgroundColor: Color? = Color.Red,
) {
    check(degrees in 1..89)
    check(alpha in 0f..1f)

    val radians = degrees * (PI / 180)

    Box(
        content = { content() },
        modifier =
            modifier
                .graphicsLayer {
                    this.alpha = alpha

                    val w = size.width
                    val h = size.height

                    val sine = sin(radians).toFloat()
                    val cosine = cos(radians).toFloat()

                    translationX = (w - w * cosine + h * sine) / 2f
                    translationY = (h - w * sine + h * cosine) / 2f
                    rotationZ = 360f - degrees
                }
                .thenIf(backgroundColor != null) { Modifier.background(backgroundColor!!) }
                .layout { measurable, constraints ->
                    val placeable = measurable.measure(constraints)

                    val tangent = tan(radians)
                    val leftPadding = (placeable.measuredHeight / tangent).roundToInt()
                    val rightPadding = (placeable.measuredHeight * tangent).roundToInt()

                    layout(
                        width = placeable.measuredWidth + leftPadding + rightPadding,
                        height = placeable.measuredHeight,
                    ) {
                        placeable.place(leftPadding, 0)
                    }
                }
    )
}
+59 −36
Original line number Diff line number Diff line
@@ -18,14 +18,19 @@

package com.android.systemui.scene.ui.composable

import android.os.SystemProperties
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.motionEventSpy
import androidx.compose.ui.input.pointer.pointerInput
@@ -37,6 +42,7 @@ import com.android.compose.animation.scene.SceneTransitionLayoutState
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.UserAction as SceneTransitionUserAction
import com.android.compose.animation.scene.observableTransitionState
import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
@@ -75,12 +81,16 @@ fun SceneContainer(
    val currentDestinations: Map<UserAction, SceneModel> by
        currentScene.destinationScenes().collectAsState()
    val state = remember { SceneTransitionLayoutState(currentSceneKey.toTransitionSceneKey()) }
    val isRibbonEnabled = remember { SystemProperties.getBoolean("flexi.ribbon", false) }

    DisposableEffect(viewModel, state) {
        viewModel.setTransitionState(state.observableTransitionState().map { it.toModel() })
        onDispose { viewModel.setTransitionState(null) }
    }

    Box(
        modifier = Modifier.fillMaxSize(),
    ) {
        SceneTransitionLayout(
            currentScene = currentSceneKey.toTransitionSceneKey(),
            onChangeScene = viewModel::onSceneChanged,
@@ -123,6 +133,19 @@ fun SceneContainer(
                }
            }
        }

        if (isRibbonEnabled) {
            BottomRightCornerRibbon(
                content = {
                    Text(
                        text = "flexi\uD83E\uDD43",
                        color = Color.White,
                    )
                },
                modifier = Modifier.align(Alignment.BottomEnd),
            )
        }
    }
}

// TODO(b/293899074): remove this once we can use the one from SceneTransitionLayout.