1 /* 2 * Copyright (C) 2021 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 package com.android.systemui.battery; 17 18 import static android.provider.Settings.System.SHOW_BATTERY_PERCENT; 19 20 import android.content.ContentResolver; 21 import android.content.Context; 22 import android.database.ContentObserver; 23 import android.net.Uri; 24 import android.os.Handler; 25 import android.os.HandlerExecutor; 26 import android.provider.Settings; 27 import android.text.TextUtils; 28 import android.util.ArraySet; 29 import android.view.View; 30 31 import androidx.annotation.NonNull; 32 33 import com.android.systemui.dagger.SysUISingleton; 34 import com.android.systemui.dagger.qualifiers.Main; 35 import com.android.systemui.flags.FeatureFlags; 36 import com.android.systemui.flags.Flags; 37 import com.android.systemui.settings.UserTracker; 38 import com.android.systemui.statusbar.phone.StatusBarLocation; 39 import com.android.systemui.statusbar.phone.ui.StatusBarIconController; 40 import com.android.systemui.statusbar.policy.BatteryController; 41 import com.android.systemui.statusbar.policy.ConfigurationController; 42 import com.android.systemui.tuner.TunerService; 43 import com.android.systemui.util.ViewController; 44 45 import java.io.PrintWriter; 46 47 import javax.inject.Inject; 48 49 /** 50 * Controller for {@link BatteryMeterView}. 51 * @deprecated once [NewStatusBarIcons] is rolled out, this class is no longer needed 52 */ 53 public class BatteryMeterViewController extends ViewController<BatteryMeterView> { 54 private final ConfigurationController mConfigurationController; 55 private final TunerService mTunerService; 56 private final Handler mMainHandler; 57 private final ContentResolver mContentResolver; 58 private final FeatureFlags mFeatureFlags; 59 private final BatteryController mBatteryController; 60 61 private final String mSlotBattery; 62 private final SettingObserver mSettingObserver; 63 private final UserTracker mUserTracker; 64 private final StatusBarLocation mLocation; 65 66 private final ConfigurationController.ConfigurationListener mConfigurationListener = 67 new ConfigurationController.ConfigurationListener() { 68 @Override 69 public void onDensityOrFontScaleChanged() { 70 mView.scaleBatteryMeterViews(); 71 } 72 }; 73 74 private final TunerService.Tunable mTunable = new TunerService.Tunable() { 75 @Override 76 public void onTuningChanged(String key, String newValue) { 77 if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) { 78 ArraySet<String> icons = StatusBarIconController.getIconHideList( 79 getContext(), newValue); 80 mView.setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE); 81 } 82 } 83 }; 84 85 private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback = 86 new BatteryController.BatteryStateChangeCallback() { 87 @Override 88 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { 89 mView.onBatteryLevelChanged(level, pluggedIn); 90 } 91 92 @Override 93 public void onPowerSaveChanged(boolean isPowerSave) { 94 mView.onPowerSaveChanged(isPowerSave); 95 } 96 97 @Override 98 public void onBatteryUnknownStateChanged(boolean isUnknown) { 99 mView.onBatteryUnknownStateChanged(isUnknown); 100 } 101 102 @Override 103 public void onIsBatteryDefenderChanged(boolean isBatteryDefender) { 104 mView.onIsBatteryDefenderChanged(isBatteryDefender); 105 } 106 107 @Override 108 public void onIsIncompatibleChargingChanged(boolean isIncompatibleCharging) { 109 if (mFeatureFlags.isEnabled(Flags.INCOMPATIBLE_CHARGING_BATTERY_ICON)) { 110 mView.onIsIncompatibleChargingChanged(isIncompatibleCharging); 111 } 112 } 113 114 @Override 115 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 116 pw.print(super.toString()); 117 pw.println(" location=" + mLocation); 118 mView.dump(pw, args); 119 } 120 }; 121 122 private final UserTracker.Callback mUserChangedCallback = 123 new UserTracker.Callback() { 124 @Override 125 public void onUserChanged(int newUser, @NonNull Context userContext) { 126 mContentResolver.unregisterContentObserver(mSettingObserver); 127 registerShowBatteryPercentObserver(newUser); 128 mView.updateShowPercent(); 129 } 130 }; 131 132 // Some places may need to show the battery conditionally, and not obey the tuner 133 private boolean mIgnoreTunerUpdates; 134 private boolean mIsSubscribedForTunerUpdates; 135 136 @Inject BatteryMeterViewController( BatteryMeterView view, StatusBarLocation location, UserTracker userTracker, ConfigurationController configurationController, TunerService tunerService, @Main Handler mainHandler, ContentResolver contentResolver, FeatureFlags featureFlags, BatteryController batteryController)137 public BatteryMeterViewController( 138 BatteryMeterView view, 139 StatusBarLocation location, 140 UserTracker userTracker, 141 ConfigurationController configurationController, 142 TunerService tunerService, 143 @Main Handler mainHandler, 144 ContentResolver contentResolver, 145 FeatureFlags featureFlags, 146 BatteryController batteryController) { 147 super(view); 148 mLocation = location; 149 mUserTracker = userTracker; 150 mConfigurationController = configurationController; 151 mTunerService = tunerService; 152 mMainHandler = mainHandler; 153 mContentResolver = contentResolver; 154 mFeatureFlags = featureFlags; 155 mBatteryController = batteryController; 156 157 mView.setBatteryEstimateFetcher(mBatteryController::getEstimatedTimeRemainingString); 158 159 mSlotBattery = getResources().getString(com.android.internal.R.string.status_bar_battery); 160 mSettingObserver = new SettingObserver(mMainHandler); 161 } 162 163 @Override onViewAttached()164 protected void onViewAttached() { 165 mConfigurationController.addCallback(mConfigurationListener); 166 subscribeForTunerUpdates(); 167 mBatteryController.addCallback(mBatteryStateChangeCallback); 168 169 registerShowBatteryPercentObserver(mUserTracker.getUserId()); 170 registerGlobalBatteryUpdateObserver(); 171 mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(mMainHandler)); 172 173 mView.updateShowPercent(); 174 } 175 176 @Override onViewDetached()177 protected void onViewDetached() { 178 mConfigurationController.removeCallback(mConfigurationListener); 179 unsubscribeFromTunerUpdates(); 180 mBatteryController.removeCallback(mBatteryStateChangeCallback); 181 182 mUserTracker.removeCallback(mUserChangedCallback); 183 mContentResolver.unregisterContentObserver(mSettingObserver); 184 } 185 186 /** 187 * Turn off {@link BatteryMeterView}'s subscribing to the tuner for updates, and thus avoid it 188 * controlling its own visibility. 189 */ ignoreTunerUpdates()190 public void ignoreTunerUpdates() { 191 mIgnoreTunerUpdates = true; 192 unsubscribeFromTunerUpdates(); 193 } 194 subscribeForTunerUpdates()195 private void subscribeForTunerUpdates() { 196 if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) { 197 return; 198 } 199 200 mTunerService.addTunable(mTunable, StatusBarIconController.ICON_HIDE_LIST); 201 mIsSubscribedForTunerUpdates = true; 202 } 203 unsubscribeFromTunerUpdates()204 private void unsubscribeFromTunerUpdates() { 205 if (!mIsSubscribedForTunerUpdates) { 206 return; 207 } 208 209 mTunerService.removeTunable(mTunable); 210 mIsSubscribedForTunerUpdates = false; 211 } 212 registerShowBatteryPercentObserver(int user)213 private void registerShowBatteryPercentObserver(int user) { 214 mContentResolver.registerContentObserver( 215 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), 216 false, 217 mSettingObserver, 218 user); 219 } 220 registerGlobalBatteryUpdateObserver()221 private void registerGlobalBatteryUpdateObserver() { 222 mContentResolver.registerContentObserver( 223 Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME), 224 false, 225 mSettingObserver); 226 } 227 228 private final class SettingObserver extends ContentObserver { SettingObserver(Handler handler)229 public SettingObserver(Handler handler) { 230 super(handler); 231 } 232 233 @Override onChange(boolean selfChange, Uri uri)234 public void onChange(boolean selfChange, Uri uri) { 235 super.onChange(selfChange, uri); 236 mView.updateShowPercent(); 237 if (TextUtils.equals(uri.getLastPathSegment(), 238 Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)) { 239 // update the text for sure if the estimate in the cache was updated 240 mView.updatePercentText(); 241 } 242 } 243 } 244 245 /** */ 246 @SysUISingleton 247 public static class Factory { 248 private final UserTracker mUserTracker; 249 private final ConfigurationController mConfigurationController; 250 private final TunerService mTunerService; 251 private final @Main Handler mMainHandler; 252 private final ContentResolver mContentResolver; 253 private final FeatureFlags mFeatureFlags; 254 private final BatteryController mBatteryController; 255 256 @Inject Factory( UserTracker userTracker, ConfigurationController configurationController, TunerService tunerService, @Main Handler mainHandler, ContentResolver contentResolver, FeatureFlags featureFlags, BatteryController batteryController )257 public Factory( 258 UserTracker userTracker, 259 ConfigurationController configurationController, 260 TunerService tunerService, 261 @Main Handler mainHandler, 262 ContentResolver contentResolver, 263 FeatureFlags featureFlags, 264 BatteryController batteryController 265 ) { 266 mUserTracker = userTracker; 267 mConfigurationController = configurationController; 268 mTunerService = tunerService; 269 mMainHandler = mainHandler; 270 mContentResolver = contentResolver; 271 mFeatureFlags = featureFlags; 272 mBatteryController = batteryController; 273 } 274 275 /** */ create(View view, StatusBarLocation location)276 public BatteryMeterViewController create(View view, StatusBarLocation location) { 277 return new BatteryMeterViewController( 278 (BatteryMeterView) view, 279 location, 280 mUserTracker, 281 mConfigurationController, 282 mTunerService, 283 mMainHandler, 284 mContentResolver, 285 mFeatureFlags, 286 mBatteryController 287 ); 288 } 289 } 290 } 291