From fde63fc35118c05c12fd7e199d6092bbe2b243a1 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Tue, 12 Dec 2017 12:52:35 -0800 Subject: [PATCH] Add infra for battery tip This cl adds the basic structure for battery tip: 1. BaseBatteryTip: Model class to represent the tip and build preference and dialog 2. SummaryTip: Display a general battery summary(i.e. your battery is good..) 3. BatteryTipLoader: AsyncLoader to load the battery tips. 4. BatteryTipPreferenceController: preference controller for preference group to display battery tips This cl also: 1. Remove the anomaly code in PowerUsageSummary and we will add it to app restriction in future. 2. Add preference_category_no_title.xml to avoid the extra 32dp blank at the top. Bug: 70570352 Test: RunSettingsRoboTests Change-Id: If91a553888e2eb91d55fb1d0d7bbea69652f144c --- res/drawable/ic_check_circle_green_24dp.xml | 25 ++++ res/layout/preference_category_no_title.xml | 27 +++++ res/values/strings.xml | 5 + res/xml/power_usage_summary.xml | 7 +- .../settings/fuelgauge/PowerUsageSummary.java | 93 +++++++-------- .../fuelgauge/batterytip/BatteryTipLoader.java | 58 +++++++++ .../batterytip/BatteryTipPreferenceController.java | 125 +++++++++++++++++++ .../fuelgauge/batterytip/tips/BatteryTip.java | 117 ++++++++++++++++++ .../fuelgauge/batterytip/tips/SummaryTip.java | 64 ++++++++++ .../fuelgauge/PowerUsageSummaryLegacyTest.java | 4 +- .../settings/fuelgauge/PowerUsageSummaryTest.java | 11 +- .../BatteryTipPreferenceControllerTest.java | 132 +++++++++++++++++++++ .../fuelgauge/batterytip/tips/BatteryTipTest.java | 97 +++++++++++++++ 13 files changed, 700 insertions(+), 65 deletions(-) create mode 100644 res/drawable/ic_check_circle_green_24dp.xml create mode 100644 res/layout/preference_category_no_title.xml create mode 100644 src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java create mode 100644 src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java create mode 100644 src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java create mode 100644 src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java diff --git a/res/drawable/ic_check_circle_green_24dp.xml b/res/drawable/ic_check_circle_green_24dp.xml new file mode 100644 index 0000000000..6f2692ddbb --- /dev/null +++ b/res/drawable/ic_check_circle_green_24dp.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/layout/preference_category_no_title.xml b/res/layout/preference_category_no_title.xml new file mode 100644 index 0000000000..136ec6d47f --- /dev/null +++ b/res/layout/preference_category_no_title.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 694a1b052d..65f73c81bf 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4738,6 +4738,11 @@ %1$d apps misbehaving + + Battery is in good shape + + Apps are behaving normally + Stop app? diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml index 80179c02ac..0aec18fcf5 100644 --- a/res/xml/power_usage_summary.xml +++ b/res/xml/power_usage_summary.xml @@ -26,10 +26,9 @@ android:selectable="true" android:layout="@layout/battery_header"/> - + diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index e4b70a1437..a5b6c08ae4 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -55,10 +55,9 @@ 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.AnomalyDetectionPolicy; -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.fuelgauge.anomaly.AnomalyUtils; +import com.android.settings.fuelgauge.batterytip.BatteryTipLoader; +import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; @@ -72,14 +71,15 @@ import java.util.List; * Displays a list of apps and subsystems that consume power, ordered by how much power was * consumed since the last time it was unplugged. */ -public class PowerUsageSummary extends PowerUsageBase implements - AnomalyDialogListener, OnLongClickListener, OnClickListener { +public class PowerUsageSummary extends PowerUsageBase implements OnLongClickListener, + OnClickListener, BatteryTipPreferenceController.BatteryTipListener { static final String TAG = "PowerUsageSummary"; private static final boolean DEBUG = false; private static final String KEY_APP_LIST = "app_list"; private static final String KEY_BATTERY_HEADER = "battery_header"; + private static final String KEY_BATTERY_TIP = "battery_tip"; private static final String KEY_SHOW_ALL_APPS = "show_all_apps"; private static final String KEY_SCREEN_USAGE = "screen_usage"; @@ -89,12 +89,11 @@ public class PowerUsageSummary extends PowerUsageBase implements private static final String KEY_SCREEN_TIMEOUT = "screen_timeout_battery"; private static final String KEY_AMBIENT_DISPLAY = "ambient_display_battery"; private static final String KEY_BATTERY_SAVER_SUMMARY = "battery_saver_summary"; - private static final String KEY_HIGH_USAGE = "high_usage"; @VisibleForTesting - static final int ANOMALY_LOADER = 1; + static final int BATTERY_INFO_LOADER = 1; @VisibleForTesting - static final int BATTERY_INFO_LOADER = 2; + static final int BATTERY_TIP_LOADER = 2; private static final int MENU_STATS_TYPE = Menu.FIRST; @VisibleForTesting static final int MENU_HIGH_POWER_APPS = Menu.FIRST + 3; @@ -126,36 +125,9 @@ public class PowerUsageSummary extends PowerUsageBase implements @VisibleForTesting BatteryHeaderPreferenceController mBatteryHeaderPreferenceController; private BatteryAppListPreferenceController mBatteryAppListPreferenceController; - private AnomalySummaryPreferenceController mAnomalySummaryPreferenceController; + private BatteryTipPreferenceController mBatteryTipPreferenceController; private int mStatsType = BatteryStats.STATS_SINCE_CHARGED; - private LoaderManager.LoaderCallbacks> mAnomalyLoaderCallbacks = - new LoaderManager.LoaderCallbacks>() { - - @Override - public Loader> onCreateLoader(int id, Bundle args) { - return new AnomalyLoader(getContext(), mStatsHelper); - } - - @Override - public void onLoadFinished(Loader> loader, List data) { - final AnomalyUtils anomalyUtils = AnomalyUtils.getInstance(getContext()); - anomalyUtils.logAnomalies(mMetricsFeatureProvider, data, - MetricsEvent.FUELGAUGE_POWER_USAGE_SUMMARY); - - // show high usage preference if possible - mAnomalySummaryPreferenceController.updateAnomalySummaryPreference(data); - - updateAnomalySparseArray(data); - mBatteryAppListPreferenceController.refreshAnomalyIcon(mAnomalySparseArray); - } - - @Override - public void onLoaderReset(Loader> loader) { - - } - }; - @VisibleForTesting LoaderManager.LoaderCallbacks mBatteryInfoLoaderCallbacks = new LoaderManager.LoaderCallbacks() { @@ -217,6 +189,26 @@ public class PowerUsageSummary extends PowerUsageBase implements } }; + private LoaderManager.LoaderCallbacks> mBatteryTipsCallbacks = + new LoaderManager.LoaderCallbacks>() { + + @Override + public Loader> onCreateLoader(int id, Bundle args) { + return new BatteryTipLoader(getContext(), mStatsHelper); + } + + @Override + public void onLoadFinished(Loader> loader, + List data) { + mBatteryTipPreferenceController.updateBatteryTips(data); + } + + @Override + public void onLoaderReset(Loader> loader) { + + } + }; + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -229,8 +221,6 @@ public class PowerUsageSummary extends PowerUsageBase implements mLastFullChargePref = (PowerGaugePreference) findPreference( KEY_TIME_SINCE_LAST_FULL_CHARGE); mFooterPreferenceMixin.createFooterPreference().setTitle(R.string.battery_footer_summary); - mAnomalySummaryPreferenceController = new AnomalySummaryPreferenceController( - (SettingsActivity) getActivity(), this, MetricsEvent.FUELGAUGE_POWER_USAGE_SUMMARY); mBatteryUtils = BatteryUtils.getInstance(getContext()); mAnomalySparseArray = new SparseArray<>(); @@ -251,9 +241,6 @@ public class PowerUsageSummary extends PowerUsageBase implements @Override public boolean onPreferenceTreeClick(Preference preference) { - if (mAnomalySummaryPreferenceController.onPreferenceTreeClick(preference)) { - return true; - } if (KEY_BATTERY_HEADER.equals(preference.getKey())) { performBatteryHeaderClick(); return true; @@ -282,6 +269,9 @@ public class PowerUsageSummary extends PowerUsageBase implements mBatteryAppListPreferenceController = new BatteryAppListPreferenceController(context, KEY_APP_LIST, lifecycle, activity, this); controllers.add(mBatteryAppListPreferenceController); + mBatteryTipPreferenceController = new BatteryTipPreferenceController(context, + KEY_BATTERY_TIP, this); + controllers.add(mBatteryTipPreferenceController); controllers.add(new AutoBrightnessPreferenceController(context, KEY_AUTO_BRIGHTNESS)); controllers.add(new TimeoutPreferenceController(context, KEY_SCREEN_TIMEOUT)); controllers.add(new BatterySaverController(context, getLifecycle())); @@ -382,7 +372,7 @@ public class PowerUsageSummary extends PowerUsageBase implements return; } - restartAnomalyDetectionIfPossible(); + restartBatteryTipLoader(); // reload BatteryInfo and updateUI restartBatteryInfoLoader(); @@ -398,10 +388,8 @@ public class PowerUsageSummary extends PowerUsageBase implements } @VisibleForTesting - void restartAnomalyDetectionIfPossible() { - if (getAnomalyDetectionPolicy().isAnomalyDetectionEnabled()) { - getLoaderManager().restartLoader(ANOMALY_LOADER, Bundle.EMPTY, mAnomalyLoaderCallbacks); - } + void restartBatteryTipLoader() { + getLoaderManager().restartLoader(BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks); } @VisibleForTesting @@ -485,11 +473,6 @@ public class PowerUsageSummary extends PowerUsageBase implements } @Override - public void onAnomalyHandled(Anomaly anomaly) { - mAnomalySummaryPreferenceController.hideHighUsagePreference(); - } - - @Override public boolean onLongClick(View view) { showBothEstimates(); view.setOnLongClickListener(null); @@ -513,6 +496,11 @@ public class PowerUsageSummary extends PowerUsageBase implements } } + @Override + public void onBatteryTipHandled(BatteryTip batteryTip) { + restartBatteryTipLoader(); + } + private static class SummaryProvider implements SummaryLoader.SummaryProvider { private final Context mContext; private final SummaryLoader mLoader; @@ -555,7 +543,6 @@ public class PowerUsageSummary extends PowerUsageBase implements @Override public List getNonIndexableKeys(Context context) { List niks = super.getNonIndexableKeys(context); - niks.add(KEY_HIGH_USAGE); niks.add(KEY_BATTERY_SAVER_SUMMARY); // Duplicates in display niks.add(KEY_AUTO_BRIGHTNESS); diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java new file mode 100644 index 0000000000..b8cb6c48b1 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java @@ -0,0 +1,58 @@ +/* + * 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.batterytip; + +import android.content.Context; + +import com.android.internal.os.BatteryStatsHelper; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; +import com.android.settings.fuelgauge.batterytip.tips.SummaryTip; +import com.android.settingslib.utils.AsyncLoader; + +import java.util.ArrayList; +import java.util.List; + +/** + * Loader to compute and return a battery tip list. It will always return a full length list even + * though some tips may have state {@code BaseBatteryTip.StateType.INVISIBLE}. + */ +public class BatteryTipLoader extends AsyncLoader> { + private static final String TAG = "BatteryTipLoader"; + + private static final boolean USE_FAKE_DATA = false; + + private BatteryStatsHelper mBatteryStatsHelper; + + public BatteryTipLoader(Context context, BatteryStatsHelper batteryStatsHelper) { + super(context); + mBatteryStatsHelper = batteryStatsHelper; + } + + @Override + public List loadInBackground() { + List tips = new ArrayList<>(); + + //TODO(b/70570352): add battery tip detectors + tips.add(new SummaryTip(BatteryTip.StateType.NEW)); + return tips; + } + + @Override + protected void onDiscardResult(List result) { + } + +} diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java new file mode 100644 index 0000000000..f6114052cf --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java @@ -0,0 +1,125 @@ +/* + * 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.batterytip; + +import android.content.Context; +import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceGroup; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; +import com.android.settings.fuelgauge.batterytip.tips.SummaryTip; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Controller in charge of the battery tip group + */ +public class BatteryTipPreferenceController extends BasePreferenceController { + private BatteryTipListener mBatteryTipListener; + private List mBatteryTips; + private Map mBatteryTipMap; + @VisibleForTesting + PreferenceGroup mPreferenceGroup; + @VisibleForTesting + Context mPrefContext; + + public BatteryTipPreferenceController(Context context, String preferenceKey) { + this(context, preferenceKey, null); + } + + public BatteryTipPreferenceController(Context context, String preferenceKey, + BatteryTipListener batteryTipListener) { + super(context, preferenceKey); + mBatteryTipListener = batteryTipListener; + mBatteryTipMap = new HashMap<>(); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPrefContext = screen.getContext(); + mPreferenceGroup = (PreferenceGroup) screen.findPreference(getPreferenceKey()); + + // Add summary tip in advance to avoid UI flakiness + final SummaryTip summaryTip = new SummaryTip(BatteryTip.StateType.NEW); + mPreferenceGroup.addPreference(summaryTip.buildPreference(mPrefContext)); + } + + public void updateBatteryTips(List batteryTips) { + if (mBatteryTips == null) { + mBatteryTips = batteryTips; + } else { + // mBatteryTips and batteryTips always have the same length and same sequence. + for (int i = 0, size = batteryTips.size(); i < size; i++) { + mBatteryTips.get(i).updateState(batteryTips.get(i)); + } + } + + //TODO(b/70570352): try to reuse the existing preference rather than remove and add. + mPreferenceGroup.removeAll(); + for (int i = 0, size = batteryTips.size(); i < size; i++) { + final BatteryTip batteryTip = mBatteryTips.get(i); + if (batteryTip.getState() != BatteryTip.StateType.INVISIBLE) { + final Preference preference = batteryTip.buildPreference(mPrefContext); + mBatteryTipMap.put(preference.getKey(), batteryTip); + mPreferenceGroup.addPreference(preference); + } + } + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + final BatteryTip batteryTip = mBatteryTipMap.get(preference.getKey()); + if (batteryTip != null) { + if (batteryTip.shouldShowDialog()) { + // build and show the dialog + } else { + batteryTip.action(); + if (mBatteryTipListener != null) { + mBatteryTipListener.onBatteryTipHandled(batteryTip); + } + } + + return true; + } + + return super.handlePreferenceTreeClick(preference); + } + + /** + * Listener to give the control back to target fragment + */ + public interface BatteryTipListener { + /** + * This method is invoked once battery tip is handled, then target fragment could do + * extra work. + * + * @param batteryTip that has been handled + */ + void onBatteryTipHandled(BatteryTip batteryTip); + } +} diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java new file mode 100644 index 0000000000..e633272487 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java @@ -0,0 +1,117 @@ +/* + * 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.batterytip.tips; + +import android.app.Dialog; +import android.content.Context; +import android.support.annotation.IdRes; +import android.support.annotation.IntDef; +import android.support.v7.preference.Preference; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Base model for a battery tip(e.g. suggest user to turn on battery saver) + * + * Each {@link BatteryTip} contains basic data(e.g. title, summary, icon) as well as the + * pre-defined action(e.g. turn on battery saver) + */ +public abstract class BatteryTip { + @Retention(RetentionPolicy.SOURCE) + @IntDef({StateType.NEW, + StateType.HANDLED, + StateType.INVISIBLE}) + public @interface StateType { + int NEW = 0; + int HANDLED = 1; + int INVISIBLE = 2; + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({TipType.SUMMARY, + TipType.BATTERY_SAVER, + TipType.HIGH_DEVICE_USAGE, + TipType.SMART_BATTERY_MANAGER, + TipType.APP_RESTRICTION, + TipType.REDUCED_BATTERY, + TipType.LOW_BATTERY}) + public @interface TipType { + int SUMMARY = 0; + int BATTERY_SAVER = 1; + int HIGH_DEVICE_USAGE = 2; + int SMART_BATTERY_MANAGER = 3; + int APP_RESTRICTION = 4; + int REDUCED_BATTERY = 5; + int LOW_BATTERY = 6; + } + + private static final String KEY_PREFIX = "key_battery_tip"; + + @TipType + protected int mType; + @StateType + protected int mState; + protected boolean mShowDialog; + + public abstract CharSequence getTitle(Context context); + + public abstract CharSequence getSummary(Context context); + + @IdRes + public abstract int getIconId(); + + /** + * Update the current {@link #mState} using the new {@code tip}. + * @param tip used to update + */ + public abstract void updateState(BatteryTip tip); + + /** + * Execute the action for this {@link BatteryTip} + */ + public abstract void action(); + + /** + * Build the dialog to display either the info about {@link BatteryTip} or confirmation + * about the action. + */ + public abstract Dialog buildDialog(); + + public Preference buildPreference(Context context) { + Preference preference = new Preference(context); + + preference.setKey(getKey()); + preference.setTitle(getTitle(context)); + preference.setSummary(getSummary(context)); + preference.setIcon(getIconId()); + return preference; + } + + public boolean shouldShowDialog() { + return mShowDialog; + } + + public String getKey() { + return KEY_PREFIX + mType; + } + + @StateType + public int getState() { + return mState; + } +} diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java new file mode 100644 index 0000000000..ab2a6c3f19 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java @@ -0,0 +1,64 @@ +/* + * 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.batterytip.tips; + +import android.app.Dialog; +import android.content.Context; + +import com.android.settings.R; + +/** + * Tip to show general summary about battery life + */ +public class SummaryTip extends BatteryTip { + + public SummaryTip(@StateType int state) { + mShowDialog = false; + mState = state; + } + + @Override + public CharSequence getTitle(Context context) { + return context.getString(R.string.battery_tip_summary_title); + } + + @Override + public CharSequence getSummary(Context context) { + return context.getString(R.string.battery_tip_summary_summary); + } + + @Override + public int getIconId() { + return R.drawable.ic_check_circle_green_24dp; + } + + @Override + public void updateState(BatteryTip tip) { + mState = tip.mState; + } + + @Override + public void action() { + // do nothing + } + + @Override + public Dialog buildDialog() { + //TODO(b/70570352): create the dialog for summary tip and add test + return null; + } +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacyTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacyTest.java index a317626531..bc5b1d7a02 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacyTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacyTest.java @@ -452,8 +452,8 @@ public class PowerUsageSummaryLegacyTest { mFragment.restartAnomalyDetectionIfPossible(); - verify(mLoaderManager).restartLoader(eq(PowerUsageSummary.ANOMALY_LOADER), eq(Bundle.EMPTY), - any()); + verify(mLoaderManager).restartLoader(eq(PowerUsageSummaryLegacy.ANOMALY_LOADER), + eq(Bundle.EMPTY), any()); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java index 0ca983f3f8..272890939a 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java @@ -339,15 +339,14 @@ public class PowerUsageSummaryTest { } @Test - public void testInitAnomalyDetectionIfPossible_detectionEnabled_init() { + public void testRestartBatteryTipLoader() { + //TODO: add policy logic here when BatteryTipPolicy is implemented doReturn(mLoaderManager).when(mFragment).getLoaderManager(); - doReturn(mAnomalyDetectionPolicy).when(mFragment).getAnomalyDetectionPolicy(); - when(mAnomalyDetectionPolicy.isAnomalyDetectionEnabled()).thenReturn(true); - mFragment.restartAnomalyDetectionIfPossible(); + mFragment.restartBatteryTipLoader(); - verify(mLoaderManager).restartLoader(eq(PowerUsageSummary.ANOMALY_LOADER), eq(Bundle.EMPTY), - any()); + verify(mLoaderManager).restartLoader(eq(PowerUsageSummary.BATTERY_TIP_LOADER), + eq(Bundle.EMPTY), any()); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java new file mode 100644 index 0000000000..944587fb21 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java @@ -0,0 +1,132 @@ +/* + * 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.batterytip; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceCategory; +import android.support.v7.preference.PreferenceGroup; +import android.support.v7.preference.PreferenceManager; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.TestConfig; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; +import com.android.settings.fuelgauge.batterytip.tips.SummaryTip; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class BatteryTipPreferenceControllerTest { + private static final String KEY_PREF = "battery_tip"; + private static final String KEY_TIP = "key_battery_tip"; + @Mock + private BatteryTipPreferenceController.BatteryTipListener mBatteryTipListener; + @Mock + private PreferenceScreen mPreferenceScreen; + @Mock + private BatteryTip mBatteryTip; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private PreferenceManager mPreferenceManager; + + private Context mContext; + private PreferenceGroup mPreferenceGroup; + private BatteryTipPreferenceController mBatteryTipPreferenceController; + private List mOldBatteryTips; + private List mNewBatteryTips; + private Preference mPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + mPreferenceGroup = spy(new PreferenceCategory(mContext)); + doReturn(mContext).when(mPreferenceScreen).getContext(); + doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager(); + doReturn(mPreferenceGroup).when(mPreferenceScreen).findPreference(KEY_PREF); + mPreference = new Preference(mContext); + mPreference.setKey(KEY_TIP); + + mOldBatteryTips = new ArrayList<>(); + mOldBatteryTips.add(new SummaryTip(BatteryTip.StateType.NEW)); + mNewBatteryTips = new ArrayList<>(); + mNewBatteryTips.add(new SummaryTip(BatteryTip.StateType.INVISIBLE)); + + mBatteryTipPreferenceController = new BatteryTipPreferenceController(mContext, KEY_PREF, + mBatteryTipListener); + mBatteryTipPreferenceController.mPreferenceGroup = mPreferenceGroup; + mBatteryTipPreferenceController.mPrefContext = mContext; + } + + @Test + public void testDisplayPreference_addSummaryTip() { + mBatteryTipPreferenceController.displayPreference(mPreferenceScreen); + + assertOnlyContainsSummaryTip(mPreferenceGroup); + } + + @Test + public void updateBatteryTips_updateTwice_firstShowSummaryTipThenRemoveIt() { + // Display summary tip because its state is new + mBatteryTipPreferenceController.updateBatteryTips(mOldBatteryTips); + assertOnlyContainsSummaryTip(mPreferenceGroup); + + // Remove summary tip because its new state is invisible + mBatteryTipPreferenceController.updateBatteryTips(mNewBatteryTips); + assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0); + } + + @Test + public void testHandlePreferenceTreeClick_noDialog_invokeAction() { + List batteryTips = new ArrayList<>(); + batteryTips.add(mBatteryTip); + doReturn(mPreference).when(mBatteryTip).buildPreference(any()); + doReturn(false).when(mBatteryTip).shouldShowDialog(); + doReturn(KEY_TIP).when(mBatteryTip).getKey(); + mBatteryTipPreferenceController.updateBatteryTips(batteryTips); + + mBatteryTipPreferenceController.handlePreferenceTreeClick(mPreference); + + verify(mBatteryTip).action(); + } + + private void assertOnlyContainsSummaryTip(final PreferenceGroup preferenceGroup) { + assertThat(preferenceGroup.getPreferenceCount()).isEqualTo(1); + + final Preference preference = preferenceGroup.getPreference(0); + assertThat(preference.getTitle()).isEqualTo("Battery is in good shape"); + assertThat(preference.getSummary()).isEqualTo("Apps are behaving normally"); + } +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java new file mode 100644 index 0000000000..eec8e76091 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java @@ -0,0 +1,97 @@ +/* + * 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.batterytip.tips; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.Dialog; +import android.content.Context; +import android.support.annotation.IdRes; +import android.support.v7.preference.Preference; + +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class BatteryTipTest { + private static final String TITLE = "title"; + private static final String SUMMARY = "summary"; + @IdRes + private static final int ICON_ID = R.drawable.ic_fingerprint; + + private Context mContext; + private TestBatteryTip mBatteryTip; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mBatteryTip = new TestBatteryTip(); + } + + @Test + public void testBuildPreference() { + final Preference preference = mBatteryTip.buildPreference(mContext); + + assertThat(preference.getTitle()).isEqualTo(TITLE); + assertThat(preference.getSummary()).isEqualTo(SUMMARY); + assertThat(preference.getIcon()).isEqualTo(mContext.getDrawable(ICON_ID)); + } + + /** + * Used to test the non abstract methods in {@link TestBatteryTip} + */ + public class TestBatteryTip extends BatteryTip { + + @Override + public String getTitle(Context context) { + return TITLE; + } + + @Override + public String getSummary(Context context) { + return SUMMARY; + } + + @Override + public int getIconId() { + return ICON_ID; + } + + @Override + public void updateState(BatteryTip tip) { + // do nothing + } + + @Override + public void action() { + // do nothing + } + + @Override + public Dialog buildDialog() { + return null; + } + } + +} -- 2.11.0