1 /* 2 * Copyright (C) 2009 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 17 package com.android.settings.fuelgauge; 18 19 import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType; 20 21 import android.app.settings.SettingsEnums; 22 import android.content.Context; 23 import android.database.ContentObserver; 24 import android.net.Uri; 25 import android.os.Bundle; 26 import android.os.Handler; 27 import android.provider.Settings.Global; 28 29 import androidx.annotation.VisibleForTesting; 30 import androidx.loader.app.LoaderManager; 31 import androidx.loader.content.Loader; 32 import androidx.preference.Preference; 33 34 import com.android.settings.R; 35 import com.android.settings.SettingsActivity; 36 import com.android.settings.Utils; 37 import com.android.settings.fuelgauge.batterytip.BatteryTipLoader; 38 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; 39 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; 40 import com.android.settings.overlay.FeatureFactory; 41 import com.android.settings.search.BaseSearchIndexProvider; 42 import com.android.settingslib.search.SearchIndexable; 43 import com.android.settingslib.widget.LayoutPreference; 44 45 import java.util.List; 46 47 /** 48 * Displays a list of apps and subsystems that consume power, ordered by how much power was consumed 49 * since the last time it was unplugged. 50 */ 51 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) 52 public class PowerUsageSummary extends PowerUsageBase implements 53 BatteryTipPreferenceController.BatteryTipListener { 54 55 static final String TAG = "PowerUsageSummary"; 56 57 @VisibleForTesting 58 static final String KEY_BATTERY_ERROR = "battery_help_message"; 59 @VisibleForTesting 60 static final String KEY_BATTERY_USAGE = "battery_usage_summary"; 61 62 @VisibleForTesting 63 static final int BATTERY_INFO_LOADER = 1; 64 @VisibleForTesting 65 static final int BATTERY_TIP_LOADER = 2; 66 67 @VisibleForTesting 68 PowerUsageFeatureProvider mPowerFeatureProvider; 69 @VisibleForTesting 70 BatteryUtils mBatteryUtils; 71 @VisibleForTesting 72 LayoutPreference mBatteryLayoutPref; 73 @VisibleForTesting 74 BatteryInfo mBatteryInfo; 75 76 @VisibleForTesting 77 BatteryHeaderPreferenceController mBatteryHeaderPreferenceController; 78 @VisibleForTesting 79 BatteryTipPreferenceController mBatteryTipPreferenceController; 80 @VisibleForTesting 81 boolean mNeedUpdateBatteryTip; 82 @VisibleForTesting 83 Preference mHelpPreference; 84 @VisibleForTesting 85 Preference mBatteryUsagePreference; 86 87 @VisibleForTesting 88 final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) { 89 @Override 90 public void onChange(boolean selfChange, Uri uri) { 91 restartBatteryInfoLoader(); 92 } 93 }; 94 95 @VisibleForTesting 96 LoaderManager.LoaderCallbacks<BatteryInfo> mBatteryInfoLoaderCallbacks = 97 new LoaderManager.LoaderCallbacks<BatteryInfo>() { 98 99 @Override 100 public Loader<BatteryInfo> onCreateLoader(int i, Bundle bundle) { 101 return new BatteryInfoLoader(getContext()); 102 } 103 104 @Override 105 public void onLoadFinished(Loader<BatteryInfo> loader, BatteryInfo batteryInfo) { 106 mBatteryHeaderPreferenceController.updateHeaderPreference(batteryInfo); 107 mBatteryHeaderPreferenceController.updateHeaderByBatteryTips( 108 mBatteryTipPreferenceController.getCurrentBatteryTip(), batteryInfo); 109 mBatteryInfo = batteryInfo; 110 } 111 112 @Override 113 public void onLoaderReset(Loader<BatteryInfo> loader) { 114 // do nothing 115 } 116 }; 117 118 private LoaderManager.LoaderCallbacks<List<BatteryTip>> mBatteryTipsCallbacks = 119 new LoaderManager.LoaderCallbacks<List<BatteryTip>>() { 120 121 @Override 122 public Loader<List<BatteryTip>> onCreateLoader(int id, Bundle args) { 123 return new BatteryTipLoader(getContext(), mBatteryUsageStats); 124 } 125 126 @Override 127 public void onLoadFinished(Loader<List<BatteryTip>> loader, 128 List<BatteryTip> data) { 129 mBatteryTipPreferenceController.updateBatteryTips(data); 130 mBatteryHeaderPreferenceController.updateHeaderByBatteryTips( 131 mBatteryTipPreferenceController.getCurrentBatteryTip(), mBatteryInfo); 132 } 133 134 @Override 135 public void onLoaderReset(Loader<List<BatteryTip>> loader) { 136 137 } 138 }; 139 140 @Override onAttach(Context context)141 public void onAttach(Context context) { 142 super.onAttach(context); 143 final SettingsActivity activity = (SettingsActivity) getActivity(); 144 145 mBatteryHeaderPreferenceController = use(BatteryHeaderPreferenceController.class); 146 mBatteryHeaderPreferenceController.setActivity(activity); 147 mBatteryHeaderPreferenceController.setFragment(this); 148 mBatteryHeaderPreferenceController.setLifecycle(getSettingsLifecycle()); 149 150 mBatteryTipPreferenceController = use(BatteryTipPreferenceController.class); 151 mBatteryTipPreferenceController.setActivity(activity); 152 mBatteryTipPreferenceController.setFragment(this); 153 mBatteryTipPreferenceController.setBatteryTipListener(this::onBatteryTipHandled); 154 } 155 156 @Override onCreate(Bundle icicle)157 public void onCreate(Bundle icicle) { 158 super.onCreate(icicle); 159 setAnimationAllowed(true); 160 161 initFeatureProvider(); 162 initPreference(); 163 164 mBatteryUtils = BatteryUtils.getInstance(getContext()); 165 166 if (Utils.isBatteryPresent(getContext())) { 167 restartBatteryInfoLoader(); 168 } else { 169 // Present help preference when battery is unavailable. 170 mHelpPreference.setVisible(true); 171 } 172 mBatteryTipPreferenceController.restoreInstanceState(icicle); 173 updateBatteryTipFlag(icicle); 174 } 175 176 @Override onResume()177 public void onResume() { 178 super.onResume(); 179 getContentResolver().registerContentObserver( 180 Global.getUriFor(Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME), 181 false, 182 mSettingsObserver); 183 } 184 185 @Override onPause()186 public void onPause() { 187 getContentResolver().unregisterContentObserver(mSettingsObserver); 188 super.onPause(); 189 } 190 191 @Override getMetricsCategory()192 public int getMetricsCategory() { 193 return SettingsEnums.FUELGAUGE_POWER_USAGE_SUMMARY_V2; 194 } 195 196 @Override getLogTag()197 protected String getLogTag() { 198 return TAG; 199 } 200 201 @Override getPreferenceScreenResId()202 protected int getPreferenceScreenResId() { 203 return R.xml.power_usage_summary; 204 } 205 206 @Override getHelpResource()207 public int getHelpResource() { 208 return R.string.help_url_battery; 209 } 210 211 @Override isBatteryHistoryNeeded()212 protected boolean isBatteryHistoryNeeded() { 213 return false; 214 } 215 refreshUi(@atteryUpdateType int refreshType)216 protected void refreshUi(@BatteryUpdateType int refreshType) { 217 final Context context = getContext(); 218 if (context == null) { 219 return; 220 } 221 // Skip refreshing UI if battery is not present. 222 if (!mIsBatteryPresent) { 223 return; 224 } 225 226 // Skip BatteryTipLoader if device is rotated or only battery level change 227 if (mNeedUpdateBatteryTip 228 && refreshType != BatteryUpdateType.BATTERY_LEVEL) { 229 restartBatteryTipLoader(); 230 } else { 231 mNeedUpdateBatteryTip = true; 232 } 233 // reload BatteryInfo and updateUI 234 restartBatteryInfoLoader(); 235 } 236 237 @VisibleForTesting restartBatteryTipLoader()238 void restartBatteryTipLoader() { 239 getLoaderManager().restartLoader(BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks); 240 } 241 242 @VisibleForTesting setBatteryLayoutPreference(LayoutPreference layoutPreference)243 void setBatteryLayoutPreference(LayoutPreference layoutPreference) { 244 mBatteryLayoutPref = layoutPreference; 245 } 246 247 @VisibleForTesting initFeatureProvider()248 void initFeatureProvider() { 249 final Context context = getContext(); 250 mPowerFeatureProvider = FeatureFactory.getFactory(context) 251 .getPowerUsageFeatureProvider(context); 252 } 253 254 @VisibleForTesting initPreference()255 void initPreference() { 256 mBatteryUsagePreference = findPreference(KEY_BATTERY_USAGE); 257 mBatteryUsagePreference.setSummary( 258 mPowerFeatureProvider.isChartGraphEnabled(getContext()) ? 259 getString(R.string.advanced_battery_preference_summary_with_hours) : 260 getString(R.string.advanced_battery_preference_summary)); 261 262 mHelpPreference = findPreference(KEY_BATTERY_ERROR); 263 mHelpPreference.setVisible(false); 264 } 265 266 @VisibleForTesting restartBatteryInfoLoader()267 void restartBatteryInfoLoader() { 268 if (getContext() == null) { 269 return; 270 } 271 // Skip restartBatteryInfoLoader if battery is not present. 272 if (!mIsBatteryPresent) { 273 return; 274 } 275 getLoaderManager().restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY, 276 mBatteryInfoLoaderCallbacks); 277 } 278 279 @VisibleForTesting updateBatteryTipFlag(Bundle icicle)280 void updateBatteryTipFlag(Bundle icicle) { 281 mNeedUpdateBatteryTip = icicle == null || mBatteryTipPreferenceController.needUpdate(); 282 } 283 284 @Override restartBatteryStatsLoader(@atteryUpdateType int refreshType)285 protected void restartBatteryStatsLoader(@BatteryUpdateType int refreshType) { 286 super.restartBatteryStatsLoader(refreshType); 287 // Update battery header if battery is present. 288 if (mIsBatteryPresent) { 289 mBatteryHeaderPreferenceController.quickUpdateHeaderPreference(); 290 } 291 } 292 293 @Override onSaveInstanceState(Bundle outState)294 public void onSaveInstanceState(Bundle outState) { 295 super.onSaveInstanceState(outState); 296 mBatteryTipPreferenceController.saveInstanceState(outState); 297 } 298 299 @Override onBatteryTipHandled(BatteryTip batteryTip)300 public void onBatteryTipHandled(BatteryTip batteryTip) { 301 restartBatteryTipLoader(); 302 } 303 304 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 305 new BaseSearchIndexProvider(R.xml.power_usage_summary); 306 } 307