diff --git a/res/color/color_accent_selector.xml b/res/color/color_accent_selector.xml new file mode 100644 index 00000000000..3ccb64068ec --- /dev/null +++ b/res/color/color_accent_selector.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/res/color/color_battery_anomaly_yellow_selector.xml b/res/color/color_battery_anomaly_yellow_selector.xml new file mode 100644 index 00000000000..0dd79c2fb84 --- /dev/null +++ b/res/color/color_battery_anomaly_yellow_selector.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/res/drawable/ic_battery_tips_lightbulb.xml b/res/drawable/ic_battery_tips_lightbulb.xml index f1449f9bb5b..6fffefc8119 100644 --- a/res/drawable/ic_battery_tips_lightbulb.xml +++ b/res/drawable/ic_battery_tips_lightbulb.xml @@ -20,6 +20,6 @@ android:viewportWidth="24" android:viewportHeight="24"> \ No newline at end of file diff --git a/res/drawable/ic_battery_tips_warning_icon.xml b/res/drawable/ic_battery_tips_warning_icon.xml new file mode 100644 index 00000000000..c5df8a8856d --- /dev/null +++ b/res/drawable/ic_battery_tips_warning_icon.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/res/layout/battery_tips_card.xml b/res/layout/battery_tips_card.xml index 3eb2eb23cfa..c9a00bc6ab9 100644 --- a/res/layout/battery_tips_card.xml +++ b/res/layout/battery_tips_card.xml @@ -61,7 +61,7 @@ android:text="@string/battery_tips_card_action_button" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="?android:attr/textColorPrimary" - app:strokeColor="?android:attr/colorAccent" + app:strokeColor="@color/color_accent_selector" app:strokeWidth="1dp" /> diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 72e2e2f41c6..1723d177797 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -1409,6 +1409,17 @@ + + + ic_battery_tips_lightbulb + ic_battery_tips_warning_icon + + + + color_accent_selector + color_battery_anomaly_yellow_selector + + Turn on adaptive brightness to extend battery life diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java index 2d530bd3731..97bae5a6951 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java @@ -23,6 +23,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -51,6 +52,8 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic private String mAnomalyEventId; private PowerAnomalyKey mPowerAnomalyKey; + private int mIconResourceId = 0; + private int mMainButtonStrokeColorResourceId = 0; @VisibleForTesting CharSequence mMainButtonLabel; @@ -73,6 +76,26 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic mPowerAnomalyKey = null; } + /** + * Sets the icon in tips card. + */ + public void setIconResourceId(int resourceId) { + if (mIconResourceId != resourceId) { + mIconResourceId = resourceId; + notifyChanged(); + } + } + + /** + * Sets the stroke color of main button in tips card. + */ + public void setMainButtonStrokeColorResourceId(int resourceId) { + if (mMainButtonStrokeColorResourceId != resourceId) { + mMainButtonStrokeColorResourceId = resourceId; + notifyChanged(); + } + } + /** * Sets the anomaly event id which is used in metrics. */ @@ -159,9 +182,15 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic MaterialButton mainButton = (MaterialButton) view.findViewById(R.id.main_button); mainButton.setOnClickListener(this); mainButton.setText(mMainButtonLabel); + if (mMainButtonStrokeColorResourceId != 0) { + mainButton.setStrokeColorResource(mMainButtonStrokeColorResourceId); + } MaterialButton dismissButton = (MaterialButton) view.findViewById(R.id.dismiss_button); dismissButton.setOnClickListener(this); dismissButton.setText(mDismissButtonLabel); + if (mIconResourceId != 0) { + ((ImageView) view.findViewById(R.id.icon)).setImageResource(mIconResourceId); + } if (!mPowerUsageFeatureProvider.isBatteryTipsFeedbackEnabled()) { return; diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java index 96c1330363d..33c61e61511 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java @@ -77,23 +77,29 @@ public class BatteryTipsController extends BasePreferenceController { return null; } + private String getStringFromResource(int resourceId, int resourceIndex) { + if (resourceId < 0) { + return null; + } + final String[] stringArray = mContext.getResources().getStringArray(resourceId); + return (resourceIndex >= 0 && resourceIndex < stringArray.length) + ? stringArray[resourceIndex] : null; + } + + private int getResourceId(int resourceId, int resourceIndex, String defType) { + final String key = getStringFromResource(resourceId, resourceIndex); + return TextUtils.isEmpty(key) ? 0 + : mContext.getResources().getIdentifier(key, defType, mContext.getPackageName()); + } + private String getString(PowerAnomalyEvent powerAnomalyEvent, Function warningBannerInfoSupplier, Function warningItemInfoSupplier, int resourceId, int resourceIndex) { String string = getInfo(powerAnomalyEvent, warningBannerInfoSupplier, warningItemInfoSupplier); - - if (!TextUtils.isEmpty(string) || resourceId < 0) { - return string; - } - - String[] stringArray = mContext.getResources().getStringArray(resourceId); - if (resourceIndex >= 0 && resourceIndex < stringArray.length) { - string = stringArray[resourceIndex]; - } - - return string; + return (!TextUtils.isEmpty(string) || resourceId < 0) ? string + : getStringFromResource(resourceId, resourceIndex); } @VisibleForTesting @@ -107,6 +113,13 @@ public class BatteryTipsController extends BasePreferenceController { return; } + // Get card icon and color styles + final int cardStyleId = powerAnomalyEvent.getType().getNumber(); + final int iconResId = getResourceId( + R.array.battery_tips_card_icons, cardStyleId, "drawable"); + final int colorResId = getResourceId( + R.array.battery_tips_card_colors, cardStyleId, "color"); + // Get card preference strings and navigate fragment info final PowerAnomalyKey powerAnomalyKey = powerAnomalyEvent.hasKey() ? powerAnomalyEvent.getKey() : null; @@ -133,10 +146,12 @@ public class BatteryTipsController extends BasePreferenceController { String preferenceHighlightKey = getInfo(powerAnomalyEvent, WarningBannerInfo::getMainButtonSourceHighlightKey, null); - // Updated card preference and main button fragment launcher + // Update card preference and main button fragment launcher mCardPreference.setAnomalyEventId(powerAnomalyEvent.getEventId()); mCardPreference.setPowerAnomalyKey(powerAnomalyKey); mCardPreference.setTitle(titleString); + mCardPreference.setIconResourceId(iconResId); + mCardPreference.setMainButtonStrokeColorResourceId(colorResId); mCardPreference.setMainButtonLabel(mainBtnString); mCardPreference.setDismissButtonLabel(dismissBtnString); mCardPreference.setMainButtonLauncherInfo( diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java index e1ba84e7dbf..ac9de1fa336 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.res.Resources; import android.os.LocaleList; +import com.android.settings.R; import com.android.settings.testutils.BatteryTestUtils; import com.android.settings.testutils.FakeFeatureFactory; @@ -83,6 +84,9 @@ public final class BatteryTipsControllerTest { // Check pre-defined string verify(mBatteryTipsCardPreference).setTitle( "Turn on adaptive brightness to extend battery life"); + verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb); + verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId( + R.color.color_accent_selector); verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings"); verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it"); // Check proto info @@ -103,6 +107,9 @@ public final class BatteryTipsControllerTest { verify(mBatteryTipsCardPreference).setAnomalyEventId("ScreenTimeoutAnomaly"); verify(mBatteryTipsCardPreference).setTitle("Reduce screen timeout to extend battery life"); + verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb); + verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId( + R.color.color_accent_selector); verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings"); verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it"); verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo( @@ -129,6 +136,9 @@ public final class BatteryTipsControllerTest { verify(mBatteryTipsCardPreference).setAnomalyEventId("ScreenTimeoutAnomaly"); verify(mBatteryTipsCardPreference).setTitle(testTitle); + verify(mBatteryTipsCardPreference).setIconResourceId(R.drawable.ic_battery_tips_lightbulb); + verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId( + R.color.color_accent_selector); verify(mBatteryTipsCardPreference).setMainButtonLabel("View Settings"); verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it"); verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo( @@ -138,4 +148,27 @@ public final class BatteryTipsControllerTest { verify(mFeatureFactory.metricsFeatureProvider).action( mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "ScreenTimeoutAnomaly"); } + + @Test + public void handleBatteryTipsCardUpdated_appAnomaly_showAnomaly() { + PowerAnomalyEvent event = BatteryTestUtils.createAppAnomalyEvent(); + when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true); + + mBatteryTipsController.handleBatteryTipsCardUpdated(event); + + verify(mBatteryTipsCardPreference).setAnomalyEventId("AppAnomaly"); + verify(mBatteryTipsCardPreference).setTitle( + "Chrome used more battery than usual in foreground"); + verify(mBatteryTipsCardPreference).setIconResourceId( + R.drawable.ic_battery_tips_warning_icon); + verify(mBatteryTipsCardPreference).setMainButtonStrokeColorResourceId( + R.color.color_battery_anomaly_yellow_selector); + verify(mBatteryTipsCardPreference).setMainButtonLabel("Check"); + verify(mBatteryTipsCardPreference).setDismissButtonLabel("Got it"); + verify(mBatteryTipsCardPreference).setMainButtonLauncherInfo( + null, null, null); + verify(mBatteryTipsCardPreference).setVisible(true); + verify(mFeatureFactory.metricsFeatureProvider).action( + mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, "AppAnomaly"); + } } diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java index 136431dfa19..3297d1ef4de 100644 --- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java @@ -39,6 +39,7 @@ import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEventList; import com.android.settings.fuelgauge.batteryusage.PowerAnomalyKey; import com.android.settings.fuelgauge.batteryusage.PowerAnomalyType; import com.android.settings.fuelgauge.batteryusage.WarningBannerInfo; +import com.android.settings.fuelgauge.batteryusage.WarningItemInfo; import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventDao; import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity; import com.android.settings.fuelgauge.batteryusage.db.BatteryState; @@ -70,14 +71,18 @@ public class BatteryTestUtils { BatteryManager.BATTERY_STATUS_DISCHARGING); } - /** Sets the work profile mode. */ + /** + * Sets the work profile mode. + */ public static void setWorkProfile(Context context) { final UserManager userManager = context.getSystemService(UserManager.class); Shadows.shadowOf(userManager).setManagedProfile(true); Shadows.shadowOf(userManager).setIsSystemUser(false); } - /** Creates and sets up the in-memory {@link BatteryStateDatabase}. */ + /** + * Creates and sets up the in-memory {@link BatteryStateDatabase}. + */ public static BatteryStateDatabase setUpBatteryStateDatabase(Context context) { final BatteryStateDatabase inMemoryDatabase = Room.inMemoryDatabaseBuilder(context, BatteryStateDatabase.class) @@ -87,21 +92,27 @@ public class BatteryTestUtils { return inMemoryDatabase; } - /** Inserts a fake data into the database for testing. */ + /** + * Inserts a fake data into the database for testing. + */ public static void insertDataToBatteryStateTable( Context context, long timestamp, String packageName) { insertDataToBatteryStateTable( context, timestamp, packageName, /*multiple=*/ false, /*isFullChargeStart=*/ false); } - /** Inserts a fake data into the database for testing. */ + /** + * Inserts a fake data into the database for testing. + */ public static void insertDataToBatteryStateTable( Context context, long timestamp, String packageName, boolean isFullChargeStart) { insertDataToBatteryStateTable( context, timestamp, packageName, /*multiple=*/ false, isFullChargeStart); } - /** Inserts a fake data into the database for testing. */ + /** + * Inserts a fake data into the database for testing. + */ public static void insertDataToBatteryStateTable( Context context, long timestamp, String packageName, boolean multiple, boolean isFullChargeStart) { @@ -151,14 +162,18 @@ public class BatteryTestUtils { } } - /** Inserts a fake data into the database for testing. */ + /** + * Inserts a fake data into the database for testing. + */ public static void insertDataToAppUsageEventTable( Context context, long userId, long timestamp, String packageName) { insertDataToAppUsageEventTable( context, userId, timestamp, packageName, /*multiple=*/ false); } - /** Inserts a fake data into the database for testing. */ + /** + * Inserts a fake data into the database for testing. + */ public static void insertDataToAppUsageEventTable( Context context, long userId, long timestamp, String packageName, boolean multiple) { final AppUsageEventEntity entity = @@ -179,7 +194,9 @@ public class BatteryTestUtils { } } - /** Gets customized battery changed intent. */ + /** + * Gets customized battery changed intent. + */ public static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) { Intent intent = new Intent(); intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged); @@ -190,7 +207,9 @@ public class BatteryTestUtils { return intent; } - /** Configures the incompatible charger environment. */ + /** + * Configures the incompatible charger environment. + */ public static void setupIncompatibleEvent( UsbPort mockUsbPort, UsbManager mockUsbManager, UsbPortStatus mockUsbPortStatus) { final List usbPorts = new ArrayList<>(); @@ -203,12 +222,16 @@ public class BatteryTestUtils { .thenReturn(new int[]{UsbPortStatus.COMPLIANCE_WARNING_OTHER}); } - /** Create an empty power anomaly event list proto. */ + /** + * Create an empty power anomaly event list proto. + */ public static PowerAnomalyEventList createEmptyPowerAnomalyEventList() { return PowerAnomalyEventList.getDefaultInstance(); } - /** Create an non-empty power anomaly event list proto. */ + /** + * Create an non-empty power anomaly event list proto. + */ public static PowerAnomalyEventList createNonEmptyPowerAnomalyEventList() { return PowerAnomalyEventList.newBuilder() .addPowerAnomalyEvents(0, createAdaptiveBrightnessAnomalyEvent()) @@ -216,7 +239,9 @@ public class BatteryTestUtils { .build(); } - /** Create a power anomaly event proto of adaptive brightness. */ + /** + * Create a power anomaly event proto of adaptive brightness. + */ public static PowerAnomalyEvent createAdaptiveBrightnessAnomalyEvent() { return PowerAnomalyEvent.newBuilder() .setEventId("BrightnessAnomaly") @@ -231,7 +256,9 @@ public class BatteryTestUtils { .build(); } - /** Create a power anomaly event proto of screen timeout. */ + /** + * Create a power anomaly event proto of screen timeout. + */ public static PowerAnomalyEvent createScreenTimeoutAnomalyEvent() { return PowerAnomalyEvent.newBuilder() .setEventId("ScreenTimeoutAnomaly") @@ -245,4 +272,21 @@ public class BatteryTestUtils { .build()) .build(); } + + /** + * Create a power anomaly event proto of app anomaly. + */ + public static PowerAnomalyEvent createAppAnomalyEvent() { + return PowerAnomalyEvent.newBuilder() + .setEventId("AppAnomaly") + .setType(PowerAnomalyType.TYPE_APPS_ITEM) + .setKey(PowerAnomalyKey.KEY_APP) + .setScore(2.0f) + .setWarningItemInfo(WarningItemInfo.newBuilder() + .setTitleString("Chrome used more battery than usual in foreground") + .setMainButtonString("Check") + .setCancelButtonString("Got it") + .build()) + .build(); + } }