diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 8d6ba75eef3..91bb9854b3e 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -16,7 +16,10 @@ package com.android.settings.fuelgauge; +import android.content.Context; import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; import com.android.internal.os.BatterySipper; /** @@ -62,4 +65,24 @@ public interface PowerUsageFeatureProvider { * Check whether the anomaly detection is enabled */ boolean isAnomalyDetectionEnabled(); + + /** + * Returns an improved prediction for battery time remaining. + */ + long getEnhancedBatteryPrediction(Context context); + + /** + * Checks whether the toggle for enhanced battery predictions is enabled. + */ + boolean isEnhancedBatteryPredictionEnabled(Context context); + + /** + * Returns the Uri used to query for an enhanced battery prediction from a cursor loader. + */ + Uri getEnhancedBatteryPredictionUri(); + + /** + * Returns the the estimate in the cursor as a long or -1 if the cursor is null + */ + long getTimeRemainingEstimate(Cursor cursor); } diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index cc29874d843..4ebe10fde9a 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -19,6 +19,8 @@ package com.android.settings.fuelgauge; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; import android.os.Process; import com.android.internal.os.BatterySipper; import com.android.internal.util.ArrayUtils; @@ -89,4 +91,24 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider public boolean isAnomalyDetectionEnabled() { return false; } + + @Override + public long getEnhancedBatteryPrediction(Context context) { + return -1; + } + + @Override + public boolean isEnhancedBatteryPredictionEnabled(Context context) { + return false; + } + + @Override + public Uri getEnhancedBatteryPredictionUri() { + return null; + } + + @Override + public long getTimeRemainingEstimate(Cursor cursor) { + return 0; + } } diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index cd7b336fb6d..5d65031b2ba 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -19,11 +19,15 @@ package com.android.settings.fuelgauge; import android.app.Activity; import android.app.LoaderManager; import android.content.Context; +import android.content.CursorLoader; import android.content.Intent; import android.content.IntentFilter; import android.content.Loader; import android.content.res.TypedArray; +import android.content.res.Resources; +import android.database.Cursor; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.BatteryStats; import android.os.Build; import android.os.Bundle; @@ -38,9 +42,9 @@ import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceGroup; import android.text.TextUtils; import android.text.format.DateUtils; +import android.text.format.Formatter; import android.util.Log; import android.util.SparseArray; -import android.util.TypedValue; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -102,6 +106,7 @@ public class PowerUsageSummary extends PowerUsageBase implements @VisibleForTesting static final int ANOMALY_LOADER = 1; + private static final int BATTERY_ESTIMATE_LOADER = 2; private static final int MENU_STATS_TYPE = Menu.FIRST; @VisibleForTesting static final int MENU_HIGH_POWER_APPS = Menu.FIRST + 3; @@ -124,6 +129,9 @@ public class PowerUsageSummary extends PowerUsageBase implements PowerUsageFeatureProvider mPowerFeatureProvider; @VisibleForTesting BatteryUtils mBatteryUtils; + @VisibleForTesting + long mEnhancedEstimate = -1; + /** * SparseArray that maps uid to {@link Anomaly}, so we could find {@link Anomaly} by uid */ @@ -158,6 +166,40 @@ public class PowerUsageSummary extends PowerUsageBase implements } }; + private LoaderManager.LoaderCallbacks mBatteryPredictionLoaderCallbacks = + new LoaderManager.LoaderCallbacks() { + + @Override + public Loader onCreateLoader(int i, Bundle bundle) { + final Uri queryUri = mPowerFeatureProvider.getEnhancedBatteryPredictionUri(); + return new CursorLoader(getContext(), queryUri, null, null, null, null); + } + + @Override + public void onLoadFinished(Loader loader, Cursor cursor) { + try { + if (cursor != null && cursor.moveToFirst()) { + mEnhancedEstimate = + mPowerFeatureProvider.getTimeRemainingEstimate(cursor); + } + } finally { + cursor.close(); + } + final long elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000; + Intent batteryBroadcast = getContext().registerReceiver(null, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(getContext(), + batteryBroadcast, mStatsHelper.getStats(), elapsedRealtimeUs, false); + useEnhancedEstimateIfAvailable(getContext(), batteryInfo); + updateHeaderPreference(batteryInfo); + } + + @Override + public void onLoaderReset(Loader loader) { + // do nothing + } + }; + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -175,6 +217,10 @@ public class PowerUsageSummary extends PowerUsageBase implements mAnomalySparseArray = new SparseArray<>(); initFeatureProvider(); + if (mPowerFeatureProvider != null) { + getLoaderManager().initLoader(BATTERY_ESTIMATE_LOADER, Bundle.EMPTY, + mBatteryPredictionLoaderCallbacks); + } } @Override @@ -454,6 +500,7 @@ public class PowerUsageSummary extends PowerUsageBase implements new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context, batteryBroadcast, mStatsHelper.getStats(), elapsedRealtimeUs, false); + useEnhancedEstimateIfAvailable(context, batteryInfo); updateHeaderPreference(batteryInfo); final long runningTime = calculateRunningTimeBasedOnStatsType(); @@ -697,6 +744,18 @@ public class PowerUsageSummary extends PowerUsageBase implements } } + @VisibleForTesting + void useEnhancedEstimateIfAvailable(Context context, BatteryInfo batteryInfo) { + if (mEnhancedEstimate > 0) { + final Resources resources = context.getResources(); + batteryInfo.remainingTimeUs = mEnhancedEstimate; + String timeString = Formatter.formatShortElapsedTime(context, mEnhancedEstimate); + batteryInfo.remainingLabel = resources.getString( + com.android.settingslib.R.string.power_remaining_duration_only, + timeString); + } + } + private static List getFakeStats() { ArrayList stats = new ArrayList<>(); float use = 5; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java index bbcd4f281a1..ca45b4bfca2 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java @@ -15,12 +15,14 @@ */ package com.android.settings.fuelgauge; +import java.util.List; +import org.robolectric.RuntimeEnvironment; import android.app.LoaderManager; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.content.ContentResolver; import android.os.PowerManager; -import android.os.Process; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.SparseArray; @@ -51,14 +53,11 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; -import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.ArrayList; -import java.util.List; import static com.android.settings.fuelgauge.PowerUsageSummary.MENU_ADDITIONAL_BATTERY_INFO; import static com.android.settings.fuelgauge.PowerUsageSummary.MENU_HIGH_POWER_APPS; @@ -69,7 +68,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; @@ -146,6 +144,8 @@ public class PowerUsageSummaryTest { private SettingsActivity mSettingsActivity; @Mock private LoaderManager mLoaderManager; + @Mock + private ContentResolver mContentResolver; private List mUsageList; private Context mRealContext; @@ -489,6 +489,21 @@ public class PowerUsageSummaryTest { assertThat(mFragment.mAnomalySparseArray.get(UID_2)).containsExactly(anomaly3); } + @Test + public void testUseEnhancedEstimateIfAvailable() { + // mock out the provider + final long time = 60 * 1000 * 1000; + PowerUsageFeatureProvider provider = mFeatureFactory.getPowerUsageFeatureProvider(mContext); + mFragment.mPowerFeatureProvider = provider; + mFragment.mEnhancedEstimate = time; + + mFragment.useEnhancedEstimateIfAvailable(mRealContext, mBatteryInfo); + + // The string that gets returned always has weird whitespacing to make it fit + // so we're just going to check that it contains the correct value we care about. + assertThat(mBatteryInfo.remainingTimeUs).isEqualTo(time); + assertThat(mBatteryInfo.remainingLabel).contains("About 17 hrs"); + } @Test public void testInitAnomalyDetectionIfPossible_detectionEnabled_init() {