From a1a30296ae67d3be27a3cb805bd4e26d70812640 Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Fri, 12 Mar 2021 15:47:31 +0800 Subject: [PATCH 1/4] Fix NPE for ConfigureNotificationSettings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NPE is caused by that we have removed the advanced category from Notification page for android S design but it still tries to get category and call setInitialExpandedChildrenCount in onCreate(). Only run the relevant logic on the old design since it’s only used to expand the advanced category and we don’t need the expand feature anymore for android S. Bug: 182237530 Fixes: 182532954 Test: robotest & manual Change-Id: I96f35fa40221079d5498d9d2fab9c75d64698808 --- .../ConfigureNotificationSettings.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java index 0f3695a0a89..dcba273c6a2 100644 --- a/src/com/android/settings/notification/ConfigureNotificationSettings.java +++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java @@ -127,20 +127,23 @@ public class ConfigureNotificationSettings extends DashboardFragment implements @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - final PreferenceScreen screen = getPreferenceScreen(); - final Bundle arguments = getArguments(); + // TODO(b/182237530): This method should be removed when this flag is deprecated. + if (!FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.SILKY_HOME)) { + final PreferenceScreen screen = getPreferenceScreen(); + final Bundle arguments = getArguments(); - if (screen == null) { - return; - } - if (arguments != null) { - final String highlightKey = arguments.getString(EXTRA_FRAGMENT_ARG_KEY); - if (!TextUtils.isEmpty(highlightKey)) { - final PreferenceCategory advancedCategory = - screen.findPreference(KEY_ADVANCED_CATEGORY); - // Has highlight row - expand everything - advancedCategory.setInitialExpandedChildrenCount(Integer.MAX_VALUE); - scrollToPreference(advancedCategory); + if (screen == null) { + return; + } + if (arguments != null) { + final String highlightKey = arguments.getString(EXTRA_FRAGMENT_ARG_KEY); + if (!TextUtils.isEmpty(highlightKey)) { + final PreferenceCategory advancedCategory = + screen.findPreference(KEY_ADVANCED_CATEGORY); + // Has highlight row - expand everything + advancedCategory.setInitialExpandedChildrenCount(Integer.MAX_VALUE); + scrollToPreference(advancedCategory); + } } } } From 1e508a428048a3739c0cff9815742d4a7984bb72 Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Fri, 12 Mar 2021 22:18:26 +0800 Subject: [PATCH 2/4] Fix the issue of the repo upload hooking checker Fixes: 182555684 Test: repo upload test Change-Id: I80a4d4de84b6d54a7b50c325b51b832b7b40b133 --- color-check-baseline.xml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/color-check-baseline.xml b/color-check-baseline.xml index b94da0df4e1..9c79bab72e3 100644 --- a/color-check-baseline.xml +++ b/color-check-baseline.xml @@ -4013,4 +4013,36 @@ column="5"/> + + + + + + + + From 820bee81d682518fb52fee54d3a0549f5c897b09 Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Fri, 19 Feb 2021 14:34:01 -0800 Subject: [PATCH 3/4] Transition BatteryInfo and BatteryUtils to BatteryUsageStats API Bug: 173745486 Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryHistoryPreferenceTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryInfoLoaderTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryInfoTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.BatteryUtilsTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.fuelgauge.batterytip.detectors Change-Id: I469ff8b88aa3307422c02f51943df4ef1759db56 --- .../AppBatteryPreferenceController.java | 2 +- .../fuelgauge/BatteryHistoryPreference.java | 7 +- .../settings/fuelgauge/BatteryInfo.java | 155 +++++++++--------- .../settings/fuelgauge/BatteryInfoLoader.java | 12 +- .../fuelgauge/BatteryUsageStatsLoader.java | 11 +- .../settings/fuelgauge/BatteryUtils.java | 21 ++- .../fuelgauge/DebugEstimatesLoader.java | 10 +- .../fuelgauge/PowerUsageAdvanced.java | 5 + .../settings/fuelgauge/PowerUsageBase.java | 74 +++++++-- .../settings/fuelgauge/PowerUsageSummary.java | 7 +- .../batterytip/BatteryTipLoader.java | 5 +- .../detectors/HighUsageDetector.java | 8 +- .../fuelgauge/BatteryInfoLoaderTest.java | 27 +-- .../settings/fuelgauge/BatteryInfoTest.java | 91 +++++----- .../settings/fuelgauge/BatteryUtilsTest.java | 7 +- .../fuelgauge/PowerUsageBaseTest.java | 5 + .../batterytip/BatteryTipLoaderTest.java | 2 +- .../detectors/HighUsageDetectorTest.java | 27 ++- 18 files changed, 296 insertions(+), 180 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java index 83b42410fad..307ceb1e0a2 100644 --- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java @@ -230,7 +230,7 @@ public class AppBatteryPreferenceController extends BasePreferenceController @Override @NonNull public Loader onCreateLoader(int id, Bundle args) { - return new BatteryUsageStatsLoader(mContext); + return new BatteryUsageStatsLoader(mContext, /* includeBatteryHistory */ false); } @Override diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java index faca9fbcb67..4d3b9cd2e56 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java +++ b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java @@ -17,15 +17,16 @@ package com.android.settings.fuelgauge; import android.content.Context; +import android.os.BatteryUsageStats; import android.util.AttributeSet; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; import com.android.settings.widget.UsageView; @@ -50,11 +51,11 @@ public class BatteryHistoryPreference extends Preference { setSelectable(false); } - public void setStats(BatteryStatsHelper batteryStats) { + void setBatteryUsageStats(@NonNull BatteryUsageStats batteryUsageStats) { BatteryInfo.getBatteryInfo(getContext(), info -> { mBatteryInfo = info; notifyChanged(); - }, batteryStats, false); + }, batteryUsageStats, false); } public void setBottomSummary(CharSequence text) { diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java index 5d7b3258717..a4dd86c1fa7 100644 --- a/src/com/android/settings/fuelgauge/BatteryInfo.java +++ b/src/com/android/settings/fuelgauge/BatteryInfo.java @@ -20,16 +20,18 @@ import android.content.IntentFilter; import android.content.res.Resources; import android.os.AsyncTask; import android.os.BatteryManager; -import android.os.BatteryStats; import android.os.BatteryStats.HistoryItem; -import android.os.Bundle; +import android.os.BatteryStatsManager; +import android.os.BatteryUsageStats; import android.os.SystemClock; import android.text.format.Formatter; import android.util.SparseIntArray; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; -import com.android.internal.os.BatteryStatsHelper; +import com.android.internal.os.BatteryStatsHistoryIterator; import com.android.settings.Utils; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.UsageView; @@ -52,7 +54,7 @@ public class BatteryInfo { public String statusLabel; public String suggestionLabel; private boolean mCharging; - private BatteryStats mStats; + private BatteryUsageStats mBatteryUsageStats; private static final String LOG_TAG = "BatteryInfo"; private long timePeriod; @@ -126,7 +128,7 @@ public class BatteryInfo { parserList[i] = parsers[i]; } parserList[parsers.length] = parser; - parse(mStats, parserList); + parseBatteryHistory(parserList); String timeString = context.getString(R.string.charge_length_format, Formatter.formatShortElapsedTime(context, timePeriod)); String remaining = ""; @@ -137,22 +139,25 @@ public class BatteryInfo { view.setBottomLabels(new CharSequence[]{timeString, remaining}); } - public static void getBatteryInfo(final Context context, final Callback callback) { - BatteryInfo.getBatteryInfo(context, callback, null /* statsHelper */, - false /* shortString */); - } - public static void getBatteryInfo(final Context context, final Callback callback, boolean shortString) { - BatteryInfo.getBatteryInfo(context, callback, null /* statsHelper */, shortString); + BatteryInfo.getBatteryInfo(context, callback, /* batteryUsageStats */ null, shortString); } public static void getBatteryInfo(final Context context, final Callback callback, - final BatteryStatsHelper statsHelper, boolean shortString) { + @Nullable final BatteryUsageStats batteryUsageStats, + boolean shortString) { new AsyncTask() { @Override protected BatteryInfo doInBackground(Void... params) { - return getBatteryInfo(context, statsHelper, shortString); + BatteryUsageStats stats; + if (batteryUsageStats != null) { + stats = batteryUsageStats; + } else { + stats = context.getSystemService(BatteryStatsManager.class) + .getBatteryUsageStats(); + } + return getBatteryInfo(context, stats, shortString); } @Override @@ -164,18 +169,13 @@ public class BatteryInfo { }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } + /** + * Creates a BatteryInfo based on BatteryUsageStats + */ + @WorkerThread public static BatteryInfo getBatteryInfo(final Context context, - final BatteryStatsHelper statsHelper, boolean shortString) { - final BatteryStats stats; + @NonNull final BatteryUsageStats batteryUsageStats, boolean shortString) { final long batteryStatsTime = System.currentTimeMillis(); - if (statsHelper == null) { - final BatteryStatsHelper localStatsHelper = new BatteryStatsHelper(context, - true); - localStatsHelper.create((Bundle) null); - stats = localStatsHelper.getStats(); - } else { - stats = statsHelper.getStats(); - } BatteryUtils.logRuntime(LOG_TAG, "time for getStats", batteryStatsTime); final long startTime = System.currentTimeMillis(); @@ -197,38 +197,38 @@ public class BatteryInfo { Estimate.storeCachedEstimate(context, estimate); BatteryUtils .logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime); - return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, + return BatteryInfo.getBatteryInfo(context, batteryBroadcast, batteryUsageStats, estimate, elapsedRealtimeUs, shortString); } } - final long prediction = discharging - ? stats.computeBatteryTimeRemaining(elapsedRealtimeUs) : 0; + final long prediction = discharging ? batteryUsageStats.getBatteryTimeRemainingMs() : 0; final Estimate estimate = new Estimate( PowerUtil.convertUsToMs(prediction), false, /* isBasedOnUsage */ EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); BatteryUtils.logRuntime(LOG_TAG, "time for regular BatteryInfo", startTime); - return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, + return BatteryInfo.getBatteryInfo(context, batteryBroadcast, batteryUsageStats, estimate, elapsedRealtimeUs, shortString); } @WorkerThread public static BatteryInfo getBatteryInfoOld(Context context, Intent batteryBroadcast, - BatteryStats stats, long elapsedRealtimeUs, boolean shortString) { + BatteryUsageStats batteryUsageStats, long elapsedRealtimeUs, boolean shortString) { Estimate estimate = new Estimate( - PowerUtil.convertUsToMs(stats.computeBatteryTimeRemaining(elapsedRealtimeUs)), + batteryUsageStats.getBatteryTimeRemainingMs(), false, EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); - return getBatteryInfo(context, batteryBroadcast, stats, estimate, elapsedRealtimeUs, - shortString); + return getBatteryInfo(context, batteryBroadcast, batteryUsageStats, estimate, + elapsedRealtimeUs, shortString); } @WorkerThread public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast, - BatteryStats stats, Estimate estimate, long elapsedRealtimeUs, boolean shortString) { + @NonNull BatteryUsageStats batteryUsageStats, Estimate estimate, + long elapsedRealtimeUs, boolean shortString) { final long startTime = System.currentTimeMillis(); BatteryInfo info = new BatteryInfo(); - info.mStats = stats; + info.mBatteryUsageStats = batteryUsageStats; info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast); info.batteryPercentString = Utils.formatPercentage(info.batteryLevel); info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; @@ -241,16 +241,17 @@ public class BatteryInfo { if (!info.mCharging) { updateBatteryInfoDischarging(context, shortString, estimate, info); } else { - updateBatteryInfoCharging(context, batteryBroadcast, stats, elapsedRealtimeUs, info); + updateBatteryInfoCharging(context, batteryBroadcast, batteryUsageStats, + info); } BatteryUtils.logRuntime(LOG_TAG, "time for getBatteryInfo", startTime); return info; } private static void updateBatteryInfoCharging(Context context, Intent batteryBroadcast, - BatteryStats stats, long elapsedRealtimeUs, BatteryInfo info) { + BatteryUsageStats stats, BatteryInfo info) { final Resources resources = context.getResources(); - final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs); + final long chargeTimeMs = stats.getChargeTimeRemainingMs(); final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN); info.discharging = false; @@ -260,8 +261,8 @@ public class BatteryInfo { int chargingLimitedResId = R.string.power_charging_limited; info.chargeLabel = context.getString(chargingLimitedResId, info.batteryPercentString); - } else if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) { - info.remainingTimeUs = chargeTime; + } else if (chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL) { + info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs); CharSequence timeString = StringUtil.formatElapsedTime(context, PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */); int resId = R.string.power_charging_duration; @@ -313,7 +314,11 @@ public class BatteryInfo { void onParsingDone(); } - public static void parse(BatteryStats stats, BatteryDataParser... parsers) { + /** + * Iterates over battery history included in the BatteryUsageStats that this object + * was initialized with. + */ + public void parseBatteryHistory(BatteryDataParser... parsers) { long startWalltime = 0; long endWalltime = 0; long historyStart = 0; @@ -324,41 +329,41 @@ public class BatteryInfo { int lastInteresting = 0; int pos = 0; boolean first = true; - if (stats.startIteratingHistoryLocked()) { - final HistoryItem rec = new HistoryItem(); - while (stats.getNextHistoryLocked(rec)) { - pos++; - if (first) { - first = false; - historyStart = rec.time; + final BatteryStatsHistoryIterator iterator1 = + mBatteryUsageStats.iterateBatteryStatsHistory(); + final HistoryItem rec = new HistoryItem(); + while (iterator1.next(rec)) { + pos++; + if (first) { + first = false; + historyStart = rec.time; + } + if (rec.cmd == HistoryItem.CMD_CURRENT_TIME + || rec.cmd == HistoryItem.CMD_RESET) { + // If there is a ridiculously large jump in time, then we won't be + // able to create a good chart with that data, so just ignore the + // times we got before and pretend like our data extends back from + // the time we have now. + // Also, if we are getting a time change and we are less than 5 minutes + // since the start of the history real time, then also use this new + // time to compute the base time, since whatever time we had before is + // pretty much just noise. + if (rec.currentTime > (lastWallTime + (180 * 24 * 60 * 60 * 1000L)) + || rec.time < (historyStart + (5 * 60 * 1000L))) { + startWalltime = 0; } - if (rec.cmd == HistoryItem.CMD_CURRENT_TIME - || rec.cmd == HistoryItem.CMD_RESET) { - // If there is a ridiculously large jump in time, then we won't be - // able to create a good chart with that data, so just ignore the - // times we got before and pretend like our data extends back from - // the time we have now. - // Also, if we are getting a time change and we are less than 5 minutes - // since the start of the history real time, then also use this new - // time to compute the base time, since whatever time we had before is - // pretty much just noise. - if (rec.currentTime > (lastWallTime + (180 * 24 * 60 * 60 * 1000L)) - || rec.time < (historyStart + (5 * 60 * 1000L))) { - startWalltime = 0; - } - lastWallTime = rec.currentTime; - lastRealtime = rec.time; - if (startWalltime == 0) { - startWalltime = lastWallTime - (lastRealtime - historyStart); - } - } - if (rec.isDeltaData()) { - lastInteresting = pos; - historyEnd = rec.time; + lastWallTime = rec.currentTime; + lastRealtime = rec.time; + if (startWalltime == 0) { + startWalltime = lastWallTime - (lastRealtime - historyStart); } } + if (rec.isDeltaData()) { + lastInteresting = pos; + historyEnd = rec.time; + } } - stats.finishIteratingHistoryLocked(); + endWalltime = lastWallTime + historyEnd - lastRealtime; int i = 0; @@ -367,9 +372,11 @@ public class BatteryInfo { for (int j = 0; j < parsers.length; j++) { parsers[j].onParsingStarted(startWalltime, endWalltime); } - if (endWalltime > startWalltime && stats.startIteratingHistoryLocked()) { - final HistoryItem rec = new HistoryItem(); - while (stats.getNextHistoryLocked(rec) && i < N) { + + if (endWalltime > startWalltime) { + final BatteryStatsHistoryIterator iterator2 = + mBatteryUsageStats.iterateBatteryStatsHistory(); + while (iterator2.next(rec) && i < N) { if (rec.isDeltaData()) { curWalltime += rec.time - lastRealtime; lastRealtime = rec.time; @@ -404,8 +411,6 @@ public class BatteryInfo { } } - stats.finishIteratingHistoryLocked(); - for (int j = 0; j < parsers.length; j++) { parsers[j].onParsingDone(); } diff --git a/src/com/android/settings/fuelgauge/BatteryInfoLoader.java b/src/com/android/settings/fuelgauge/BatteryInfoLoader.java index cd87612ea7b..ffee4627f70 100644 --- a/src/com/android/settings/fuelgauge/BatteryInfoLoader.java +++ b/src/com/android/settings/fuelgauge/BatteryInfoLoader.java @@ -19,7 +19,6 @@ import android.content.Context; import androidx.annotation.VisibleForTesting; -import com.android.internal.os.BatteryStatsHelper; import com.android.settingslib.utils.AsyncLoaderCompat; /** @@ -28,17 +27,14 @@ import com.android.settingslib.utils.AsyncLoaderCompat; * when not available. */ public class BatteryInfoLoader extends AsyncLoaderCompat{ - - BatteryStatsHelper mStatsHelper; private static final String LOG_TAG = "BatteryInfoLoader"; @VisibleForTesting - BatteryUtils batteryUtils; + BatteryUtils mBatteryUtils; - public BatteryInfoLoader(Context context, BatteryStatsHelper batteryStatsHelper) { + public BatteryInfoLoader(Context context) { super(context); - mStatsHelper = batteryStatsHelper; - batteryUtils = BatteryUtils.getInstance(context); + mBatteryUtils = BatteryUtils.getInstance(context); } @Override @@ -48,6 +44,6 @@ public class BatteryInfoLoader extends AsyncLoaderCompat{ @Override public BatteryInfo loadInBackground() { - return batteryUtils.getBatteryInfo(mStatsHelper, LOG_TAG); + return mBatteryUtils.getBatteryInfo(LOG_TAG); } } diff --git a/src/com/android/settings/fuelgauge/BatteryUsageStatsLoader.java b/src/com/android/settings/fuelgauge/BatteryUsageStatsLoader.java index 5b184a9cd52..d35ef82b818 100644 --- a/src/com/android/settings/fuelgauge/BatteryUsageStatsLoader.java +++ b/src/com/android/settings/fuelgauge/BatteryUsageStatsLoader.java @@ -19,6 +19,7 @@ package com.android.settings.fuelgauge; import android.content.Context; import android.os.BatteryStatsManager; import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; import com.android.settingslib.utils.AsyncLoaderCompat; @@ -27,15 +28,21 @@ import com.android.settingslib.utils.AsyncLoaderCompat; */ public class BatteryUsageStatsLoader extends AsyncLoaderCompat { private final BatteryStatsManager mBatteryStatsManager; + private final boolean mIncludeBatteryHistory; - public BatteryUsageStatsLoader(Context context) { + public BatteryUsageStatsLoader(Context context, boolean includeBatteryHistory) { super(context); mBatteryStatsManager = context.getSystemService(BatteryStatsManager.class); + mIncludeBatteryHistory = includeBatteryHistory; } @Override public BatteryUsageStats loadInBackground() { - return mBatteryStatsManager.getBatteryUsageStats(); + final BatteryUsageStatsQuery.Builder builder = new BatteryUsageStatsQuery.Builder(); + if (mIncludeBatteryHistory) { + builder.includeBatteryHistory(); + } + return mBatteryStatsManager.getBatteryUsageStats(builder.build()); } @Override diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 5b1f096d2e7..8c0ab46a347 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -24,6 +24,9 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.BatteryStats; +import android.os.BatteryStatsManager; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; import android.os.Build; import android.os.Bundle; import android.os.Process; @@ -103,7 +106,7 @@ public class BatteryUtils { } @VisibleForTesting - BatteryUtils(Context context) { + public BatteryUtils(Context context) { mContext = context; mPackageManager = context.getPackageManager(); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); @@ -472,29 +475,35 @@ public class BatteryUtils { } @WorkerThread - public BatteryInfo getBatteryInfo(final BatteryStatsHelper statsHelper, final String tag) { + public BatteryInfo getBatteryInfo(final String tag) { + final BatteryStatsManager systemService = mContext.getSystemService( + BatteryStatsManager.class); + final BatteryUsageStats batteryUsageStats = systemService.getBatteryUsageStats( + new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build()); + final long startTime = System.currentTimeMillis(); // Stuff we always need to get BatteryInfo final Intent batteryBroadcast = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + final long elapsedRealtimeUs = PowerUtil.convertMsToUs( SystemClock.elapsedRealtime()); - final BatteryStats stats = statsHelper.getStats(); + BatteryInfo batteryInfo; Estimate estimate = getEnhancedEstimate(); // couldn't get estimate from cache or provider, use fallback if (estimate == null) { estimate = new Estimate( - PowerUtil.convertUsToMs(stats.computeBatteryTimeRemaining(elapsedRealtimeUs)), + PowerUtil.convertUsToMs(batteryUsageStats.getBatteryTimeRemainingMs()), false /* isBasedOnUsage */, EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); } BatteryUtils.logRuntime(tag, "BatteryInfoLoader post query", startTime); - batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast, stats, - estimate, elapsedRealtimeUs, false /* shortString */); + batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast, + batteryUsageStats, estimate, elapsedRealtimeUs, false /* shortString */); BatteryUtils.logRuntime(tag, "BatteryInfoLoader.loadInBackground", startTime); return batteryInfo; diff --git a/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java b/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java index c8dbb59a4bb..0623bcb814d 100644 --- a/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java +++ b/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java @@ -19,6 +19,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryStats; +import android.os.BatteryStatsManager; +import android.os.BatteryUsageStats; import android.os.SystemClock; import com.android.internal.os.BatteryStatsHelper; @@ -56,15 +58,17 @@ public class DebugEstimatesLoader extends AsyncLoaderCompat> { Intent batteryBroadcast = getContext().registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); BatteryStats stats = mStatsHelper.getStats(); - + BatteryUsageStats batteryUsageStats = + context.getSystemService(BatteryStatsManager.class).getBatteryUsageStats(); BatteryInfo oldinfo = BatteryInfo.getBatteryInfoOld(getContext(), batteryBroadcast, - stats, elapsedRealtimeUs, false); + batteryUsageStats, elapsedRealtimeUs, false); Estimate estimate = powerUsageFeatureProvider.getEnhancedBatteryPrediction(context); if (estimate == null) { estimate = new Estimate(0, false, EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); } - BatteryInfo newInfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast, stats, + BatteryInfo newInfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast, + batteryUsageStats, estimate, elapsedRealtimeUs, false); List infos = new ArrayList<>(); diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java index befede46b9b..86e52d9555f 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java +++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java @@ -141,6 +141,11 @@ public class PowerUsageAdvanced extends PowerUsageBase { return controllers; } + @Override + protected boolean isBatteryHistoryNeeded() { + return true; + } + @Override protected void refreshUi(@BatteryUpdateType int refreshType) { final Context context = getContext(); diff --git a/src/com/android/settings/fuelgauge/PowerUsageBase.java b/src/com/android/settings/fuelgauge/PowerUsageBase.java index 3a5ed6cd3af..29ecedc2f10 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageBase.java +++ b/src/com/android/settings/fuelgauge/PowerUsageBase.java @@ -19,10 +19,12 @@ import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpd import android.app.Activity; import android.content.Context; +import android.os.BatteryUsageStats; import android.os.Bundle; import android.os.UserManager; import android.view.Menu; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; @@ -40,12 +42,29 @@ public abstract class PowerUsageBase extends DashboardFragment { static final int MENU_STATS_REFRESH = Menu.FIRST + 1; private static final String TAG = "PowerUsageBase"; private static final String KEY_REFRESH_TYPE = "refresh_type"; + private static final String KEY_INCLUDE_HISTORY = "include_history"; + + private static final int LOADER_BATTERY_STATS_HELPER = 0; + private static final int LOADER_BATTERY_USAGE_STATS = 1; protected BatteryStatsHelper mStatsHelper; + @VisibleForTesting + BatteryUsageStats mBatteryUsageStats; + protected UserManager mUm; private BatteryBroadcastReceiver mBatteryBroadcastReceiver; protected boolean mIsBatteryPresent = true; + // TODO(b/180630447): switch to BatteryUsageStatsLoader and remove all references to + // BatteryStatsHelper and BatterySipper + @VisibleForTesting + final BatteryStatsHelperLoaderCallbacks mBatteryStatsHelperLoaderCallbacks = + new BatteryStatsHelperLoaderCallbacks(); + + @VisibleForTesting + final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks = + new BatteryUsageStatsLoaderCallbacks(); + @Override public void onAttach(Activity activity) { super.onAttach(activity); @@ -83,42 +102,73 @@ public abstract class PowerUsageBase extends DashboardFragment { protected void restartBatteryStatsLoader(int refreshType) { final Bundle bundle = new Bundle(); bundle.putInt(KEY_REFRESH_TYPE, refreshType); + bundle.putBoolean(KEY_INCLUDE_HISTORY, isBatteryHistoryNeeded()); + getLoaderManager().restartLoader(LOADER_BATTERY_STATS_HELPER, bundle, + mBatteryStatsHelperLoaderCallbacks); + getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle, + mBatteryUsageStatsLoaderCallbacks); + } - getLoaderManager().restartLoader(0, bundle, new PowerLoaderCallback()); + private void onLoadFinished(@BatteryUpdateType int refreshType) { + // Wait for both loaders to finish before proceeding. + if (mStatsHelper == null || mBatteryUsageStats == null) { + return; + } + + refreshUi(refreshType); } protected abstract void refreshUi(@BatteryUpdateType int refreshType); + protected abstract boolean isBatteryHistoryNeeded(); protected void updatePreference(BatteryHistoryPreference historyPref) { final long startTime = System.currentTimeMillis(); - historyPref.setStats(mStatsHelper); + historyPref.setBatteryUsageStats(mBatteryUsageStats); BatteryUtils.logRuntime(TAG, "updatePreference", startTime); } - /** - * {@link android.app.LoaderManager.LoaderCallbacks} for {@link PowerUsageBase} to load - * the {@link BatteryStatsHelper} - */ - public class PowerLoaderCallback implements LoaderManager.LoaderCallbacks { + private class BatteryStatsHelperLoaderCallbacks + implements LoaderManager.LoaderCallbacks { private int mRefreshType; @Override - public Loader onCreateLoader(int id, - Bundle args) { + public Loader onCreateLoader(int id, Bundle args) { mRefreshType = args.getInt(KEY_REFRESH_TYPE); return new BatteryStatsHelperLoader(getContext()); } @Override public void onLoadFinished(Loader loader, - BatteryStatsHelper statsHelper) { - mStatsHelper = statsHelper; - refreshUi(mRefreshType); + BatteryStatsHelper batteryHelper) { + mStatsHelper = batteryHelper; + PowerUsageBase.this.onLoadFinished(mRefreshType); } @Override public void onLoaderReset(Loader loader) { + } + } + private class BatteryUsageStatsLoaderCallbacks + implements LoaderManager.LoaderCallbacks { + private int mRefreshType; + + @Override + @NonNull + public Loader onCreateLoader(int id, Bundle args) { + mRefreshType = args.getInt(KEY_REFRESH_TYPE); + return new BatteryUsageStatsLoader(getContext(), args.getBoolean(KEY_INCLUDE_HISTORY)); + } + + @Override + public void onLoadFinished(Loader loader, + BatteryUsageStats batteryUsageStats) { + mBatteryUsageStats = batteryUsageStats; + PowerUsageBase.this.onLoadFinished(mRefreshType); + } + + @Override + public void onLoaderReset(Loader loader) { } } } diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index c00c1313e82..4f8ac628092 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -88,7 +88,7 @@ public class PowerUsageSummary extends PowerUsageBase implements @Override public Loader onCreateLoader(int i, Bundle bundle) { - return new BatteryInfoLoader(getContext(), mStatsHelper); + return new BatteryInfoLoader(getContext()); } @Override @@ -190,6 +190,11 @@ public class PowerUsageSummary extends PowerUsageBase implements return R.string.help_url_battery; } + @Override + protected boolean isBatteryHistoryNeeded() { + return false; + } + protected void refreshUi(@BatteryUpdateType int refreshType) { final Context context = getContext(); if (context == null) { diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java index 0c916b2d4a9..9b80a1f4029 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java @@ -65,12 +65,11 @@ public class BatteryTipLoader extends AsyncLoaderCompat> { } final List tips = new ArrayList<>(); final BatteryTipPolicy policy = new BatteryTipPolicy(getContext()); - final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(mBatteryStatsHelper, TAG); + final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(TAG); final Context context = getContext(); tips.add(new LowBatteryDetector(context, policy, batteryInfo).detect()); - tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper, - batteryInfo.discharging).detect()); + tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper, batteryInfo).detect()); tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect()); tips.add(new EarlyWarningDetector(policy, context).detect()); tips.add(new BatteryDefenderDetector(batteryInfo).detect()); diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java index 067046ca852..928ae52532c 100644 --- a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java @@ -45,6 +45,7 @@ import java.util.concurrent.TimeUnit; public class HighUsageDetector implements BatteryTipDetector { private BatteryTipPolicy mPolicy; private BatteryStatsHelper mBatteryStatsHelper; + private final BatteryInfo mBatteryInfo; private List mHighUsageAppList; @VisibleForTesting HighUsageDataParser mDataParser; @@ -54,14 +55,15 @@ public class HighUsageDetector implements BatteryTipDetector { boolean mDischarging; public HighUsageDetector(Context context, BatteryTipPolicy policy, - BatteryStatsHelper batteryStatsHelper, boolean discharging) { + BatteryStatsHelper batteryStatsHelper, BatteryInfo batteryInfo) { mPolicy = policy; mBatteryStatsHelper = batteryStatsHelper; + mBatteryInfo = batteryInfo; mHighUsageAppList = new ArrayList<>(); mBatteryUtils = BatteryUtils.getInstance(context); mDataParser = new HighUsageDataParser(mPolicy.highUsagePeriodMs, mPolicy.highUsageBatteryDraining); - mDischarging = discharging; + mDischarging = batteryInfo.discharging; } @Override @@ -115,6 +117,6 @@ public class HighUsageDetector implements BatteryTipDetector { @VisibleForTesting void parseBatteryData() { - BatteryInfo.parse(mBatteryStatsHelper.getStats(), mDataParser); + mBatteryInfo.parseBatteryHistory(mDataParser); } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoLoaderTest.java index 6593767a44d..5bcaf0a5cce 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoLoaderTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoLoaderTest.java @@ -19,23 +19,23 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; -import android.os.BatteryStats; +import android.os.BatteryStatsManager; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.testutils.BatteryTestUtils; import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; @@ -46,10 +46,10 @@ public class BatteryInfoLoaderTest { private static final long TEST_TIME_REMAINING = 1000L; - @Mock (answer = Answers.RETURNS_DEEP_STUBS) - private BatteryStatsHelper mHelper; - @Mock (answer = Answers.RETURNS_DEEP_STUBS) - private BatteryStats mStats; + @Mock + private BatteryStatsManager mBatteryStatsManager; + @Mock + private BatteryUsageStats mBatteryUsageStats; private Context mContext; @@ -60,8 +60,11 @@ public class BatteryInfoLoaderTest { FakeFeatureFactory.setupForTest().getPowerUsageFeatureProvider(mContext); doReturn(mContext).when(mContext).getApplicationContext(); - when(mStats.computeBatteryTimeRemaining(anyLong())).thenReturn(TEST_TIME_REMAINING); - doReturn(mStats).when(mHelper).getStats(); + when(mContext.getSystemService(eq(Context.BATTERY_STATS_SERVICE))) + .thenReturn(mBatteryStatsManager); + when(mBatteryUsageStats.getBatteryTimeRemainingMs()).thenReturn(TEST_TIME_REMAINING); + when(mBatteryStatsManager.getBatteryUsageStats(any(BatteryUsageStatsQuery.class))) + .thenReturn(mBatteryUsageStats); final Intent dischargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent(); doReturn(dischargingBatteryBroadcast).when(mContext).registerReceiver(any(), any()); @@ -69,8 +72,8 @@ public class BatteryInfoLoaderTest { @Test public void test_loadInBackground_dischargingOldEstimate_dischargingLabelNotNull() { - BatteryInfoLoader loader = new BatteryInfoLoader(mContext, mHelper); - loader.batteryUtils = new BatteryUtils(mContext); + BatteryInfoLoader loader = new BatteryInfoLoader(mContext); + loader.mBatteryUtils = new BatteryUtils(mContext); BatteryInfo info = loader.loadInBackground(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java index 4c19477d7a9..18c53266438 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java @@ -34,9 +34,11 @@ import android.content.Context; import android.content.Intent; import android.os.BatteryManager; import android.os.BatteryStats; +import android.os.BatteryUsageStats; import android.os.SystemClock; import android.util.SparseIntArray; +import com.android.internal.os.BatteryStatsHistoryIterator; import com.android.settings.testutils.BatteryTestUtils; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.widget.UsageView; @@ -46,7 +48,6 @@ import com.android.settingslib.fuelgauge.Estimate; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -83,9 +84,8 @@ public class BatteryInfoTest { private Intent mChargingBatteryBroadcast; private Context mContext; private FakeFeatureFactory mFeatureFactory; - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private BatteryStats mBatteryStats; + @Mock + private BatteryUsageStats mBatteryUsageStats; @Before public void setUp() { @@ -100,9 +100,10 @@ public class BatteryInfoTest { @Test public void testGetBatteryInfo_hasStatusLabel() { - doReturn(REMAINING_TIME_NULL).when(mBatteryStats).computeBatteryTimeRemaining(anyLong()); + doReturn(REMAINING_TIME_NULL).when(mBatteryUsageStats).getBatteryTimeRemainingMs(); BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, - mDisChargingBatteryBroadcast, mBatteryStats, SystemClock.elapsedRealtime() * 1000, + mDisChargingBatteryBroadcast, mBatteryUsageStats, + SystemClock.elapsedRealtime() * 1000, true /* shortString */); assertThat(info.statusLabel).isEqualTo(STATUS_NOT_CHARGING); @@ -110,28 +111,28 @@ public class BatteryInfoTest { @Test public void testGetBatteryInfo_doNotShowChargingMethod_hasRemainingTime() { - doReturn(REMAINING_TIME).when(mBatteryStats).computeChargeTimeRemaining(anyLong()); + doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs(); BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast, - mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */); + mBatteryUsageStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */); assertThat(info.chargeLabel.toString()).isEqualTo(STATUS_CHARGING_TIME); } @Test public void testGetBatteryInfo_doNotShowChargingMethod_noRemainingTime() { - doReturn(REMAINING_TIME_NULL).when(mBatteryStats).computeChargeTimeRemaining(anyLong()); + doReturn(REMAINING_TIME_NULL).when(mBatteryUsageStats).getChargeTimeRemainingMs(); BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast, - mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */); + mBatteryUsageStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */); assertThat(info.chargeLabel.toString()).isEqualTo(STATUS_CHARGING_NO_TIME); } @Test public void testGetBatteryInfo_pluggedInUsingShortString_usesCorrectData() { - doReturn(TEST_CHARGE_TIME_REMAINING).when(mBatteryStats).computeChargeTimeRemaining( - anyLong()); + doReturn(TEST_CHARGE_TIME_REMAINING / 1000) + .when(mBatteryUsageStats).getChargeTimeRemainingMs(); BatteryInfo info = BatteryInfo.getBatteryInfoOld(mContext, mChargingBatteryBroadcast, - mBatteryStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */); + mBatteryUsageStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */); assertThat(info.discharging).isEqualTo(false); assertThat(info.chargeLabel.toString()).isEqualTo("50% - 1 min until charged"); @@ -143,10 +144,10 @@ public class BatteryInfoTest { true /* isBasedOnUsage */, 1000 /* averageDischargeTime */); BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, - mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000, false /* shortString */); BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, - mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000, true /* shortString */); // We only add special mention for the long string @@ -163,10 +164,10 @@ public class BatteryInfoTest { true /* isBasedOnUsage */, 1000 /* averageDischargeTime */); BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, - mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000, false /* shortString */); BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, - mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000, true /* shortString */); // These should be identical in either case @@ -183,7 +184,7 @@ public class BatteryInfoTest { true /* isBasedOnUsage */, 1000 /* averageDischargeTime */); BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, - mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000, false /* shortString */); assertThat(info.suggestionLabel).doesNotContain(BATTERY_RUN_OUT_PREFIX); @@ -196,7 +197,7 @@ public class BatteryInfoTest { true /* isBasedOnUsage */, 1000 /* averageDischargeTime */); BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, - mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000, false /* shortString */); // Check that strings are showing less than 15 minutes remaining regardless of exact time. @@ -211,10 +212,10 @@ public class BatteryInfoTest { @Test public void testGetBatteryInfo_basedOnUsageFalse_usesDefaultString() { BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, - mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, false /* shortString */); BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast, - mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, true /* shortString */); assertThat(info.remainingLabel.toString()).doesNotContain(ENHANCED_STRING_SUFFIX); @@ -223,12 +224,11 @@ public class BatteryInfoTest { @Test public void testGetBatteryInfo_charging_usesChargeTime() { - doReturn(TEST_CHARGE_TIME_REMAINING) - .when(mBatteryStats) - .computeChargeTimeRemaining(anyLong()); + doReturn(TEST_CHARGE_TIME_REMAINING / 1000) + .when(mBatteryUsageStats).getChargeTimeRemainingMs(); BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, - mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, false /* shortString */); assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING); assertThat(info.remainingLabel.toString()) @@ -240,7 +240,7 @@ public class BatteryInfoTest { mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_LEVEL, 100); BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, - mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, false /* shortString */); assertThat(info.chargeLabel).isEqualTo("100%"); @@ -249,13 +249,13 @@ public class BatteryInfoTest { @Test public void testGetBatteryInfo_chargingWithOverheated_updateChargeLabel() { doReturn(TEST_CHARGE_TIME_REMAINING) - .when(mBatteryStats) - .computeChargeTimeRemaining(anyLong()); + .when(mBatteryUsageStats) + .getChargeTimeRemainingMs(); mChargingBatteryBroadcast .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT); BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, - mBatteryStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, + mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000, false /* shortString */); assertThat(info.isOverheated).isTrue(); @@ -264,28 +264,29 @@ public class BatteryInfoTest { // Make our battery stats return a sequence of battery events. private void mockBatteryStatsHistory() { - // Mock out new data every time start...Locked is called. + // Mock out new data every time iterateBatteryStatsHistory is called. doAnswer(invocation -> { - doAnswer(new Answer() { - private int count = 0; - private long[] times = {1000, 1500, 2000}; - private byte[] levels = {99, 98, 97}; + BatteryStatsHistoryIterator iterator = mock(BatteryStatsHistoryIterator.class); + doAnswer(new Answer() { + private int mCount = 0; + private final long[] mTimes = {1000, 1500, 2000}; + private final byte[] mLevels = {99, 98, 97}; @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - if (count == times.length) { + public Boolean answer(InvocationOnMock invocation) throws Throwable { + if (mCount == mTimes.length) { return false; } BatteryStats.HistoryItem record = invocation.getArgument(0); record.cmd = BatteryStats.HistoryItem.CMD_UPDATE; - record.time = times[count]; - record.batteryLevel = levels[count]; - count++; + record.time = mTimes[mCount]; + record.batteryLevel = mLevels[mCount]; + mCount++; return true; } - }).when(mBatteryStats).getNextHistoryLocked(any(BatteryStats.HistoryItem.class)); - return true; - }).when(mBatteryStats).startIteratingHistoryLocked(); + }).when(iterator).next(any(BatteryStats.HistoryItem.class)); + return iterator; + }).when(mBatteryUsageStats).iterateBatteryStatsHistory(); } private void assertOnlyHistory(BatteryInfo info) { @@ -337,9 +338,9 @@ public class BatteryInfoTest { private BatteryInfo getBatteryInfo(boolean charging, boolean enhanced, boolean estimate) { if (charging && estimate) { - doReturn(1000L).when(mBatteryStats).computeChargeTimeRemaining(anyLong()); + doReturn(1000L).when(mBatteryUsageStats).getChargeTimeRemainingMs(); } else { - doReturn(0L).when(mBatteryStats).computeChargeTimeRemaining(anyLong()); + doReturn(0L).when(mBatteryUsageStats).getChargeTimeRemainingMs(); } Estimate batteryEstimate = new Estimate( estimate ? 1000 : 0, @@ -347,7 +348,7 @@ public class BatteryInfoTest { 1000 /* averageDischargeTime */); BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, charging ? mChargingBatteryBroadcast : mDisChargingBatteryBroadcast, - mBatteryStats, batteryEstimate, SystemClock.elapsedRealtime() * 1000, false); + mBatteryUsageStats, batteryEstimate, SystemClock.elapsedRealtime() * 1000, false); doReturn(enhanced).when(mFeatureFactory.powerUsageFeatureProvider) .isEnhancedBatteryPredictionEnabled(mContext); return info; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java index f393da8b65c..c8fdf8c9562 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java @@ -48,6 +48,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.BatteryStats; +import android.os.BatteryStatsManager; import android.os.Build; import android.os.Bundle; import android.os.Process; @@ -157,6 +158,8 @@ public class BatteryUtilsTest { private ApplicationInfo mApplicationInfo; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private BatteryStatsHelper mBatteryStatsHelper; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private BatteryStatsManager mBatteryStatsManager; @Mock private ApplicationInfo mHighApplicationInfo; @Mock @@ -228,6 +231,8 @@ public class BatteryUtilsTest { mContext = spy(RuntimeEnvironment.application); doReturn(mPackageManager).when(mContext).getPackageManager(); doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE); + doReturn(mBatteryStatsManager).when(mContext) + .getSystemService(Context.BATTERY_STATS_SERVICE); mBatteryUtils = spy(new BatteryUtils(mContext)); mBatteryUtils.mPowerUsageFeatureProvider = mProvider; doReturn(0L).when(mBatteryUtils) @@ -741,7 +746,7 @@ public class BatteryUtilsTest { any(IntentFilter.class))).thenReturn(new Intent()); //Should not crash - assertThat(mBatteryUtils.getBatteryInfo(mBatteryStatsHelper, TAG)).isNotNull(); + assertThat(mBatteryUtils.getBatteryInfo(TAG)).isNotNull(); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java index cd1b1780d2c..87547008d2f 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java @@ -74,6 +74,11 @@ public class PowerUsageBaseTest { return 0; } + @Override + protected boolean isBatteryHistoryNeeded() { + return false; + } + @Override protected void refreshUi(int refreshType) { // Do nothing diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java index 8cc17d8d98f..c97d79ff2a1 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java @@ -77,7 +77,7 @@ public class BatteryTipLoaderTest { doReturn(mContext).when(mContext).getApplicationContext(); doReturn(mPowerManager).when(mContext).getSystemService(Context.POWER_SERVICE); doReturn(mIntent).when(mContext).registerReceiver(any(), any()); - doReturn(mBatteryInfo).when(mBatteryUtils).getBatteryInfo(any(), any()); + doReturn(mBatteryInfo).when(mBatteryUtils).getBatteryInfo(any()); mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryStatsHelper); mBatteryTipLoader.mBatteryUtils = mBatteryUtils; } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java index 5c56f46c4bd..93005d51093 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java @@ -18,7 +18,9 @@ package com.android.settings.fuelgauge.batterytip.detectors; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -26,8 +28,11 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.Intent; import android.os.BatteryStats; -import android.text.format.DateUtils; +import android.os.BatteryStatsManager; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; @@ -53,6 +58,8 @@ import java.util.List; @RunWith(RobolectricTestRunner.class) public class HighUsageDetectorTest { + private static final String TAG = "HighUsageDetectorTest"; + private static final int UID_HIGH = 123; private static final int UID_LOW = 345; private static final double POWER_HIGH = 20000; @@ -68,6 +75,10 @@ public class HighUsageDetectorTest { private BatterySipper mSystemBatterySipper; @Mock private HighUsageDataParser mDataParser; + @Mock + private BatteryUsageStats mBatteryUsageStats; + @Mock + private BatteryStatsManager mBatteryStatsManager; private AppInfo mHighAppInfo; private AppInfo mLowAppInfo; @@ -80,11 +91,19 @@ public class HighUsageDetectorTest { public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); mPolicy = spy(new BatteryTipPolicy(mContext)); - mBatteryUtils = spy(BatteryUtils.getInstance(mContext)); + mBatteryUtils = spy(new BatteryUtils(mContext)); + + when(mContext.getSystemService(eq(Context.BATTERY_STATS_SERVICE))) + .thenReturn(mBatteryStatsManager); + when(mBatteryStatsManager.getBatteryUsageStats(any(BatteryUsageStatsQuery.class))) + .thenReturn(mBatteryUsageStats); + + mContext.sendStickyBroadcast(new Intent(Intent.ACTION_BATTERY_CHANGED)); + mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper, - true /* mDischarging */)); + mBatteryUtils.getBatteryInfo(TAG))); mHighUsageDetector.mBatteryUtils = mBatteryUtils; mHighUsageDetector.mDataParser = mDataParser; doNothing().when(mHighUsageDetector).parseBatteryData(); From d8df0d97e206bf89b273c8e3a6c9bc407f7b593f Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Mon, 8 Mar 2021 20:25:49 -0800 Subject: [PATCH 4/4] Move WiFi/Bluetooth scanning toggles to new pages Screenshots: http://shortn/_ZmO6y9Zi5S Bug: 180533061 Test: on device Change-Id: I1223c9f5641bcc24b3e16af45138643f62849b8b --- res/values/strings.xml | 4 + res/xml/location_services.xml | 24 +++--- .../location_services_bluetooth_scanning.xml | 32 ++++++++ res/xml/location_services_wifi_scanning.xml | 32 ++++++++ .../location/BluetoothScanningFragment.java | 81 +++++++++++++++++++ ...canningMainSwitchPreferenceController.java | 76 +++++++++++++++++ ...BluetoothScanningPreferenceController.java | 49 +++++++++++ ...vicesWifiScanningPreferenceController.java | 50 ++++++++++++ .../location/WifiScanningFragment.java | 81 +++++++++++++++++++ ...canningMainSwitchPreferenceController.java | 77 ++++++++++++++++++ 10 files changed, 494 insertions(+), 12 deletions(-) create mode 100644 res/xml/location_services_bluetooth_scanning.xml create mode 100644 res/xml/location_services_wifi_scanning.xml create mode 100644 src/com/android/settings/location/BluetoothScanningFragment.java create mode 100644 src/com/android/settings/location/BluetoothScanningMainSwitchPreferenceController.java create mode 100644 src/com/android/settings/location/LocationServicesBluetoothScanningPreferenceController.java create mode 100644 src/com/android/settings/location/LocationServicesWifiScanningPreferenceController.java create mode 100644 src/com/android/settings/location/WifiScanningFragment.java create mode 100644 src/com/android/settings/location/WifiScanningMainSwitchPreferenceController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 9fe106b149a..a2f1aa879d0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3186,6 +3186,10 @@ PRL version MEID (sim slot %1$d) + + On + + Off Both Wi\u2011Fi and Bluetooth scanning are on diff --git a/res/xml/location_services.xml b/res/xml/location_services.xml index ef94886f748..516491c5f1e 100644 --- a/res/xml/location_services.xml +++ b/res/xml/location_services.xml @@ -18,21 +18,21 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/location_services_screen_title"> - - - - + + + + diff --git a/res/xml/location_services_bluetooth_scanning.xml b/res/xml/location_services_bluetooth_scanning.xml new file mode 100644 index 00000000000..fb522f0d5dc --- /dev/null +++ b/res/xml/location_services_bluetooth_scanning.xml @@ -0,0 +1,32 @@ + + + + + + + + + + diff --git a/res/xml/location_services_wifi_scanning.xml b/res/xml/location_services_wifi_scanning.xml new file mode 100644 index 00000000000..a436fac7666 --- /dev/null +++ b/res/xml/location_services_wifi_scanning.xml @@ -0,0 +1,32 @@ + + + + + + + + + + diff --git a/src/com/android/settings/location/BluetoothScanningFragment.java b/src/com/android/settings/location/BluetoothScanningFragment.java new file mode 100644 index 00000000000..553f975e2b8 --- /dev/null +++ b/src/com/android/settings/location/BluetoothScanningFragment.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.location; + +import android.app.settings.SettingsEnums; +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.search.SearchIndexable; + +import java.util.ArrayList; +import java.util.List; + +/** + * A page that configures the Bluetooth scanning setting. + */ +@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) +public class BluetoothScanningFragment extends DashboardFragment { + private static final String TAG = "BluetoothScanningFragment"; + + @Override + public int getMetricsCategory() { + return SettingsEnums.LOCATION_SERVICES; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.location_services_bluetooth_scanning; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + } + + private static List buildPreferenceControllers(Context context) { + final List controllers = new ArrayList<>(); + controllers.add(new BluetoothScanningPreferenceController(context)); + return controllers; + } + + /** + * For Search. + */ + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.location_services_bluetooth_scanning) { + + @Override + public List createPreferenceControllers(Context + context) { + return buildPreferenceControllers(context); + } + }; +} diff --git a/src/com/android/settings/location/BluetoothScanningMainSwitchPreferenceController.java b/src/com/android/settings/location/BluetoothScanningMainSwitchPreferenceController.java new file mode 100644 index 00000000000..051fd8d8f1f --- /dev/null +++ b/src/com/android/settings/location/BluetoothScanningMainSwitchPreferenceController.java @@ -0,0 +1,76 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.location; + +import android.content.Context; +import android.provider.Settings; +import android.widget.Switch; + +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.TogglePreferenceController; +import com.android.settingslib.widget.MainSwitchPreference; +import com.android.settingslib.widget.OnMainSwitchChangeListener; + +/** + * Preference controller for Bluetooth scanning main switch. + */ +public class BluetoothScanningMainSwitchPreferenceController extends TogglePreferenceController + implements OnMainSwitchChangeListener { + + private static final String KEY_BLUETOOTH_SCANNING_SWITCH = "bluetooth_always_scanning_switch"; + + public BluetoothScanningMainSwitchPreferenceController(Context context) { + super(context, KEY_BLUETOOTH_SCANNING_SWITCH); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + MainSwitchPreference pref = screen.findPreference(getPreferenceKey()); + pref.addOnSwitchChangeListener(this); + pref.updateStatus(isChecked()); + } + + @Override + public int getAvailabilityStatus() { + return mContext.getResources().getBoolean(R.bool.config_show_location_scanning) + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; + } + + @Override + public boolean isChecked() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1; + } + + @Override + public boolean setChecked(boolean isChecked) { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, isChecked ? 1 : 0); + // Returning true means the underlying setting is updated. + return true; + } + + @Override + public void onSwitchChanged(Switch switchView, boolean isChecked) { + if (isChecked != isChecked()) { + setChecked(isChecked); + } + } +} diff --git a/src/com/android/settings/location/LocationServicesBluetoothScanningPreferenceController.java b/src/com/android/settings/location/LocationServicesBluetoothScanningPreferenceController.java new file mode 100644 index 00000000000..9913848eb23 --- /dev/null +++ b/src/com/android/settings/location/LocationServicesBluetoothScanningPreferenceController.java @@ -0,0 +1,49 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.location; + +import android.content.Context; +import android.provider.Settings; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; + +/** + * Preference controller for Bluetooth scanning in Location Services. + */ +public class LocationServicesBluetoothScanningPreferenceController extends + BasePreferenceController { + + public LocationServicesBluetoothScanningPreferenceController(Context context, String key) { + super(context, key); + } + + @Override + public CharSequence getSummary() { + final boolean bleScanOn = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1; + int resId = + bleScanOn ? R.string.scanning_status_text_on : R.string.scanning_status_text_off; + return mContext.getString(resId); + } + + @AvailabilityStatus + public int getAvailabilityStatus() { + return mContext.getResources().getBoolean(R.bool.config_show_location_scanning) + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; + } +} diff --git a/src/com/android/settings/location/LocationServicesWifiScanningPreferenceController.java b/src/com/android/settings/location/LocationServicesWifiScanningPreferenceController.java new file mode 100644 index 00000000000..080a023268c --- /dev/null +++ b/src/com/android/settings/location/LocationServicesWifiScanningPreferenceController.java @@ -0,0 +1,50 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.location; + +import android.content.Context; +import android.net.wifi.WifiManager; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; + +/** + * Preference controller for Wi-Fi scanning in Location Services. + */ +public class LocationServicesWifiScanningPreferenceController extends BasePreferenceController { + + private final WifiManager mWifiManager; + + public LocationServicesWifiScanningPreferenceController(Context context, String key) { + super(context, key); + mWifiManager = context.getSystemService(WifiManager.class); + } + + @Override + public CharSequence getSummary() { + final boolean wifiScanOn = mWifiManager.isScanAlwaysAvailable(); + int resId = + wifiScanOn ? R.string.scanning_status_text_on : R.string.scanning_status_text_off; + return mContext.getString(resId); + } + + @AvailabilityStatus + public int getAvailabilityStatus() { + return mContext.getResources().getBoolean(R.bool.config_show_location_scanning) + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; + } +} diff --git a/src/com/android/settings/location/WifiScanningFragment.java b/src/com/android/settings/location/WifiScanningFragment.java new file mode 100644 index 00000000000..f5cb0ae2255 --- /dev/null +++ b/src/com/android/settings/location/WifiScanningFragment.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.location; + +import android.app.settings.SettingsEnums; +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.search.SearchIndexable; + +import java.util.ArrayList; +import java.util.List; + +/** + * A page that configures the Wi-Fi scanning setting. + */ +@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) +public class WifiScanningFragment extends DashboardFragment { + private static final String TAG = "WifiScanningFragment"; + + @Override + public int getMetricsCategory() { + return SettingsEnums.LOCATION_SERVICES; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.location_services_wifi_scanning; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + } + + private static List buildPreferenceControllers(Context context) { + final List controllers = new ArrayList<>(); + controllers.add(new WifiScanningPreferenceController(context)); + return controllers; + } + + /** + * For Search. + */ + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.location_services_wifi_scanning) { + + @Override + public List createPreferenceControllers(Context + context) { + return buildPreferenceControllers(context); + } + }; +} diff --git a/src/com/android/settings/location/WifiScanningMainSwitchPreferenceController.java b/src/com/android/settings/location/WifiScanningMainSwitchPreferenceController.java new file mode 100644 index 00000000000..a69fdb8890f --- /dev/null +++ b/src/com/android/settings/location/WifiScanningMainSwitchPreferenceController.java @@ -0,0 +1,77 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.location; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.widget.Switch; + +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.TogglePreferenceController; +import com.android.settingslib.widget.MainSwitchPreference; +import com.android.settingslib.widget.OnMainSwitchChangeListener; + +/** + * Preference controller for Wi-Fi scanning main switch. + */ +public class WifiScanningMainSwitchPreferenceController extends TogglePreferenceController + implements OnMainSwitchChangeListener { + + private static final String KEY_WIFI_SCANNING_SWITCH = "wifi_always_scanning_switch"; + private final WifiManager mWifiManager; + + public WifiScanningMainSwitchPreferenceController(Context context) { + super(context, KEY_WIFI_SCANNING_SWITCH); + mWifiManager = context.getSystemService(WifiManager.class); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + + MainSwitchPreference pref = screen.findPreference(getPreferenceKey()); + pref.addOnSwitchChangeListener(this); + pref.updateStatus(isChecked()); + } + + @Override + public int getAvailabilityStatus() { + return mContext.getResources().getBoolean(R.bool.config_show_location_scanning) + ? AVAILABLE + : UNSUPPORTED_ON_DEVICE; + } + + @Override + public boolean isChecked() { + return mWifiManager.isScanAlwaysAvailable(); + } + + @Override + public boolean setChecked(boolean isChecked) { + mWifiManager.setScanAlwaysAvailable(isChecked); + // Returning true means the underlying setting is updated. + return true; + } + + @Override + public void onSwitchChanged(Switch switchView, boolean isChecked) { + if (isChecked != isChecked()) { + setChecked(isChecked); + } + } +}