Add BatteryFix Slice
Change-Id: I504df1e9caadced71cc37f8be9207ab9fd26f9ab
Fixes: 114807643
Test: manual
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index cbfae2e..0ae001d 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -2,18 +2,6 @@
<issues format="4">
<issue
- id="LintError"
- severity="Error"
- message="No `.class` files were found in project ".", so none of the classfile based checks could be run. Does the project need to be built first?"
- category="Lint"
- priority="10"
- summary="Lint Failure"
- explanation="This issue type represents a problem running lint itself. Examples include failure to find bytecode for source files (which means certain detectors could not be run), parsing errors in lint configuration files, etc.
These errors are not errors in your own code, but they are shown to make it clear that some checks were not completed.">
- <location
- file="."/>
- </issue>
-
- <issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
@@ -2553,7 +2541,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rXC/strings.xml"
- line="2530"
+ line="2533"
column="168"/>
</issue>
@@ -2569,7 +2557,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rAU/strings.xml"
- line="2531"
+ line="2534"
column="64"/>
</issue>
@@ -2585,7 +2573,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rCA/strings.xml"
- line="2531"
+ line="2534"
column="64"/>
</issue>
@@ -2601,7 +2589,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rGB/strings.xml"
- line="2531"
+ line="2534"
column="64"/>
</issue>
@@ -2617,7 +2605,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rIN/strings.xml"
- line="2531"
+ line="2534"
column="64"/>
</issue>
@@ -2633,7 +2621,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/strings.xml"
- line="5886"
+ line="5902"
column="36"/>
</issue>
@@ -2665,7 +2653,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="443"
+ line="448"
column="44"/>
</issue>
@@ -2681,7 +2669,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="449"
+ line="454"
column="44"/>
</issue>
@@ -2697,7 +2685,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="450"
+ line="455"
column="44"/>
</issue>
@@ -2761,7 +2749,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
- line="91"
+ line="90"
column="47"/>
</issue>
@@ -2777,7 +2765,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
- line="91"
+ line="90"
column="47"/>
</issue>
@@ -2793,7 +2781,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
- line="97"
+ line="96"
column="40"/>
</issue>
@@ -2809,7 +2797,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
- line="97"
+ line="96"
column="40"/>
</issue>
@@ -2825,7 +2813,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
- line="160"
+ line="159"
column="45"/>
</issue>
@@ -2841,7 +2829,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
- line="161"
+ line="160"
column="49"/>
</issue>
@@ -2857,7 +2845,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
- line="169"
+ line="168"
column="45"/>
</issue>
@@ -2873,7 +2861,7 @@
errorLine2=" ^">
<location
file="res/values/themes.xml"
- line="170"
+ line="169"
column="49"/>
</issue>
@@ -2885,6 +2873,54 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item name="batteryGoodColor">@color/battery_good_color_light</item>"
+ errorLine2=" ^">
+ <location
+ file="res/values/themes.xml"
+ line="185"
+ column="39"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item name="batteryMaybeColor">@color/battery_maybe_color_light</item>"
+ errorLine2=" ^">
+ <location
+ file="res/values/themes.xml"
+ line="186"
+ column="40"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item name="batteryBadColor">@color/battery_bad_color_light</item>"
+ errorLine2=" ^">
+ <location
+ file="res/values/themes.xml"
+ line="187"
+ column="38"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" <item name="wifi_signal_color">@color/setup_wizard_wifi_color_dark</item>"
errorLine2=" ^">
<location
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 4f44a36..b280482 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -180,6 +180,11 @@
<!-- action bar, needed for search bar icon tinting -->
<item name="android:actionBarTheme">@*android:style/ThemeOverlay.DeviceDefault.ActionBar.Accent</item>
+
+ <!-- For battery status icons in -->
+ <item name="batteryGoodColor">@color/battery_good_color_light</item>
+ <item name="batteryMaybeColor">@color/battery_maybe_color_light</item>
+ <item name="batteryBadColor">@color/battery_bad_color_light</item>
</style>
<style name="Theme.Settings.Home" parent="Theme.Settings.HomeBase">
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index b5c39a1..0266689 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -26,6 +26,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.settings.Utils;
+import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -115,6 +116,6 @@
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
}
}
+ BatteryFixSlice.updateBatteryTipAvailabilityCache(mContext);
}
-
}
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
index f58ec74..db3fddc 100644
--- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import com.android.settings.homepage.contextualcards.deviceinfo.BatterySlice;
+import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.intelligence.ContextualCardProto.ContextualCard;
@@ -61,11 +62,18 @@
.setCardName(LowStorageSlice.PATH_LOW_STORAGE)
.setCardCategory(ContextualCard.Category.IMPORTANT)
.build();
+ final ContextualCard batteryFixCard =
+ ContextualCard.newBuilder()
+ .setSliceUri(BatteryFixSlice.BATTERY_FIX_URI.toString())
+ .setCardName(BatteryFixSlice.PATH_BATTERY_FIX)
+ .setCardCategory(ContextualCard.Category.IMPORTANT)
+ .build();
final ContextualCardList cards = ContextualCardList.newBuilder()
.addCard(wifiCard)
.addCard(batteryInfoCard)
.addCard(connectedDeviceCard)
.addCard(lowStorageCard)
+ .addCard(batteryFixCard)
.build();
return cards;
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
new file mode 100644
index 0000000..23ff172
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2018 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.homepage.contextualcards.slices;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.ListBuilder.RowBuilder;
+import androidx.slice.builders.SliceAction;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.R;
+import com.android.settings.SubSettings;
+import com.android.settings.Utils;
+import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
+import com.android.settings.fuelgauge.PowerUsageSummary;
+import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.slices.CustomSliceable;
+import com.android.settings.slices.SettingsSliceProvider;
+import com.android.settings.slices.SliceBackgroundWorker;
+import com.android.settings.slices.SliceBuilderUtils;
+import com.android.settingslib.utils.ThreadUtils;
+
+import java.util.List;
+
+public class BatteryFixSlice implements CustomSliceable {
+
+ /**
+ * Unique name of Battery Fix Slice.
+ */
+ public static final String PATH_BATTERY_FIX = "battery_fix";
+
+ /**
+ * Uri for Battery Fix Slice.
+ */
+ public static final Uri BATTERY_FIX_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(PATH_BATTERY_FIX)
+ .build();
+
+ @VisibleForTesting
+ static final String PREFS = "battery_fix_prefs";
+ @VisibleForTesting
+ static final String KEY_CURRENT_TIPS_TYPE = "current_tip_type";
+
+ private static final String TAG = "BatteryFixSlice";
+
+ private final Context mContext;
+
+ public BatteryFixSlice(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public Uri getUri() {
+ return BATTERY_FIX_URI;
+ }
+
+ /**
+ * Return a Slice bound to {@link #BATTERY_FIX_URI}.
+ */
+ @Override
+ public Slice getSlice() {
+ IconCompat icon;
+ SliceAction primaryAction;
+ Slice slice = null;
+
+ // TipType.SUMMARY is battery good
+ if (readBatteryTipAvailabilityCache(mContext) == BatteryTip.TipType.SUMMARY) {
+ return null;
+ }
+
+ final List<BatteryTip> batteryTips = SliceBackgroundWorker.getInstance(mContext,
+ this).getResults();
+
+ if (batteryTips != null) {
+ for (BatteryTip batteryTip : batteryTips) {
+ if (batteryTip.getState() != BatteryTip.StateType.INVISIBLE) {
+ icon = IconCompat.createWithResource(mContext, batteryTip.getIconId());
+ primaryAction = new SliceAction(getPrimaryAction(),
+ icon,
+ batteryTip.getTitle(mContext));
+ slice = new ListBuilder(mContext, BATTERY_FIX_URI, ListBuilder.INFINITY)
+ .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
+ .addRow(new RowBuilder()
+ .setTitle(batteryTip.getTitle(mContext))
+ .setSubtitle(batteryTip.getSummary(mContext))
+ .setPrimaryAction(primaryAction)
+ .addEndItem(icon, ListBuilder.ICON_IMAGE))
+ .build();
+ break;
+ }
+ }
+ } else {
+ icon = IconCompat.createWithResource(mContext,
+ R.drawable.ic_battery_status_good_24dp);
+ final String title = mContext.getString(R.string.power_usage_summary_title);
+ primaryAction = new SliceAction(getPrimaryAction(), icon, title);
+ slice = new ListBuilder(mContext, BATTERY_FIX_URI, ListBuilder.INFINITY)
+ .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
+ .addRow(new RowBuilder()
+ .setTitle(title)
+ .setPrimaryAction(primaryAction)
+ .addEndItem(icon, ListBuilder.ICON_IMAGE))
+ .build();
+ }
+ return slice;
+ }
+
+ @Override
+ public Intent getIntent() {
+ final String screenTitle = mContext.getText(R.string.power_usage_summary_title)
+ .toString();
+ final Uri contentUri = new Uri.Builder().appendPath(PATH_BATTERY_FIX).build();
+
+ return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
+ PowerUsageSummary.class.getName(), PATH_BATTERY_FIX,
+ screenTitle,
+ MetricsProto.MetricsEvent.SLICE)
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(contentUri);
+ }
+
+ @Override
+ public void onNotifyChange(Intent intent) {
+ }
+
+ @Override
+ public Class getBackgroundWorkerClass() {
+ return BatteryTipWorker.class;
+ }
+
+ private PendingIntent getPrimaryAction() {
+ final Intent intent = getIntent();
+ return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
+ }
+
+ // TODO(b/114807643): we should find a better way to get current battery tip type quickly
+ // Now we save battery tip type to shared preference when battery level changes
+ public static void updateBatteryTipAvailabilityCache(Context context) {
+ ThreadUtils.postOnBackgroundThread(() -> {
+ refreshBatteryTips(context);
+ });
+ }
+
+ @VisibleForTesting
+ static int readBatteryTipAvailabilityCache(Context context) {
+ final SharedPreferences prefs = context.getSharedPreferences(PREFS, MODE_PRIVATE);
+ return prefs.getInt(KEY_CURRENT_TIPS_TYPE, BatteryTip.TipType.SUMMARY);
+ }
+
+ @WorkerThread
+ private static List<BatteryTip> refreshBatteryTips(Context context) {
+ final BatteryStatsHelperLoader statsLoader = new BatteryStatsHelperLoader(context);
+ final BatteryStatsHelper statsHelper = statsLoader.loadInBackground();
+ final BatteryTipLoader loader = new BatteryTipLoader(context, statsHelper);
+ final List<BatteryTip> batteryTips = loader.loadInBackground();
+ for (BatteryTip batteryTip : batteryTips) {
+ if (batteryTip.getState() != BatteryTip.StateType.INVISIBLE) {
+ SharedPreferences.Editor editor = context.getSharedPreferences(PREFS,
+ MODE_PRIVATE).edit();
+ editor.putInt(KEY_CURRENT_TIPS_TYPE, batteryTip.getType());
+ editor.apply();
+ break;
+ }
+ }
+ return batteryTips;
+ }
+
+ public static class BatteryTipWorker extends SliceBackgroundWorker<BatteryTip> {
+
+ private final Context mContext;
+
+ public BatteryTipWorker(Context context, Uri uri) {
+ super(context, uri);
+ mContext = context;
+ }
+
+ @Override
+ protected void onSlicePinned() {
+ ThreadUtils.postOnBackgroundThread(() -> {
+ final List<BatteryTip> batteryTips = refreshBatteryTips(mContext);
+ updateResults(batteryTips);
+ });
+ }
+
+ @Override
+ protected void onSliceUnpinned() {
+ }
+
+ @Override
+ public void close() {
+ }
+ }
+}
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index 5b25498..99e22a1 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -20,10 +20,13 @@
import android.net.Uri;
import android.util.ArrayMap;
+import androidx.annotation.VisibleForTesting;
+
import com.android.settings.homepage.contextualcards.deviceinfo.BatterySlice;
import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.DeviceInfoSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
+import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.wifi.WifiSlice;
@@ -34,13 +37,11 @@
/**
* Manages custom {@link androidx.slice.Slice Slices}, which are all Slices not backed by
* preferences.
- * <p>
- * By default, all Slices in Settings should be built by a
- * </p>
*/
public class CustomSliceManager {
- protected final Map<Uri, Class<? extends CustomSliceable>> mUriMap;
+ @VisibleForTesting
+ final Map<Uri, Class<? extends CustomSliceable>> mUriMap;
private final Context mContext;
private final Map<Uri, CustomSliceable> mSliceableCache;
@@ -107,5 +108,6 @@
mUriMap.put(BatterySlice.BATTERY_CARD_URI, BatterySlice.class);
mUriMap.put(ConnectedDeviceSlice.CONNECTED_DEVICE_URI, ConnectedDeviceSlice.class);
mUriMap.put(LowStorageSlice.LOW_STORAGE_URI, LowStorageSlice.class);
+ mUriMap.put(BatteryFixSlice.BATTERY_FIX_URI, BatteryFixSlice.class);
}
}
diff --git a/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
index e074440..182c8bf 100644
--- a/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java
@@ -40,6 +40,7 @@
import android.widget.ImageView;
import com.android.settings.homepage.SettingsHomepageActivity;
+import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
@@ -99,7 +100,11 @@
}
@Test
- @Config(qualifiers = "mcc999")
+ @Config(qualifiers = "mcc999",
+ shadows = {
+ BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+ BatteryFixSliceTest.ShadowBatteryTipLoader.class
+ })
public void onStart_useMockAvatarViewMixin_shouldBeExecuted() {
final AvatarViewMixin mockAvatar = spy(new AvatarViewMixin(mActivity, mImageView));
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index fb34640..02a6761 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -33,6 +33,7 @@
import android.os.PowerManager;
import com.android.settings.Utils;
+import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
@@ -42,6 +43,11 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
@RunWith(SettingsRobolectricTestRunner.class)
public class BatteryBroadcastReceiverTest {
@@ -74,6 +80,10 @@
}
@Test
+ @Config(shadows = {
+ BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+ BatteryFixSliceTest.ShadowBatteryTipLoader.class
+ })
public void testOnReceive_batteryLevelChanged_dataUpdated() {
mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent);
@@ -85,6 +95,10 @@
}
@Test
+ @Config(shadows = {
+ BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+ BatteryFixSliceTest.ShadowBatteryTipLoader.class
+ })
public void testOnReceive_powerSaveModeChanged_listenerInvoked() {
mBatteryBroadcastReceiver.onReceive(mContext,
new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
@@ -93,6 +107,10 @@
}
@Test
+ @Config(shadows = {
+ BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+ BatteryFixSliceTest.ShadowBatteryTipLoader.class
+ })
public void testOnReceive_batteryDataNotChanged_listenerNotInvoked() {
final String batteryLevel = Utils.getBatteryPercentage(mChargingIntent);
final String batteryStatus =
@@ -108,6 +126,10 @@
}
@Test
+ @Config(shadows = {
+ BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+ BatteryFixSliceTest.ShadowBatteryTipLoader.class
+ })
public void testRegister_updateBatteryStatus() {
doReturn(mChargingIntent).when(mContext).registerReceiver(any(), any());
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
new file mode 100644
index 0000000..1df5277
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 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.homepage.contextualcards.slices;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import static com.android.settings.homepage.contextualcards.slices.BatteryFixSlice.KEY_CURRENT_TIPS_TYPE;
+import static com.android.settings.homepage.contextualcards.slices.BatteryFixSlice.PREFS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import androidx.slice.SliceProvider;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
+import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.EarlyWarningTip;
+import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class BatteryFixSliceTest {
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ }
+
+ @After
+ public void tearDown() {
+ ShadowBatteryTipLoader.reset();
+ }
+
+ @Test
+ public void readBatteryTipfromPref_readCorrectValue() {
+ int target = 111;
+ final SharedPreferences.Editor editor = mContext.getSharedPreferences(PREFS,
+ MODE_PRIVATE).edit();
+ editor.putInt(KEY_CURRENT_TIPS_TYPE, target);
+
+ editor.commit();
+
+ assertThat(BatteryFixSlice.readBatteryTipAvailabilityCache(mContext)).isEqualTo(target);
+ }
+
+ @Test
+ @Config(shadows = {
+ ShadowBatteryStatsHelperLoader.class,
+ ShadowBatteryTipLoader.class
+ })
+ public void updateBatteryTipAvailabilityCache_writeCorrectValue() {
+ final List<BatteryTip> tips = new ArrayList<>();
+ tips.add(new LowBatteryTip(BatteryTip.StateType.INVISIBLE, false, ""));
+ tips.add(new EarlyWarningTip(BatteryTip.StateType.HANDLED, false));
+ ShadowBatteryTipLoader.setBatteryTips(tips);
+
+ BatteryFixSlice.updateBatteryTipAvailabilityCache(mContext);
+
+ assertThat(BatteryFixSlice.readBatteryTipAvailabilityCache(mContext)).isEqualTo(
+ BatteryTip.TipType.BATTERY_SAVER);
+ }
+
+ @Implements(BatteryStatsHelperLoader.class)
+ public static class ShadowBatteryStatsHelperLoader {
+
+ @Implementation
+ protected BatteryStatsHelper loadInBackground() {
+ return null;
+ }
+ }
+
+ @Implements(BatteryTipLoader.class)
+ public static class ShadowBatteryTipLoader {
+
+ private static List<BatteryTip> sBatteryTips = new ArrayList<>();
+
+ @Resetter
+ public static void reset() {
+ sBatteryTips = new ArrayList<>();
+ }
+
+ @Implementation
+ protected List<BatteryTip> loadInBackground() {
+ return sBatteryTips;
+ }
+
+ public static void setBatteryTips(List<BatteryTip> tips) {
+ sBatteryTips = tips;
+ }
+ }
+}