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