diff --git a/res/layout/battery_header.xml b/res/layout/battery_header.xml
index ca5c90e3219..aeb61e18907 100644
--- a/res/layout/battery_header.xml
+++ b/res/layout/battery_header.xml
@@ -48,6 +48,12 @@
android:layout_marginTop="12dp"
android:textAppearance="@android:style/TextAppearance.Material.Small"/>
+
+
T findViewById(int id) {
return mRootView.findViewById(id);
}
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
index ecf0f9f1460..bdd2413a8e3 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
@@ -48,7 +48,9 @@ public class BatteryHeaderPreferenceController extends PreferenceController
@VisibleForTesting
TextView mTimeText;
@VisibleForTesting
- TextView mSummary;
+ TextView mSummary1;
+ @VisibleForTesting
+ TextView mSummary2;
private final Activity mActivity;
private final PreferenceFragment mHost;
@@ -73,8 +75,9 @@ public class BatteryHeaderPreferenceController extends PreferenceController
mBatteryLayoutPref = (LayoutPreference) screen.findPreference(KEY_BATTERY_HEADER);
mBatteryMeterView = (BatteryMeterView) mBatteryLayoutPref
.findViewById(R.id.battery_header_icon);
- mTimeText = (TextView) mBatteryLayoutPref.findViewById(R.id.battery_percent);
- mSummary = (TextView) mBatteryLayoutPref.findViewById(R.id.summary1);
+ mTimeText = mBatteryLayoutPref.findViewById(R.id.battery_percent);
+ mSummary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
+ mSummary2 = mBatteryLayoutPref.findViewById(R.id.summary2);
Intent batteryBroadcast = mContext.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
@@ -105,10 +108,13 @@ public class BatteryHeaderPreferenceController extends PreferenceController
public void updateHeaderPreference(BatteryInfo info) {
mTimeText.setText(Utils.formatPercentage(info.batteryLevel));
if (info.remainingLabel == null) {
- mSummary.setText(info.statusLabel);
+ mSummary1.setText(info.statusLabel);
} else {
- mSummary.setText(info.remainingLabel);
+ mSummary1.setText(info.remainingLabel);
}
+ // Clear this just to be sure we don't get UI jank on re-entering this view from another
+ // activity.
+ mSummary2.setText("");
mBatteryMeterView.setBatteryLevel(info.batteryLevel);
mBatteryMeterView.setCharging(!info.discharging);
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index 6daf23b5bbc..cb732e30b92 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -30,7 +30,6 @@ import android.text.format.Formatter;
import android.util.SparseIntArray;
import com.android.internal.os.BatteryStatsHelper;
-
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.R;
import com.android.settings.Utils;
diff --git a/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java b/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java
new file mode 100644
index 00000000000..08bd148ee88
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 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.fuelgauge;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryStats;
+import android.os.SystemClock;
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.utils.AsyncLoader;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DebugEstimatesLoader extends AsyncLoader> {
+ private BatteryStatsHelper mStatsHelper;
+
+ public DebugEstimatesLoader(Context context, BatteryStatsHelper statsHelper) {
+ super(context);
+ mStatsHelper = statsHelper;
+ }
+
+ @Override
+ protected void onDiscardResult(List result) {
+
+ }
+
+ @Override
+ public List loadInBackground() {
+ Context context = getContext();
+ PowerUsageFeatureProvider powerUsageFeatureProvider =
+ FeatureFactory.getFactory(context).getPowerUsageFeatureProvider(context);
+
+ // get stuff we'll need for both BatteryInfo
+ BatteryUtils batteryUtils = BatteryUtils.getInstance(context);
+ final long elapsedRealtimeUs = batteryUtils.convertMsToUs(SystemClock.elapsedRealtime());
+ Intent batteryBroadcast = getContext().registerReceiver(null,
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ BatteryStats stats = mStatsHelper.getStats();
+
+ BatteryInfo oldinfo = BatteryInfo.getBatteryInfoOld(getContext(), batteryBroadcast,
+ stats, elapsedRealtimeUs, false);
+
+ final long timeRemainingEnhanced = batteryUtils.convertMsToUs(
+ powerUsageFeatureProvider.getEnhancedBatteryPrediction(getContext()));
+ BatteryInfo newinfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast, stats,
+ elapsedRealtimeUs, false, timeRemainingEnhanced, true);
+
+ List infos = new ArrayList<>();
+ infos.add(oldinfo);
+ infos.add(newinfo);
+ return infos;
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 4a4d28c5a13..e6b1d9ddf2c 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -91,4 +91,25 @@ public interface PowerUsageFeatureProvider {
* Check whether a specific anomaly detector is enabled
*/
boolean isAnomalyDetectorEnabled(@Anomaly.AnomalyType int type);
+
+ /**
+ * Checks whether debugging should be enabled for battery estimates.
+ * @return
+ */
+ boolean isEstimateDebugEnabled();
+
+ /**
+ * Converts the provided string containing the remaining time into a debug string for enhanced
+ * estimates.
+ * @param timeRemaining
+ * @return A string containing the estimate and a label indicating it is an enhanced estimate
+ */
+ String getEnhancedEstimateDebugString(String timeRemaining);
+
+ /**
+ * Converts the provided string containing the remaining time into a debug string.
+ * @param timeRemaining
+ * @return A string containing the estimate and a label indicating it is a normal estimate
+ */
+ String getOldEstimateDebugString(String timeRemaining);
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 5ef6fe5384d..c43eebd2034 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -117,4 +117,19 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
public boolean isAnomalyDetectorEnabled(@Anomaly.AnomalyType int type) {
return false;
}
+
+ @Override
+ public String getEnhancedEstimateDebugString(String timeRemaining) {
+ return null;
+ }
+
+ @Override
+ public boolean isEstimateDebugEnabled() {
+ return false;
+ }
+
+ @Override
+ public String getOldEstimateDebugString(String timeRemaining) {
+ return null;
+ }
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index e59e58711fd..808a4896c4c 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge;
import android.app.Activity;
import android.app.LoaderManager;
+import android.app.LoaderManager.LoaderCallbacks;
import android.content.Context;
import android.content.Loader;
import android.content.res.TypedArray;
@@ -35,12 +36,16 @@ 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.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatterySipper.DrainType;
@@ -58,12 +63,11 @@ import com.android.settings.display.AutoBrightnessPreferenceController;
import com.android.settings.display.BatteryPercentagePreferenceController;
import com.android.settings.display.TimeoutPreferenceController;
import com.android.settings.fuelgauge.anomaly.Anomaly;
-import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment;
+import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment.AnomalyDialogListener;
import com.android.settings.fuelgauge.anomaly.AnomalyLoader;
import com.android.settings.fuelgauge.anomaly.AnomalySummaryPreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -73,7 +77,7 @@ import java.util.List;
* consumed since the last time it was unplugged.
*/
public class PowerUsageSummary extends PowerUsageBase implements
- AnomalyDialogFragment.AnomalyDialogListener {
+ AnomalyDialogListener, OnLongClickListener, OnClickListener {
static final String TAG = "PowerUsageSummary";
@@ -104,6 +108,7 @@ public class PowerUsageSummary extends PowerUsageBase implements
@VisibleForTesting
static final int MENU_TOGGLE_APPS = Menu.FIRST + 5;
private static final int MENU_HELP = Menu.FIRST + 6;
+ public static final int DEBUG_INFO_LOADER = 3;
@VisibleForTesting
boolean mShowAllApps = false;
@@ -115,15 +120,15 @@ public class PowerUsageSummary extends PowerUsageBase implements
PowerUsageFeatureProvider mPowerFeatureProvider;
@VisibleForTesting
BatteryUtils mBatteryUtils;
+ @VisibleForTesting
+ LayoutPreference mBatteryLayoutPref;
/**
* SparseArray that maps uid to {@link Anomaly}, so we could find {@link Anomaly} by uid
*/
@VisibleForTesting
SparseArray> mAnomalySparseArray;
-
private BatteryHeaderPreferenceController mBatteryHeaderPreferenceController;
- private LayoutPreference mBatteryLayoutPref;
private PreferenceGroup mAppListGroup;
private AnomalySummaryPreferenceController mAnomalySummaryPreferenceController;
private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
@@ -152,7 +157,7 @@ public class PowerUsageSummary extends PowerUsageBase implements
};
@VisibleForTesting
- LoaderManager.LoaderCallbacks BatteryInfoLoaderCallbacks =
+ LoaderManager.LoaderCallbacks mBatteryInfoLoaderCallbacks =
new LoaderManager.LoaderCallbacks() {
@Override
@@ -171,12 +176,61 @@ public class PowerUsageSummary extends PowerUsageBase implements
}
};
+ LoaderManager.LoaderCallbacks> mBatteryInfoDebugLoaderCallbacks =
+ new LoaderCallbacks>() {
+ @Override
+ public Loader> onCreateLoader(int i, Bundle bundle) {
+ return new DebugEstimatesLoader(getContext(), mStatsHelper);
+ }
+
+ @Override
+ public void onLoadFinished(Loader> loader,
+ List batteryInfos) {
+ final BatteryMeterView batteryView = (BatteryMeterView) mBatteryLayoutPref
+ .findViewById(R.id.battery_header_icon);
+ final TextView percentRemaining =
+ mBatteryLayoutPref.findViewById(R.id.battery_percent);
+ final TextView summary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
+ final TextView summary2 = mBatteryLayoutPref.findViewById(R.id.summary2);
+ BatteryInfo oldInfo = batteryInfos.get(0);
+ BatteryInfo newInfo = batteryInfos.get(1);
+ percentRemaining.setText(Utils.formatPercentage(oldInfo.batteryLevel));
+
+ // set the text to the old estimate (copied from battery info). Note that this
+ // can sometimes say 0 time remaining because battery stats requires the phone
+ // be unplugged for a period of time before being willing ot make an estimate.
+ summary1.setText(mPowerFeatureProvider.getOldEstimateDebugString(
+ Formatter.formatShortElapsedTime(getContext(),
+ mBatteryUtils.convertUsToMs(oldInfo.remainingTimeUs))));
+
+ // for this one we can just set the string directly
+ summary2.setText(mPowerFeatureProvider.getEnhancedEstimateDebugString(
+ Formatter.formatShortElapsedTime(getContext(),
+ mBatteryUtils.convertUsToMs(newInfo.remainingTimeUs))));
+
+ batteryView.setBatteryLevel(oldInfo.batteryLevel);
+ batteryView.setCharging(!oldInfo.discharging);
+ }
+
+ @Override
+ public void onLoaderReset(Loader> loader) {
+ }
+ };
+
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setAnimationAllowed(true);
+ initFeatureProvider();
mBatteryLayoutPref = (LayoutPreference) findPreference(KEY_BATTERY_HEADER);
+ View header = mBatteryLayoutPref.findViewById(R.id.summary1);
+ // Unfortunately setting a long click listener on a means it will no longer pass the regular
+ // click event to the parent, so we have to register a regular click listener as well.
+ if (mPowerFeatureProvider.isEstimateDebugEnabled()) {
+ header.setOnLongClickListener(this);
+ header.setOnClickListener(this);
+ }
mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
mScreenUsagePref = (PowerGaugePreference) findPreference(KEY_SCREEN_USAGE);
mLastFullChargePref = (PowerGaugePreference) findPreference(
@@ -187,7 +241,6 @@ public class PowerUsageSummary extends PowerUsageBase implements
mBatteryUtils = BatteryUtils.getInstance(getContext());
mAnomalySparseArray = new SparseArray<>();
- initFeatureProvider();
restartBatteryInfoLoader();
}
@@ -305,8 +358,7 @@ public class PowerUsageSummary extends PowerUsageBase implements
MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_OPTIMIZATION);
return true;
case MENU_ADDITIONAL_BATTERY_INFO:
- startActivity(FeatureFactory.getFactory(getContext())
- .getPowerUsageFeatureProvider(getContext())
+ startActivity(mPowerFeatureProvider
.getAdditionalBatteryInfoIntent());
metricsFeatureProvider.action(context,
MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_USAGE_ALERTS);
@@ -335,11 +387,7 @@ public class PowerUsageSummary extends PowerUsageBase implements
}
private void performBatteryHeaderClick() {
- final Context context = getContext();
- final PowerUsageFeatureProvider featureProvider = FeatureFactory.getFactory(context)
- .getPowerUsageFeatureProvider(context);
-
- if (featureProvider.isAdvancedUiEnabled()) {
+ if (mPowerFeatureProvider.isAdvancedUiEnabled()) {
Utils.startWithFragment(getContext(), PowerUsageAdvanced.class.getName(), null,
null, 0, R.string.advanced_battery_title, null, getMetricsCategory());
} else {
@@ -617,6 +665,17 @@ public class PowerUsageSummary extends PowerUsageBase implements
timeSequence));
}
+ @VisibleForTesting
+ void showBothEstimates() {
+ final Context context = getContext();
+ if (context == null
+ || !mPowerFeatureProvider.isEnhancedBatteryPredictionEnabled(context)) {
+ return;
+ }
+ getLoaderManager().restartLoader(DEBUG_INFO_LOADER, Bundle.EMPTY,
+ mBatteryInfoDebugLoaderCallbacks);
+ }
+
@VisibleForTesting
double calculatePercentage(double powerUsage, double dischargeAmount) {
final double totalPower = mStatsHelper.getTotalPower();
@@ -678,7 +737,7 @@ public class PowerUsageSummary extends PowerUsageBase implements
if (mPowerFeatureProvider != null
&& mPowerFeatureProvider.isEnhancedBatteryPredictionEnabled(getContext())) {
getLoaderManager().restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY,
- BatteryInfoLoaderCallbacks);
+ mBatteryInfoLoaderCallbacks);
}
}
@@ -753,6 +812,18 @@ public class PowerUsageSummary extends PowerUsageBase implements
mAnomalySummaryPreferenceController.hideHighUsagePreference();
}
+ @Override
+ public boolean onLongClick(View view) {
+ showBothEstimates();
+ view.setOnLongClickListener(null);
+ return true;
+ }
+
+ @Override
+ public void onClick(View view) {
+ performBatteryHeaderClick();
+ }
+
private static class SummaryProvider implements SummaryLoader.SummaryProvider {
private final Context mContext;
private final SummaryLoader mLoader;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index c793434a660..3f721b244d4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -83,6 +83,7 @@ public class BatteryHeaderPreferenceControllerTest {
private BatteryMeterView mBatteryMeterView;
private TextView mTimeText;
private TextView mSummary;
+ private TextView mSummary2;
private LayoutPreference mBatteryLayoutPref;
private Intent mBatteryIntent;
private Lifecycle mLifecycle;
@@ -97,6 +98,7 @@ public class BatteryHeaderPreferenceControllerTest {
mTimeText = new TextView(mContext);
mSummary = new TextView(mContext);
ShadowEntityHeaderController.setUseMock(mEntityHeaderController);
+ mSummary2 = new TextView(mContext);
mBatteryIntent = new Intent();
mBatteryIntent.putExtra(BatteryManager.EXTRA_LEVEL, BATTERY_LEVEL);
@@ -113,7 +115,8 @@ public class BatteryHeaderPreferenceControllerTest {
mContext, mActivity, mPreferenceFragment, mLifecycle);
mController.mBatteryMeterView = mBatteryMeterView;
mController.mTimeText = mTimeText;
- mController.mSummary = mSummary;
+ mController.mSummary1 = mSummary;
+ mController.mSummary2 = mSummary2;
}
@After
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index 156a1ea7946..daee1822dfd 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -15,7 +15,9 @@
*/
package com.android.settings.fuelgauge;
+import android.view.View;
import java.util.List;
+import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import android.app.LoaderManager;
import android.content.Context;
@@ -106,6 +108,8 @@ public class PowerUsageSummaryTest {
private static final double POWER_USAGE_PERCENTAGE = 50;
private static final Intent ADDITIONAL_BATTERY_INFO_INTENT =
new Intent("com.example.app.ADDITIONAL_BATTERY_INFO");
+ public static final String NEW_ML_EST_SUFFIX = "(New ML est)";
+ public static final String OLD_EST_SUFFIX = "(Old est)";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@@ -450,6 +454,18 @@ public class PowerUsageSummaryTest {
any());
}
+ @Test
+ public void testShowBothEstimates_summariesAreBothModified() {
+ doReturn(new TextView(mRealContext)).when(mBatteryLayoutPref).findViewById(R.id.summary2);
+ doReturn(new TextView(mRealContext)).when(mBatteryLayoutPref).findViewById(R.id.summary1);
+ mFragment.onLongClick(new View(mRealContext));
+ TextView summary1 = mFragment.mBatteryLayoutPref.findViewById(R.id.summary1);
+ TextView summary2 = mFragment.mBatteryLayoutPref.findViewById(R.id.summary2);
+ Robolectric.flushBackgroundThreadScheduler();
+ assertThat(summary2.getText().toString().contains(NEW_ML_EST_SUFFIX));
+ assertThat(summary1.getText().toString().contains(OLD_EST_SUFFIX));
+ }
+
public static class TestFragment extends PowerUsageSummary {
private Context mContext;