1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package com.android.settings.fuelgauge;
17 
18 import android.content.Context;
19 import android.content.Intent;
20 import android.os.BatteryManager;
21 import android.os.PowerManager;
22 import android.util.Log;
23 
24 import androidx.annotation.VisibleForTesting;
25 import androidx.preference.PreferenceScreen;
26 
27 import com.android.settings.R;
28 import com.android.settings.core.BasePreferenceController;
29 import com.android.settings.core.PreferenceControllerMixin;
30 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
31 import com.android.settings.overlay.FeatureFactory;
32 import com.android.settingslib.Utils;
33 import com.android.settingslib.widget.UsageProgressBarPreference;
34 
35 /** Controller that update the battery header view */
36 public class BatteryHeaderPreferenceController extends BasePreferenceController
37         implements PreferenceControllerMixin, BatteryPreferenceController {
38     private static final String TAG = "BatteryHeaderPreferenceController";
39 
40     @VisibleForTesting static final String KEY_BATTERY_HEADER = "battery_header";
41     private static final int BATTERY_MAX_LEVEL = 100;
42 
43     @VisibleForTesting BatteryStatusFeatureProvider mBatteryStatusFeatureProvider;
44     @VisibleForTesting UsageProgressBarPreference mBatteryUsageProgressBarPref;
45 
46     private final PowerManager mPowerManager;
47     private final BatterySettingsFeatureProvider mBatterySettingsFeatureProvider;
48 
49     private BatteryTip mBatteryTip;
50 
BatteryHeaderPreferenceController(Context context, String key)51     public BatteryHeaderPreferenceController(Context context, String key) {
52         super(context, key);
53         mPowerManager = context.getSystemService(PowerManager.class);
54         mBatteryStatusFeatureProvider =
55                 FeatureFactory.getFeatureFactory().getBatteryStatusFeatureProvider();
56         mBatterySettingsFeatureProvider =
57                 FeatureFactory.getFeatureFactory().getBatterySettingsFeatureProvider();
58     }
59 
60     @Override
displayPreference(PreferenceScreen screen)61     public void displayPreference(PreferenceScreen screen) {
62         super.displayPreference(screen);
63         mBatteryUsageProgressBarPref = screen.findPreference(getPreferenceKey());
64         // Set up empty space text first to prevent layout flaky before info loaded.
65         mBatteryUsageProgressBarPref.setBottomSummary(" ");
66 
67         if (com.android.settings.Utils.isBatteryPresent(mContext)) {
68             quickUpdateHeaderPreference();
69         } else {
70             mBatteryUsageProgressBarPref.setVisible(false);
71         }
72     }
73 
74     @Override
getAvailabilityStatus()75     public int getAvailabilityStatus() {
76         return AVAILABLE_UNSEARCHABLE;
77     }
78 
generateLabel(BatteryInfo info)79     private CharSequence generateLabel(BatteryInfo info) {
80         if (Utils.containsIncompatibleChargers(mContext, TAG)) {
81             return mContext.getString(
82                     com.android.settingslib.R.string.battery_info_status_not_charging);
83         }
84         if (BatteryUtils.isBatteryDefenderOn(info)) {
85             return mContext.getString(
86                     com.android.settingslib.R.string.battery_info_status_charging_on_hold);
87         }
88         if (info.remainingLabel != null
89                 && mBatterySettingsFeatureProvider.isChargingOptimizationMode(mContext)) {
90             return info.remainingLabel;
91         }
92         if (info.remainingLabel == null
93                 || info.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
94             return info.statusLabel;
95         }
96         if (info.pluggedStatus == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
97             final CharSequence wirelessChargingLabel =
98                     mBatterySettingsFeatureProvider.getWirelessChargingLabel(mContext, info);
99             if (wirelessChargingLabel != null) {
100                 mBatteryUsageProgressBarPref.setBottomSummaryContentDescription(
101                         mBatterySettingsFeatureProvider
102                                 .getWirelessChargingContentDescription(mContext, info));
103                 return wirelessChargingLabel;
104             }
105         }
106         if (info.statusLabel != null && !info.discharging) {
107             // Charging state
108             if (com.android.settingslib.fuelgauge.BatteryUtils.isChargingStringV2Enabled()) {
109                 return info.isFastCharging
110                         ? mContext.getString(
111                                 R.string.battery_state_and_duration,
112                                 info.statusLabel,
113                                 info.remainingLabel)
114                         : info.remainingLabel;
115             }
116             return mContext.getString(
117                     R.string.battery_state_and_duration, info.statusLabel, info.remainingLabel);
118         } else if (mPowerManager.isPowerSaveMode()) {
119             // Power save mode is on
120             final String powerSaverOn =
121                     mContext.getString(R.string.battery_tip_early_heads_up_done_title);
122             return mContext.getString(
123                     R.string.battery_state_and_duration, powerSaverOn, info.remainingLabel);
124         } else if (mBatteryTip != null && mBatteryTip.getType() == BatteryTip.TipType.LOW_BATTERY) {
125             // Low battery state
126             final String lowBattery = mContext.getString(R.string.low_battery_summary);
127             return mContext.getString(
128                     R.string.battery_state_and_duration, lowBattery, info.remainingLabel);
129         } else {
130             // Discharging state
131             return info.remainingLabel;
132         }
133     }
134 
updateHeaderPreference(BatteryInfo info)135     public void updateHeaderPreference(BatteryInfo info) {
136         if (!mBatteryStatusFeatureProvider.triggerBatteryStatusUpdate(this, info)) {
137             mBatteryUsageProgressBarPref.setBottomSummary(generateLabel(info));
138         }
139 
140         mBatteryUsageProgressBarPref.setUsageSummary(
141                 formatBatteryPercentageText(info.batteryLevel));
142         mBatteryUsageProgressBarPref.setPercent(info.batteryLevel, BATTERY_MAX_LEVEL);
143     }
144 
145     /** Callback which receives text for the summary line. */
updateBatteryStatus(String label, BatteryInfo info)146     public void updateBatteryStatus(String label, BatteryInfo info) {
147         final CharSequence summary = label != null ? label : generateLabel(info);
148         mBatteryUsageProgressBarPref.setBottomSummary(summary);
149         Log.d(TAG, "updateBatteryStatus: " + label + " summary: " + summary);
150     }
151 
quickUpdateHeaderPreference()152     public void quickUpdateHeaderPreference() {
153         Intent batteryBroadcast =
154                 com.android.settingslib.fuelgauge.BatteryUtils.getBatteryIntent(mContext);
155         final int batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
156         final boolean discharging =
157                 batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) == 0;
158 
159         mBatteryUsageProgressBarPref.setUsageSummary(formatBatteryPercentageText(batteryLevel));
160         mBatteryUsageProgressBarPref.setPercent(batteryLevel, BATTERY_MAX_LEVEL);
161     }
162 
163     /** Update summary when battery tips changed. */
updateHeaderByBatteryTips(BatteryTip batteryTip, BatteryInfo batteryInfo)164     public void updateHeaderByBatteryTips(BatteryTip batteryTip, BatteryInfo batteryInfo) {
165         mBatteryTip = batteryTip;
166 
167         if (mBatteryTip != null && batteryInfo != null) {
168             updateHeaderPreference(batteryInfo);
169         }
170     }
171 
formatBatteryPercentageText(int batteryLevel)172     private CharSequence formatBatteryPercentageText(int batteryLevel) {
173         return com.android.settings.Utils.formatPercentage(batteryLevel);
174     }
175 }
176