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