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 */ 17 18 package com.android.settings.fuelgauge; 19 20 import android.app.Activity; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.icu.text.NumberFormat; 25 import android.os.BatteryManager; 26 import android.os.PowerManager; 27 import android.text.TextUtils; 28 29 import androidx.annotation.VisibleForTesting; 30 import androidx.preference.PreferenceFragmentCompat; 31 import androidx.preference.PreferenceScreen; 32 33 import com.android.settings.R; 34 import com.android.settings.core.BasePreferenceController; 35 import com.android.settings.core.PreferenceControllerMixin; 36 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; 37 import com.android.settings.overlay.FeatureFactory; 38 import com.android.settings.widget.EntityHeaderController; 39 import com.android.settingslib.Utils; 40 import com.android.settingslib.core.lifecycle.Lifecycle; 41 import com.android.settingslib.core.lifecycle.LifecycleObserver; 42 import com.android.settingslib.core.lifecycle.events.OnStart; 43 import com.android.settingslib.widget.UsageProgressBarPreference; 44 45 /** 46 * Controller that update the battery header view 47 */ 48 public class BatteryHeaderPreferenceController extends BasePreferenceController 49 implements PreferenceControllerMixin, LifecycleObserver, OnStart, 50 BatteryPreferenceController { 51 @VisibleForTesting 52 static final String KEY_BATTERY_HEADER = "battery_header"; 53 private static final int BATTERY_MAX_LEVEL = 100; 54 55 @VisibleForTesting 56 BatteryStatusFeatureProvider mBatteryStatusFeatureProvider; 57 @VisibleForTesting 58 UsageProgressBarPreference mBatteryUsageProgressBarPref; 59 60 private Activity mActivity; 61 private PreferenceFragmentCompat mHost; 62 private Lifecycle mLifecycle; 63 private BatteryTip mBatteryTip; 64 private final PowerManager mPowerManager; 65 BatteryHeaderPreferenceController(Context context, String key)66 public BatteryHeaderPreferenceController(Context context, String key) { 67 super(context, key); 68 mPowerManager = context.getSystemService(PowerManager.class); 69 mBatteryStatusFeatureProvider = FeatureFactory.getFactory(context) 70 .getBatteryStatusFeatureProvider(context); 71 } 72 setActivity(Activity activity)73 public void setActivity(Activity activity) { 74 mActivity = activity; 75 } 76 setFragment(PreferenceFragmentCompat fragment)77 public void setFragment(PreferenceFragmentCompat fragment) { 78 mHost = fragment; 79 } 80 setLifecycle(Lifecycle lifecycle)81 public void setLifecycle(Lifecycle lifecycle) { 82 mLifecycle = lifecycle; 83 } 84 85 @Override displayPreference(PreferenceScreen screen)86 public void displayPreference(PreferenceScreen screen) { 87 super.displayPreference(screen); 88 mBatteryUsageProgressBarPref = screen.findPreference(getPreferenceKey()); 89 //Set up loading text first to prevent layout flaky before info loaded. 90 mBatteryUsageProgressBarPref.setBottomSummary( 91 mContext.getString(R.string.settings_license_activity_loading)); 92 93 if (com.android.settings.Utils.isBatteryPresent(mContext)) { 94 quickUpdateHeaderPreference(); 95 } else { 96 mBatteryUsageProgressBarPref.setVisible(false); 97 } 98 } 99 100 @Override getAvailabilityStatus()101 public int getAvailabilityStatus() { 102 return AVAILABLE_UNSEARCHABLE; 103 } 104 105 @Override onStart()106 public void onStart() { 107 EntityHeaderController.newInstance(mActivity, mHost, null /* header view */) 108 .setRecyclerView(mHost.getListView(), mLifecycle); 109 } 110 generateLabel(BatteryInfo info)111 private CharSequence generateLabel(BatteryInfo info) { 112 if (BatteryUtils.isBatteryDefenderOn(info)) { 113 return null; 114 } else if (info.remainingLabel == null 115 || info.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING) { 116 // Present status only if no remaining time or status anomalous 117 return info.statusLabel; 118 } else if (info.statusLabel != null && !info.discharging) { 119 // Charging state 120 return mContext.getString( 121 R.string.battery_state_and_duration, info.statusLabel, info.remainingLabel); 122 } else if (mPowerManager.isPowerSaveMode()) { 123 // Power save mode is on 124 final String powerSaverOn = mContext.getString( 125 R.string.battery_tip_early_heads_up_done_title); 126 return mContext.getString( 127 R.string.battery_state_and_duration, powerSaverOn, info.remainingLabel); 128 } else if (mBatteryTip != null 129 && mBatteryTip.getType() == BatteryTip.TipType.LOW_BATTERY) { 130 // Low battery state 131 final String lowBattery = mContext.getString(R.string.low_battery_summary); 132 return mContext.getString( 133 R.string.battery_state_and_duration, lowBattery, info.remainingLabel); 134 } else { 135 // Discharging state 136 return info.remainingLabel; 137 } 138 } 139 updateHeaderPreference(BatteryInfo info)140 public void updateHeaderPreference(BatteryInfo info) { 141 if (!mBatteryStatusFeatureProvider.triggerBatteryStatusUpdate(this, info)) { 142 mBatteryUsageProgressBarPref.setBottomSummary(generateLabel(info)); 143 } 144 145 mBatteryUsageProgressBarPref.setUsageSummary( 146 formatBatteryPercentageText(info.batteryLevel)); 147 mBatteryUsageProgressBarPref.setPercent(info.batteryLevel, BATTERY_MAX_LEVEL); 148 } 149 150 /** 151 * Callback which receives text for the summary line. 152 */ updateBatteryStatus(String label, BatteryInfo info)153 public void updateBatteryStatus(String label, BatteryInfo info) { 154 mBatteryUsageProgressBarPref.setBottomSummary(label != null ? label : generateLabel(info)); 155 } 156 quickUpdateHeaderPreference()157 public void quickUpdateHeaderPreference() { 158 Intent batteryBroadcast = mContext.registerReceiver(null, 159 new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 160 final int batteryLevel = Utils.getBatteryLevel(batteryBroadcast); 161 final boolean discharging = 162 batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) == 0; 163 164 mBatteryUsageProgressBarPref.setUsageSummary(formatBatteryPercentageText(batteryLevel)); 165 mBatteryUsageProgressBarPref.setPercent(batteryLevel, BATTERY_MAX_LEVEL); 166 } 167 168 /** 169 * Update summary when battery tips changed. 170 */ updateHeaderByBatteryTips(BatteryTip batteryTip, BatteryInfo batteryInfo)171 public void updateHeaderByBatteryTips(BatteryTip batteryTip, BatteryInfo batteryInfo) { 172 mBatteryTip = batteryTip; 173 174 if (mBatteryTip != null && batteryInfo != null) { 175 updateHeaderPreference(batteryInfo); 176 } 177 } 178 formatBatteryPercentageText(int batteryLevel)179 private CharSequence formatBatteryPercentageText(int batteryLevel) { 180 return TextUtils.expandTemplate(mContext.getText(R.string.battery_header_title_alternate), 181 NumberFormat.getIntegerInstance().format(batteryLevel)); 182 } 183 } 184