1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. 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 distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 package com.android.settings.fuelgauge; 15 16 import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType; 17 18 import android.app.settings.SettingsEnums; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.IntentFilter; 22 import android.database.ContentObserver; 23 import android.net.Uri; 24 import android.os.BatteryManager; 25 import android.os.Bundle; 26 import android.os.Handler; 27 import android.provider.SearchIndexableResource; 28 import android.util.Log; 29 30 import androidx.annotation.NonNull; 31 import androidx.annotation.VisibleForTesting; 32 import androidx.loader.app.LoaderManager; 33 import androidx.loader.content.Loader; 34 35 import com.android.settings.R; 36 import com.android.settings.SettingsActivity; 37 import com.android.settings.fuelgauge.BatteryBroadcastReceiver; 38 import com.android.settings.overlay.FeatureFactory; 39 import com.android.settings.search.BaseSearchIndexProvider; 40 import com.android.settingslib.core.AbstractPreferenceController; 41 import com.android.settingslib.search.SearchIndexable; 42 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.List; 46 import java.util.Map; 47 48 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) 49 public class PowerUsageAdvanced extends PowerUsageBase { 50 private static final String TAG = "AdvancedBatteryUsage"; 51 private static final String KEY_REFRESH_TYPE = "refresh_type"; 52 private static final String KEY_BATTERY_GRAPH = "battery_graph"; 53 private static final String KEY_APP_LIST = "app_list"; 54 private static final int LOADER_BATTERY_USAGE_STATS = 2; 55 56 @VisibleForTesting 57 BatteryHistoryPreference mHistPref; 58 @VisibleForTesting 59 Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap; 60 @VisibleForTesting 61 final BatteryHistoryLoaderCallbacks mBatteryHistoryLoaderCallbacks = 62 new BatteryHistoryLoaderCallbacks(); 63 64 private boolean mIsChartDataLoaded = false; 65 private boolean mIsChartGraphEnabled = false; 66 private PowerUsageFeatureProvider mPowerUsageFeatureProvider; 67 private BatteryChartPreferenceController mBatteryChartPreferenceController; 68 private BatteryAppListPreferenceController mBatteryAppListPreferenceController; 69 70 private final ContentObserver mBatteryObserver = 71 new ContentObserver(new Handler()) { 72 @Override 73 public void onChange(boolean selfChange) { 74 Log.d(TAG, "onBatteryContentChange: " + selfChange); 75 mIsChartDataLoaded = false; 76 restartBatteryStatsLoader( 77 BatteryBroadcastReceiver.BatteryUpdateType.MANUAL); 78 } 79 }; 80 81 @Override onCreate(Bundle icicle)82 public void onCreate(Bundle icicle) { 83 super.onCreate(icicle); 84 final Context context = getContext(); 85 refreshFeatureFlag(context); 86 mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_GRAPH); 87 if (mIsChartGraphEnabled) { 88 setBatteryChartPreferenceController(); 89 } else { 90 updateHistPrefSummary(context); 91 } 92 } 93 94 @Override onDestroy()95 public void onDestroy() { 96 super.onDestroy(); 97 if (getActivity().isChangingConfigurations()) { 98 BatteryEntry.clearUidCache(); 99 } 100 } 101 102 @Override getMetricsCategory()103 public int getMetricsCategory() { 104 return SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL; 105 } 106 107 @Override getLogTag()108 protected String getLogTag() { 109 return TAG; 110 } 111 112 @Override getPreferenceScreenResId()113 protected int getPreferenceScreenResId() { 114 return R.xml.power_usage_advanced; 115 } 116 117 @Override onPause()118 public void onPause() { 119 super.onPause(); 120 // Resets the flag to reload usage data in onResume() callback. 121 mIsChartDataLoaded = false; 122 final Uri uri = mPowerUsageFeatureProvider.getBatteryHistoryUri(); 123 if (uri != null) { 124 getContext().getContentResolver().unregisterContentObserver(mBatteryObserver); 125 } 126 } 127 128 @Override onResume()129 public void onResume() { 130 super.onResume(); 131 final Uri uri = mPowerUsageFeatureProvider.getBatteryHistoryUri(); 132 if (uri != null) { 133 getContext().getContentResolver().registerContentObserver( 134 uri, /*notifyForDescendants*/ true, mBatteryObserver); 135 } 136 } 137 138 @Override createPreferenceControllers(Context context)139 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 140 refreshFeatureFlag(context); 141 final List<AbstractPreferenceController> controllers = new ArrayList<>(); 142 // Creates based on the chart design is enabled or not. 143 if (mIsChartGraphEnabled) { 144 mBatteryChartPreferenceController = 145 new BatteryChartPreferenceController(context, KEY_APP_LIST, 146 getSettingsLifecycle(), (SettingsActivity) getActivity(), this); 147 controllers.add(mBatteryChartPreferenceController); 148 setBatteryChartPreferenceController(); 149 } else { 150 mBatteryAppListPreferenceController = 151 new BatteryAppListPreferenceController(context, KEY_APP_LIST, 152 getSettingsLifecycle(), (SettingsActivity) getActivity(), this); 153 controllers.add(mBatteryAppListPreferenceController); 154 } 155 return controllers; 156 } 157 158 @Override isBatteryHistoryNeeded()159 protected boolean isBatteryHistoryNeeded() { 160 return true; 161 } 162 163 @Override refreshUi(@atteryUpdateType int refreshType)164 protected void refreshUi(@BatteryUpdateType int refreshType) { 165 final Context context = getContext(); 166 if (context == null) { 167 return; 168 } 169 updatePreference(mHistPref); 170 if (mBatteryAppListPreferenceController != null && mBatteryUsageStats != null) { 171 updateHistPrefSummary(context); 172 mBatteryAppListPreferenceController.refreshAppListGroup( 173 mBatteryUsageStats, /* showAllApps */true); 174 } 175 if (mBatteryChartPreferenceController != null && mBatteryHistoryMap != null) { 176 mBatteryChartPreferenceController.setBatteryHistoryMap(mBatteryHistoryMap); 177 } 178 } 179 180 @Override restartBatteryStatsLoader(int refreshType)181 protected void restartBatteryStatsLoader(int refreshType) { 182 final Bundle bundle = new Bundle(); 183 bundle.putInt(KEY_REFRESH_TYPE, refreshType); 184 // Uses customized battery history loader if chart design is enabled. 185 if (mIsChartGraphEnabled && !mIsChartDataLoaded) { 186 mIsChartDataLoaded = true; 187 getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle, 188 mBatteryHistoryLoaderCallbacks); 189 } else if (!mIsChartGraphEnabled) { 190 super.restartBatteryStatsLoader(refreshType); 191 } 192 } 193 updateHistPrefSummary(Context context)194 private void updateHistPrefSummary(Context context) { 195 final Intent batteryIntent = 196 context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 197 final boolean plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0; 198 if (mPowerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(context) && !plugged) { 199 mHistPref.setBottomSummary( 200 mPowerUsageFeatureProvider.getAdvancedUsageScreenInfoString()); 201 } else { 202 mHistPref.hideBottomSummary(); 203 } 204 } 205 refreshFeatureFlag(Context context)206 private void refreshFeatureFlag(Context context) { 207 if (mPowerUsageFeatureProvider == null) { 208 mPowerUsageFeatureProvider = FeatureFactory.getFactory(context) 209 .getPowerUsageFeatureProvider(context); 210 mIsChartGraphEnabled = mPowerUsageFeatureProvider.isChartGraphEnabled(context); 211 } 212 } 213 setBatteryChartPreferenceController()214 private void setBatteryChartPreferenceController() { 215 if (mHistPref != null && mBatteryChartPreferenceController != null) { 216 mHistPref.setChartPreferenceController(mBatteryChartPreferenceController); 217 } 218 } 219 220 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 221 new BaseSearchIndexProvider() { 222 @Override 223 public List<SearchIndexableResource> getXmlResourcesToIndex( 224 Context context, boolean enabled) { 225 final SearchIndexableResource sir = new SearchIndexableResource(context); 226 sir.xmlResId = R.xml.power_usage_advanced; 227 return Arrays.asList(sir); 228 } 229 230 @Override 231 public List<AbstractPreferenceController> createPreferenceControllers( 232 Context context) { 233 final List<AbstractPreferenceController> controllers = new ArrayList<>(); 234 controllers.add(new BatteryAppListPreferenceController(context, 235 KEY_APP_LIST, null /* lifecycle */, null /* activity */, 236 null /* fragment */)); 237 return controllers; 238 } 239 }; 240 241 private class BatteryHistoryLoaderCallbacks 242 implements LoaderManager.LoaderCallbacks<Map<Long, Map<String, BatteryHistEntry>>> { 243 private int mRefreshType; 244 245 @Override 246 @NonNull onCreateLoader( int id, Bundle bundle)247 public Loader<Map<Long, Map<String, BatteryHistEntry>>> onCreateLoader( 248 int id, Bundle bundle) { 249 mRefreshType = bundle.getInt(KEY_REFRESH_TYPE); 250 return new BatteryHistoryLoader(getContext()); 251 } 252 253 @Override onLoadFinished(Loader<Map<Long, Map<String, BatteryHistEntry>>> loader, Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap)254 public void onLoadFinished(Loader<Map<Long, Map<String, BatteryHistEntry>>> loader, 255 Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) { 256 mBatteryHistoryMap = batteryHistoryMap; 257 PowerUsageAdvanced.this.onLoadFinished(mRefreshType); 258 } 259 260 @Override onLoaderReset(Loader<Map<Long, Map<String, BatteryHistEntry>>> loader)261 public void onLoaderReset(Loader<Map<Long, Map<String, BatteryHistEntry>>> loader) { 262 } 263 } 264 265 } 266