diff options
| author | 2025-01-31 01:17:18 -0500 | |
|---|---|---|
| committer | 2025-02-10 19:28:07 -0500 | |
| commit | a2029c1924c0534b701af24407a6eb2f528f6c06 (patch) | |
| tree | bfc12f61fcdf4c8a94a759bbd049200140385922 | |
| parent | 2f131f5edaa690dd8f6659a94ac12292d005566b (diff) | |
[sb] Use BatteryCanvas composable in the battery chip
Adds a new battery composable event chip, and a new chip view that hosts
a single ComposeView so that we can reuse it in the future.
Test: manual
Bug: 391605373
Flag: com.android.settingslib.flags.new_status_bar_icons
Flag: com.android.systemui.status_bar_root_modernization
Change-Id: I7c5f8a3636f2464cdcf8b65c23b391de14e59275
8 files changed, 168 insertions, 23 deletions
diff --git a/packages/SystemUI/res/layout/battery_status_chip.xml b/packages/SystemUI/res/layout/battery_status_chip.xml index 74371839e247..7399651d4248 100644 --- a/packages/SystemUI/res/layout/battery_status_chip.xml +++ b/packages/SystemUI/res/layout/battery_status_chip.xml @@ -24,21 +24,13 @@ <LinearLayout android:id="@+id/rounded_container" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minHeight="@dimen/ongoing_appops_chip_height" - android:layout_gravity="center" - android:background="@drawable/statusbar_chip_bg" - android:clipToOutline="true" - android:gravity="center" - android:maxWidth="@dimen/ongoing_appops_chip_max_width" - android:minWidth="@dimen/ongoing_appops_chip_min_width"> + style="@style/StatusBar.EventChip"> <com.android.systemui.battery.BatteryMeterView android:id="@+id/battery_meter_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginHorizontal="10dp" /> + android:layout_marginHorizontal="@dimen/ongoing_appops_chip_content_horizontal_margin" /> </LinearLayout> </merge>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar_event_chip_compose.xml b/packages/SystemUI/res/layout/status_bar_event_chip_compose.xml new file mode 100644 index 000000000000..ff96ab15cd15 --- /dev/null +++ b/packages/SystemUI/res/layout/status_bar_event_chip_compose.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2025 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. + --> + +<merge xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center_vertical|end"> + + <LinearLayout + android:id="@+id/rounded_container" + style="@style/StatusBar.EventChip"> + + <!-- Stub for the composable --> + <androidx.compose.ui.platform.ComposeView + android:id="@+id/compose_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/ongoing_appops_chip_content_horizontal_margin" /> + + </LinearLayout> +</merge> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 648e4c2e3ac7..4b5c1baef0a5 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1254,6 +1254,8 @@ <dimen name="ongoing_appops_chip_side_padding">8dp</dimen> <!-- Margin between icons of Ongoing App Ops chip --> <dimen name="ongoing_appops_chip_icon_margin">4dp</dimen> + <!-- Side margins for the content of an appops chip --> + <dimen name="ongoing_appops_chip_content_horizontal_margin">10dp</dimen> <!-- Icon size of Ongoing App Ops chip --> <dimen name="ongoing_appops_chip_icon_size">16sp</dimen> <!-- Radius of Ongoing App Ops chip corners --> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 4961a7ece69a..8f808d389203 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -93,6 +93,19 @@ <item name="android:textColor">?android:attr/colorPrimary</item> </style> + <style name="StatusBar.EventChip"> + <item name="android:orientation">horizontal</item> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_gravity">center</item> + <item name="android:gravity">center</item> + <item name="android:clipToOutline">true</item> + <item name="android:background">@drawable/statusbar_chip_bg</item> + <item name="android:minHeight">@dimen/ongoing_appops_chip_height</item> + <item name="android:maxWidth">@dimen/ongoing_appops_chip_max_width</item> + <item name="android:minWidth">@dimen/ongoing_appops_chip_min_width</item> + </style> + <style name="Chipbar" /> <style name="Chipbar.Text" parent="@*android:style/TextAppearance.DeviceDefault.Notification.Title"> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt index a58ce4162ddc..02cec13d2ce8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt @@ -26,6 +26,7 @@ import com.android.settingslib.flags.Flags.newStatusBarIcons import com.android.systemui.battery.BatteryMeterView import com.android.systemui.battery.unified.BatteryColors import com.android.systemui.res.R +import com.android.systemui.statusbar.core.NewStatusBarIcons import com.android.systemui.statusbar.events.BackgroundAnimatableView class BatteryStatusChip @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : @@ -37,6 +38,8 @@ class BatteryStatusChip @JvmOverloads constructor(context: Context, attrs: Attri get() = batteryMeterView init { + NewStatusBarIcons.assertInLegacyMode() + inflate(context, R.layout.battery_status_chip, this) roundedContainer = requireViewById(R.id.rounded_container) batteryMeterView = requireViewById(R.id.battery_meter_view) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt index ea1d7820c79c..5887eb6ad865 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt @@ -25,6 +25,8 @@ import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.privacy.PrivacyItem import com.android.systemui.statusbar.BatteryStatusChip import com.android.systemui.statusbar.ConnectedDisplayChip +import com.android.systemui.statusbar.core.NewStatusBarIcons +import com.android.systemui.statusbar.events.ui.view.BatteryStatusEventComposeChip typealias ViewCreator = (context: Context) -> BackgroundAnimatableView @@ -53,9 +55,7 @@ interface StatusEvent { } } -class BGView( - context: Context -) : View(context), BackgroundAnimatableView { +class BGView(context: Context) : View(context), BackgroundAnimatableView { override val view: View get() = this @@ -65,9 +65,7 @@ class BGView( } @SuppressLint("AppCompatCustomView") -class BGImageView( - context: Context -) : ImageView(context), BackgroundAnimatableView { +class BGImageView(context: Context) : ImageView(context), BackgroundAnimatableView { override val view: View get() = this @@ -84,8 +82,10 @@ class BatteryEvent(@IntRange(from = 0, to = 100) val batteryLevel: Int) : Status override val shouldAnnounceAccessibilityEvent: Boolean = false override val viewCreator: ViewCreator = { context -> - BatteryStatusChip(context).apply { - setBatteryLevel(batteryLevel) + if (NewStatusBarIcons.isEnabled) { + BatteryStatusEventComposeChip(batteryLevel, context) + } else { + BatteryStatusChip(context).apply { setBatteryLevel(batteryLevel) } } } @@ -103,9 +103,7 @@ class ConnectedDisplayEvent : StatusEvent { override var contentDescription: String? = "" override val shouldAnnounceAccessibilityEvent: Boolean = true - override val viewCreator: ViewCreator = { context -> - ConnectedDisplayChip(context) - } + override val viewCreator: ViewCreator = { context -> ConnectedDisplayChip(context) } override fun toString(): String { return javaClass.simpleName @@ -134,7 +132,8 @@ open class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEven } override fun shouldUpdateFromEvent(other: StatusEvent?): Boolean { - return other is PrivacyEvent && (other.privacyItems != privacyItems || + return other is PrivacyEvent && + (other.privacyItems != privacyItems || other.contentDescription != contentDescription || (other.forceVisible && !forceVisible)) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt new file mode 100644 index 000000000000..a90e3ff4b2dc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2025 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.statusbar.events.ui.view + +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.FrameLayout +import android.widget.LinearLayout +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import com.android.systemui.res.R +import com.android.systemui.statusbar.core.NewStatusBarIcons +import com.android.systemui.statusbar.events.BackgroundAnimatableView +import com.android.systemui.statusbar.pipeline.battery.domain.interactor.BatteryInteractor +import com.android.systemui.statusbar.pipeline.battery.shared.ui.BatteryColors.LightThemeChargingColors +import com.android.systemui.statusbar.pipeline.battery.shared.ui.BatteryFrame +import com.android.systemui.statusbar.pipeline.battery.shared.ui.BatteryGlyph +import com.android.systemui.statusbar.pipeline.battery.ui.composable.BatteryCanvas +import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel +import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel.Companion.glyphRepresentation + +/** + * [StatusEvent] chip for the battery plugged in status event. Shows the current battery level and + * charging state in the status bar via the system event animation. + * + * This chip will fully replace [BatteryStatusChip] when [NewStatusBarIcons] is rolled out + */ +@SuppressLint("ViewConstructor") +class BatteryStatusEventComposeChip +@JvmOverloads +constructor(level: Int, context: Context, attrs: AttributeSet? = null) : + FrameLayout(context, attrs), BackgroundAnimatableView { + private val roundedContainer: LinearLayout + private val composeInner: ComposeView + override val contentView: View + get() = composeInner + + init { + NewStatusBarIcons.assertInNewMode() + + inflate(context, R.layout.status_bar_event_chip_compose, this) + roundedContainer = requireViewById(R.id.rounded_container) + composeInner = requireViewById(R.id.compose_view) + composeInner.apply { + setContent { + val isFull = BatteryInteractor.isBatteryFull(level) + BatteryCanvas( + modifier = + Modifier.width(BatteryViewModel.STATUS_BAR_BATTERY_WIDTH) + .height(BatteryViewModel.STATUS_BAR_BATTERY_HEIGHT), + path = BatteryFrame.pathSpec, + // TODO(b/394659067): get a content description for this chip + contentDescription = "", + innerWidth = BatteryFrame.innerWidth, + innerHeight = BatteryFrame.innerHeight, + // This event only happens when plugged in, so we always show it as charging + glyphs = + if (isFull) listOf(BatteryGlyph.Bolt) + else level.glyphRepresentation() + BatteryGlyph.Bolt, + level = level, + isFull = isFull, + colorsProvider = { LightThemeChargingColors }, + ) + } + } + updateResources() + } + + /** + * When animating as a chip in the status bar, we want to animate the width for the rounded + * container. We have to subtract our own top and left offset because the bounds come to us as + * absolute on-screen bounds. + */ + override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) { + roundedContainer.setLeftTopRightBottom(l - left, t - top, r - left, b - top) + } + + @SuppressLint("UseCompatLoadingForDrawables") + private fun updateResources() { + roundedContainer.background = mContext.getDrawable(R.drawable.statusbar_chip_bg) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt index 8fdb6ee57587..d53cbabb1d19 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt @@ -29,7 +29,7 @@ class BatteryInteractor @Inject constructor(repo: BatteryRepository) { val level = repo.level.filterNotNull() /** Whether the battery has been fully charged */ - val isFull = level.map { it >= 100 } + val isFull = level.map { isBatteryFull(it) } /** * For the sake of battery views, consider it to be "charging" if plugged in. This allows users @@ -82,6 +82,8 @@ class BatteryInteractor @Inject constructor(repo: BatteryRepository) { companion object { /** Level below which we consider to be critically low */ private const val CRITICAL_LEVEL = 20 + + fun isBatteryFull(level: Int) = level >= 100 } } |