• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.pipeline.battery.domain.interactor
18 
19 import com.android.systemui.dagger.SysUISingleton
20 import com.android.systemui.statusbar.pipeline.battery.data.repository.BatteryRepository
21 import javax.inject.Inject
22 import kotlinx.coroutines.flow.combine
23 import kotlinx.coroutines.flow.filterNotNull
24 import kotlinx.coroutines.flow.map
25 
26 @SysUISingleton
27 class BatteryInteractor @Inject constructor(repo: BatteryRepository) {
28     /** The current level in the range of [0-100] */
29     val level = repo.level.filterNotNull()
30 
31     /** Whether the battery has been fully charged */
32     val isFull = level.map { isBatteryFull(it) }
33 
34     /**
35      * For the sake of battery views, consider it to be "charging" if plugged in. This allows users
36      * to easily confirm that the device is properly plugged in, even if its' technically not
37      * charging due to issues with the source.
38      */
39     val isCharging = repo.isPluggedIn
40 
41     /**
42      * The critical level (see [CRITICAL_LEVEL]) defines the level below which we might want to
43      * display an error UI. E.g., show the battery as red.
44      */
45     val isCritical = level.map { it <= CRITICAL_LEVEL }
46 
47     /** @see [BatteryRepository.isStateUnknown] for docs. The battery cannot be detected */
48     val isStateUnknown = repo.isStateUnknown
49 
50     /** @see [BatteryRepository.isBatteryDefenderEnabled] */
51     val isBatteryDefenderEnabled = repo.isBatteryDefenderEnabled
52 
53     /** @see [BatteryRepository.isPowerSaveEnabled] */
54     val powerSave = repo.isPowerSaveEnabled
55 
56     /** @see [BatteryRepository.isShowBatteryPercentSettingEnabled] */
57     val isBatteryPercentSettingEnabled = repo.isShowBatteryPercentSettingEnabled
58 
59     /**
60      * The battery attribution (@see [BatteryAttributionModel]) describes the attribution that best
61      * represents the current battery charging state. If charging, the attribution is
62      * [BatteryAttributionModel.Charging], etc.
63      *
64      * This flow can be used to canonically describe the battery state charging state.
65      */
66     val batteryAttributionType =
67         combine(isCharging, powerSave, isBatteryDefenderEnabled) { charging, powerSave, defend ->
68             if (powerSave) {
69                 BatteryAttributionModel.PowerSave
70             } else if (defend) {
71                 BatteryAttributionModel.Defend
72             } else if (charging) {
73                 BatteryAttributionModel.Charging
74             } else {
75                 null
76             }
77         }
78 
79     /** @see [BatteryRepository.batteryTimeRemainingEstimate] */
80     val batteryTimeRemainingEstimate = repo.batteryTimeRemainingEstimate
81 
82     companion object {
83         /** Level below which we consider to be critically low */
84         private const val CRITICAL_LEVEL = 20
85 
86         fun isBatteryFull(level: Int) = level >= 100
87     }
88 }
89 
90 /** The charging state, and therefore attribution for the battery */
91 enum class BatteryAttributionModel {
92     Defend,
93     PowerSave,
94     Charging,
95 }
96