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

Commit 5609c7fe authored by Pranav Vashi's avatar Pranav Vashi Committed by Michael Bestas
Browse files

SystemUI: Add customization to show battery percent



Change-Id: Ic14d30987eac9b412684db987698e224b93a8071
Signed-off-by: default avatarPranav Vashi <neobuddy89@gmail.com>
parent 7c39df7c
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.demomode.DemoMode
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.dump.DumpManager
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.ChipVisibilityListener
import com.android.systemui.qs.HeaderPrivacyIconsController
@@ -82,7 +83,7 @@ import com.android.systemui.statusbar.phone.domain.interactor.IsAreaDark
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
import com.android.systemui.statusbar.pipeline.battery.ui.composable.BatteryWithChargeStatus
import com.android.systemui.statusbar.pipeline.battery.ui.composable.BatteryWithEstimate
import com.android.systemui.statusbar.pipeline.battery.ui.composable.BatteryWithPercent
import com.android.systemui.statusbar.pipeline.battery.ui.composable.ShowPercentMode
import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryNextToPercentViewModel
import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel
@@ -122,7 +123,7 @@ constructor(
    private val shadeDisplaysRepositoryLazy: Lazy<ShadeDisplaysRepository>,
    private val variableDateViewControllerFactory: VariableDateViewController.Factory,
    @Named(SHADE_HEADER) private val batteryMeterViewController: BatteryMeterViewController,
    private val unifiedBatteryViewModelFactory: BatteryViewModel.AlwaysShowPercent.Factory,
    private val unifiedBatteryViewModelFactory: BatteryViewModel.BasedOnUserSetting.Factory,
    private val tandemBatteryViewModelFactory: BatteryNextToPercentViewModel.Factory,
    private val dumpManager: DumpManager,
    private val shadeCarrierGroupControllerBuilder: ShadeCarrierGroupController.Builder,
@@ -448,14 +449,14 @@ constructor(
                        id = R.id.battery_meter_composable_view
                        val showBatteryEstimate by showBatteryEstimate.collectAsStateWithLifecycle()
                        val dark = isSystemInDarkTheme()
                        BatteryWithEstimate(
                        val viewModel = rememberViewModel(traceName = "UnifiedBattery") {
                                unifiedBatteryViewModelFactory.create()
                            }
                        BatteryWithPercent(
                            modifier = Modifier.wrapContentSize(),
                            viewModelFactory = unifiedBatteryViewModelFactory,
                            viewModel = viewModel,
                            isDarkProvider = { IsAreaDark { dark } },
                            textColor =
                                if (notificationShadeBlur())
                                    Color(context.getColor(R.color.shade_header_text_color))
                                else Color.White,
                            showPercent = viewModel.isBatteryPercentSettingEnabled,
                            showEstimate = showBatteryEstimate,
                        )
                    }
+2 −2
Original line number Diff line number Diff line
@@ -143,7 +143,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
    private final TintedIconManager.Factory mTintedIconManagerFactory;
    private final BatteryMeterViewController mBatteryMeterViewController;
    private final BatteryNextToPercentViewModel.Factory mTandemBatteryViewModelFactory;
    private final BatteryViewModel.ShowPercentWhenChargingOrSetting.Factory mBatteryViewModel;
    private final BatteryViewModel.BasedOnUserSetting.Factory mBatteryViewModel;
    private final ShadeViewStateProvider mShadeViewStateProvider;
    private final KeyguardStateController mKeyguardStateController;
    private final KeyguardBypassController mKeyguardBypassController;
@@ -365,7 +365,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
            TintedIconManager.Factory tintedIconManagerFactory,
            BatteryMeterViewController batteryMeterViewController,
            BatteryNextToPercentViewModel.Factory tandemBatteryViewModelFactory,
            BatteryViewModel.ShowPercentWhenChargingOrSetting.Factory batteryViewModel,
            BatteryViewModel.BasedOnUserSetting.Factory batteryViewModel,
            ShadeViewStateProvider shadeViewStateProvider,
            KeyguardStateController keyguardStateController,
            KeyguardBypassController bypassController,
+52 −13
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@
package com.android.systemui.statusbar.pipeline.battery.data.repository

import android.content.Context
import android.provider.Settings
import android.database.ContentObserver
import android.os.Handler
import android.os.Looper
import android.os.UserHandle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -34,12 +37,15 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.suspendCancellableCoroutine
import lineageos.providers.LineageSettings

/** Repository-style state for battery information. */
interface BatteryRepository {
@@ -64,10 +70,16 @@ interface BatteryRepository {
    val isStateUnknown: Flow<Boolean>

    /**
     * [Settings.System.SHOW_BATTERY_PERCENT]. A user setting to indicate whether we should show the
     * battery percentage in the home screen status bar
     * [LineageSettings.System.STATUS_BAR_SHOW_BATTERY_PERCENT]. A user setting to indicate whether
     * we should show the battery percentage in the home screen status bar
     */
    val isShowBatteryPercentSettingEnabled: StateFlow<Boolean>
    val showBatteryPercentMode: StateFlow<Int>

    companion object {
        const val SHOW_PERCENT_HIDDEN = 0
        const val SHOW_PERCENT_INSIDE = 1
        const val SHOW_PERCENT_NEXT_TO = 2
    }

    /**
     * If available, this flow yields a string that describes the approximate time remaining for the
@@ -153,16 +165,43 @@ constructor(

    override val isStateUnknown = batteryState.map { it.isStateUnknown }

    override val isShowBatteryPercentSettingEnabled = run {
        val default =
            context.resources.getBoolean(
                com.android.internal.R.bool.config_defaultBatteryPercentageSetting
    override val showBatteryPercentMode =
        callbackFlow {
                val resolver = context.contentResolver
                val uri =
                    LineageSettings.System.getUriFor(
                        LineageSettings.System.STATUS_BAR_SHOW_BATTERY_PERCENT
                    )
        settingsRepository
            .boolSetting(name = Settings.System.SHOW_BATTERY_PERCENT, defaultValue = default)
            .flowOn(bgDispatcher)
            .stateIn(scope, SharingStarted.Lazily, default)

                fun readMode(): Int {
                    return LineageSettings.System.getIntForUser(
                        resolver, LineageSettings.System.STATUS_BAR_SHOW_BATTERY_PERCENT,
                        BatteryRepository.SHOW_PERCENT_HIDDEN, UserHandle.USER_CURRENT
                    )
                }

                val observer =
                    object : ContentObserver(Handler(Looper.getMainLooper())) {
                        override fun onChange(selfChange: Boolean) {
                            trySend(readMode())
                        }
                    }

                resolver.registerContentObserver(uri, /* notifyForDescendants = */ false,
                    observer, UserHandle.USER_ALL)

                // Emit current value immediately
                trySend(readMode())

                awaitClose { resolver.unregisterContentObserver(observer) }
            }
            .distinctUntilChanged()
            .flowOn(bgDispatcher)
            .stateIn(
                scope = scope,
                started = SharingStarted.Lazily,
                initialValue = BatteryRepository.SHOW_PERCENT_HIDDEN
            )

    /** Get and re-fetch the estimate every 2 minutes while active */
    private val estimate: Flow<String?> = flow {
+23 −3
Original line number Diff line number Diff line
@@ -17,15 +17,23 @@
package com.android.systemui.statusbar.pipeline.battery.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.statusbar.pipeline.battery.data.repository.BatteryRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn

@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class BatteryInteractor @Inject constructor(repo: BatteryRepository) {
class BatteryInteractor @Inject constructor(
    private val repo: BatteryRepository,
    @Background private val appScope: CoroutineScope,
) {
    /** The current level in the range of [0-100], or null if we don't know the level yet */
    val level =
        combine(repo.isStateUnknown, repo.level) { unknown, level ->
@@ -66,8 +74,20 @@ class BatteryInteractor @Inject constructor(repo: BatteryRepository) {
    /** @see [BatteryRepository.isPowerSaveEnabled] */
    val powerSave = repo.isPowerSaveEnabled

    /** @see [BatteryRepository.isShowBatteryPercentSettingEnabled] */
    val isBatteryPercentSettingEnabled = repo.isShowBatteryPercentSettingEnabled
    /** @see [BatteryRepository.showBatteryPercentMode] */
    val showBatteryPercentMode: StateFlow<Int> = repo.showBatteryPercentMode

    // Mode == 1
    val showPercentInsideIcon: StateFlow<Boolean> =
        repo.showBatteryPercentMode
            .map { it == BatteryRepository.SHOW_PERCENT_INSIDE }
            .stateIn(appScope, SharingStarted.Lazily, false)

    // Mode == 2
    val showPercentNextToIcon: StateFlow<Boolean> =
        repo.showBatteryPercentMode
            .map { it == BatteryRepository.SHOW_PERCENT_NEXT_TO }
            .stateIn(appScope, SharingStarted.Lazily, false)

    /**
     * The battery attribution (@see [BatteryAttributionModel]) describes the attribution that best
+4 −7
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.statusbar.pipeline.battery.ui.binder

import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
@@ -32,9 +31,8 @@ import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.phone.domain.interactor.IsAreaDark
import com.android.systemui.statusbar.pipeline.battery.ui.composable.UnifiedBattery
import com.android.systemui.statusbar.pipeline.battery.ui.composable.BatteryWithPercent
import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel
import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel.Companion.STATUS_BAR_BATTERY_HEIGHT
import kotlinx.coroutines.flow.Flow

/** In cases where the battery needs to be bound to an existing android view */
@@ -61,15 +59,14 @@ object UnifiedBatteryViewBinder {
                                }
                            val isDark by
                                isAreaDark.collectAsStateWithLifecycle(IsAreaDark { true })
                            val height =
                                with(LocalDensity.current) { STATUS_BAR_BATTERY_HEIGHT.toDp() }
                            UnifiedBattery(
                            BatteryWithPercent(
                                modifier =
                                    Modifier.height(height)
                                    Modifier
                                        .wrapContentWidth()
                                        .sysuiResTag(BatteryViewModel.TEST_TAG),
                                viewModel = viewModel,
                                isDarkProvider = { isDark },
                                showPercent = viewModel.isBatteryPercentSettingEnabled,
                            )
                        }
                    }
Loading