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.app.ActivityManager; 21 import android.content.ContentResolver; 22 import android.database.ContentObserver; 23 import android.net.Uri; 24 import android.os.Handler; 25 import android.provider.Settings; 26 import android.text.TextUtils; 27 import android.util.ArraySet; 28 import android.view.View; 29 30 import com.android.systemui.broadcast.BroadcastDispatcher; 31 import com.android.systemui.dagger.qualifiers.Main; 32 import com.android.systemui.settings.CurrentUserTracker; 33 import com.android.systemui.statusbar.phone.StatusBarIconController; 34 import com.android.systemui.statusbar.policy.BatteryController; 35 import com.android.systemui.statusbar.policy.ConfigurationController; 36 import com.android.systemui.tuner.TunerService; 37 import com.android.systemui.util.ViewController; 38 39 import javax.inject.Inject; 40 41 /** Controller for {@link BatteryMeterView}. **/ 42 public class BatteryMeterViewController extends ViewController<BatteryMeterView> { 43 private final ConfigurationController mConfigurationController; 44 private final TunerService mTunerService; 45 private final ContentResolver mContentResolver; 46 private final BatteryController mBatteryController; 47 48 private final String mSlotBattery; 49 private final SettingObserver mSettingObserver; 50 private final CurrentUserTracker mCurrentUserTracker; 51 52 private final ConfigurationController.ConfigurationListener mConfigurationListener = 53 new ConfigurationController.ConfigurationListener() { 54 @Override 55 public void onDensityOrFontScaleChanged() { 56 mView.scaleBatteryMeterViews(); 57 } 58 }; 59 60 private final TunerService.Tunable mTunable = new TunerService.Tunable() { 61 @Override 62 public void onTuningChanged(String key, String newValue) { 63 if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) { 64 ArraySet<String> icons = StatusBarIconController.getIconHideList( 65 getContext(), newValue); 66 mView.setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE); 67 } 68 } 69 }; 70 71 private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback = 72 new BatteryController.BatteryStateChangeCallback() { 73 @Override 74 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { 75 mView.onBatteryLevelChanged(level, pluggedIn); 76 } 77 78 @Override 79 public void onPowerSaveChanged(boolean isPowerSave) { 80 mView.onPowerSaveChanged(isPowerSave); 81 } 82 83 @Override 84 public void onBatteryUnknownStateChanged(boolean isUnknown) { 85 mView.onBatteryUnknownStateChanged(isUnknown); 86 } 87 }; 88 89 // Some places may need to show the battery conditionally, and not obey the tuner 90 private boolean mIgnoreTunerUpdates; 91 private boolean mIsSubscribedForTunerUpdates; 92 93 @Inject BatteryMeterViewController( BatteryMeterView view, ConfigurationController configurationController, TunerService tunerService, BroadcastDispatcher broadcastDispatcher, @Main Handler mainHandler, ContentResolver contentResolver, BatteryController batteryController)94 public BatteryMeterViewController( 95 BatteryMeterView view, 96 ConfigurationController configurationController, 97 TunerService tunerService, 98 BroadcastDispatcher broadcastDispatcher, 99 @Main Handler mainHandler, 100 ContentResolver contentResolver, 101 BatteryController batteryController) { 102 super(view); 103 mConfigurationController = configurationController; 104 mTunerService = tunerService; 105 mContentResolver = contentResolver; 106 mBatteryController = batteryController; 107 108 mView.setBatteryEstimateFetcher(mBatteryController::getEstimatedTimeRemainingString); 109 110 mSlotBattery = getResources().getString(com.android.internal.R.string.status_bar_battery); 111 mSettingObserver = new SettingObserver(mainHandler); 112 mCurrentUserTracker = new CurrentUserTracker(broadcastDispatcher) { 113 @Override 114 public void onUserSwitched(int newUserId) { 115 contentResolver.unregisterContentObserver(mSettingObserver); 116 registerShowBatteryPercentObserver(newUserId); 117 mView.updateShowPercent(); 118 } 119 }; 120 } 121 122 @Override onViewAttached()123 protected void onViewAttached() { 124 mConfigurationController.addCallback(mConfigurationListener); 125 subscribeForTunerUpdates(); 126 mBatteryController.addCallback(mBatteryStateChangeCallback); 127 128 registerShowBatteryPercentObserver(ActivityManager.getCurrentUser()); 129 registerGlobalBatteryUpdateObserver(); 130 mCurrentUserTracker.startTracking(); 131 132 mView.updateShowPercent(); 133 } 134 135 @Override onViewDetached()136 protected void onViewDetached() { 137 mConfigurationController.removeCallback(mConfigurationListener); 138 unsubscribeFromTunerUpdates(); 139 mBatteryController.removeCallback(mBatteryStateChangeCallback); 140 141 mCurrentUserTracker.stopTracking(); 142 mContentResolver.unregisterContentObserver(mSettingObserver); 143 } 144 145 /** 146 * Turn off {@link BatteryMeterView}'s subscribing to the tuner for updates, and thus avoid it 147 * controlling its own visibility. 148 */ ignoreTunerUpdates()149 public void ignoreTunerUpdates() { 150 mIgnoreTunerUpdates = true; 151 unsubscribeFromTunerUpdates(); 152 } 153 subscribeForTunerUpdates()154 private void subscribeForTunerUpdates() { 155 if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) { 156 return; 157 } 158 159 mTunerService.addTunable(mTunable, StatusBarIconController.ICON_HIDE_LIST); 160 mIsSubscribedForTunerUpdates = true; 161 } 162 unsubscribeFromTunerUpdates()163 private void unsubscribeFromTunerUpdates() { 164 if (!mIsSubscribedForTunerUpdates) { 165 return; 166 } 167 168 mTunerService.removeTunable(mTunable); 169 mIsSubscribedForTunerUpdates = false; 170 } 171 registerShowBatteryPercentObserver(int user)172 private void registerShowBatteryPercentObserver(int user) { 173 mContentResolver.registerContentObserver( 174 Settings.System.getUriFor(SHOW_BATTERY_PERCENT), 175 false, 176 mSettingObserver, 177 user); 178 } 179 registerGlobalBatteryUpdateObserver()180 private void registerGlobalBatteryUpdateObserver() { 181 mContentResolver.registerContentObserver( 182 Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME), 183 false, 184 mSettingObserver); 185 } 186 187 private final class SettingObserver extends ContentObserver { SettingObserver(Handler handler)188 public SettingObserver(Handler handler) { 189 super(handler); 190 } 191 192 @Override onChange(boolean selfChange, Uri uri)193 public void onChange(boolean selfChange, Uri uri) { 194 super.onChange(selfChange, uri); 195 mView.updateShowPercent(); 196 if (TextUtils.equals(uri.getLastPathSegment(), 197 Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)) { 198 // update the text for sure if the estimate in the cache was updated 199 mView.updatePercentText(); 200 } 201 } 202 } 203 } 204