1 /*
2  * Copyright (C) 2022 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.settings.fuelgauge.batteryusage;
17 
18 import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType;
19 
20 import android.app.Activity;
21 import android.content.Context;
22 import android.os.BatteryUsageStats;
23 import android.os.Bundle;
24 import android.os.UserManager;
25 import android.util.Log;
26 
27 import androidx.annotation.IntDef;
28 import androidx.annotation.NonNull;
29 import androidx.annotation.VisibleForTesting;
30 import androidx.loader.app.LoaderManager;
31 import androidx.loader.content.Loader;
32 
33 import com.android.settings.dashboard.DashboardFragment;
34 import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
35 
36 import java.lang.annotation.Retention;
37 import java.lang.annotation.RetentionPolicy;
38 
39 /** Common base class for things that need to show the battery usage graph. */
40 public abstract class PowerUsageBase extends DashboardFragment {
41     private static final String TAG = "PowerUsageBase";
42 
43     @VisibleForTesting static final String KEY_REFRESH_TYPE = "refresh_type";
44     @VisibleForTesting static final String KEY_INCLUDE_HISTORY = "include_history";
45     @VisibleForTesting BatteryUsageStats mBatteryUsageStats;
46 
47     protected UserManager mUm;
48     protected boolean mIsBatteryPresent = true;
49     private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
50 
51     @VisibleForTesting
52     final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks =
53             new BatteryUsageStatsLoaderCallbacks();
54 
55     @Retention(RetentionPolicy.SOURCE)
56     @IntDef({
57         LoaderIndex.BATTERY_USAGE_STATS_LOADER,
58         LoaderIndex.BATTERY_INFO_LOADER,
59         LoaderIndex.BATTERY_TIP_LOADER,
60         LoaderIndex.BATTERY_LEVEL_DATA_LOADER
61     })
62     public @interface LoaderIndex {
63         int BATTERY_USAGE_STATS_LOADER = 0;
64         int BATTERY_INFO_LOADER = 1;
65         int BATTERY_TIP_LOADER = 2;
66         int BATTERY_LEVEL_DATA_LOADER = 3;
67     }
68 
69     @Override
onAttach(Activity activity)70     public void onAttach(Activity activity) {
71         super.onAttach(activity);
72         mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);
73     }
74 
75     @Override
onCreate(Bundle icicle)76     public void onCreate(Bundle icicle) {
77         super.onCreate(icicle);
78 
79         mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
80         mBatteryBroadcastReceiver.setBatteryChangedListener(
81                 type -> {
82                     if (type == BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_NOT_PRESENT) {
83                         mIsBatteryPresent = false;
84                     }
85                     restartBatteryStatsLoader(type);
86                 });
87     }
88 
89     @Override
onStart()90     public void onStart() {
91         super.onStart();
92         mBatteryBroadcastReceiver.register();
93     }
94 
95     @Override
onStop()96     public void onStop() {
97         super.onStop();
98         mBatteryBroadcastReceiver.unRegister();
99         closeBatteryUsageStatsIfNeeded();
100     }
101 
restartBatteryStatsLoader(int refreshType)102     protected void restartBatteryStatsLoader(int refreshType) {
103         final Bundle bundle = new Bundle();
104         bundle.putInt(KEY_REFRESH_TYPE, refreshType);
105         bundle.putBoolean(KEY_INCLUDE_HISTORY, false);
106         restartLoader(
107                 LoaderIndex.BATTERY_USAGE_STATS_LOADER, bundle, mBatteryUsageStatsLoaderCallbacks);
108     }
109 
getLoaderManagerForCurrentFragment()110     protected LoaderManager getLoaderManagerForCurrentFragment() {
111         return LoaderManager.getInstance(this);
112     }
113 
restartLoader( int loaderId, Bundle bundle, LoaderManager.LoaderCallbacks<?> loaderCallbacks)114     protected void restartLoader(
115             int loaderId, Bundle bundle, LoaderManager.LoaderCallbacks<?> loaderCallbacks) {
116         LoaderManager loaderManager = getLoaderManagerForCurrentFragment();
117         Loader<?> loader = loaderManager.getLoader(loaderId);
118         if (loader != null && !loader.isReset()) {
119             loaderManager.restartLoader(loaderId, bundle, loaderCallbacks);
120         } else {
121             loaderManager.initLoader(loaderId, bundle, loaderCallbacks);
122         }
123     }
124 
onLoadFinished(@atteryUpdateType int refreshType)125     protected void onLoadFinished(@BatteryUpdateType int refreshType) {
126         refreshUi(refreshType);
127     }
128 
refreshUi(@atteryUpdateType int refreshType)129     protected abstract void refreshUi(@BatteryUpdateType int refreshType);
130 
131     private class BatteryUsageStatsLoaderCallbacks
132             implements LoaderManager.LoaderCallbacks<BatteryUsageStats> {
133         private int mRefreshType;
134 
135         @Override
136         @NonNull
onCreateLoader(int id, Bundle args)137         public Loader<BatteryUsageStats> onCreateLoader(int id, Bundle args) {
138             mRefreshType = args.getInt(KEY_REFRESH_TYPE);
139             return new BatteryUsageStatsLoader(getContext(), args.getBoolean(KEY_INCLUDE_HISTORY));
140         }
141 
142         @Override
onLoadFinished( Loader<BatteryUsageStats> loader, BatteryUsageStats batteryUsageStats)143         public void onLoadFinished(
144                 Loader<BatteryUsageStats> loader, BatteryUsageStats batteryUsageStats) {
145             closeBatteryUsageStatsIfNeeded();
146             mBatteryUsageStats = batteryUsageStats;
147             PowerUsageBase.this.onLoadFinished(mRefreshType);
148         }
149 
150         @Override
onLoaderReset(Loader<BatteryUsageStats> loader)151         public void onLoaderReset(Loader<BatteryUsageStats> loader) {}
152     }
153 
closeBatteryUsageStatsIfNeeded()154     private void closeBatteryUsageStatsIfNeeded() {
155         if (mBatteryUsageStats == null) {
156             return;
157         }
158         try {
159             mBatteryUsageStats.close();
160         } catch (Exception e) {
161             Log.e(TAG, "BatteryUsageStats.close() failed", e);
162         } finally {
163             mBatteryUsageStats = null;
164         }
165     }
166 }
167