Impl app anomlay preference

[ScreenShot]: https://screenshot.googleplex.com/BBrHTQbwbFHxZE9

Bug: 291689623
Bug: 291689643
Test: manual
Change-Id: Ia257f3ace4a2d71b2221f861be3e1238de6d791e
diff --git a/res/color/color_accent_selector.xml b/res/color/color_accent_selector.xml
new file mode 100644
index 0000000..3ccb640
--- /dev/null
+++ b/res/color/color_accent_selector.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?android:attr/colorAccent"/>
+</selector>
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 0000000..0dd79c2
--- /dev/null
+++ b/res/color/color_battery_anomaly_yellow_selector.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/palette_list_color_yellow"/>
+</selector>
diff --git a/res/drawable/ic_battery_tips_lightbulb.xml b/res/drawable/ic_battery_tips_lightbulb.xml
index f1449f9..6fffefc 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">
     <path
-        android:fillColor="?android:attr/colorAccent"
+        android:fillColor="@color/color_accent_selector"
         android:pathData="M7,20h4c0,1.1 -0.9,2 -2,2S7,21.1 7,20zM5,19h8v-2H5V19zM16.5,9.5c0,3.82 -2.66,5.86 -3.77,6.5H5.27C4.16,15.36 1.5,13.32 1.5,9.5C1.5,5.36 4.86,2 9,2S16.5,5.36 16.5,9.5zM14.5,9.5C14.5,6.47 12.03,4 9,4S3.5,6.47 3.5,9.5c0,2.47 1.49,3.89 2.35,4.5h6.3C13.01,13.39 14.5,11.97 14.5,9.5zM21.37,7.37L20,8l1.37,0.63L22,10l0.63,-1.37L24,8l-1.37,-0.63L22,6L21.37,7.37zM19,6l0.94,-2.06L22,3l-2.06,-0.94L19,0l-0.94,2.06L16,3l2.06,0.94L19,6z"/>
 </vector>
\ 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 0000000..c5df8a8
--- /dev/null
+++ b/res/drawable/ic_battery_tips_warning_icon.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright (C) 2023 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="32dp"
+    android:height="32dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@color/color_battery_anomaly_yellow_selector"
+        android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout/battery_tips_card.xml b/res/layout/battery_tips_card.xml
index 3eb2eb2..c9a00bc 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" />
         </LinearLayout>
     </LinearLayout>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 47cf21f..78e7ca4 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1409,6 +1409,17 @@
     <integer-array name="network_mode_3g_deprecated_carrier_id" translatable="false">
     </integer-array>
 
+    <!-- The following 2 arrays are for battery tips card. Please keep them the same size. -->
+    <string-array name="battery_tips_card_icons" translatable="false">
+        <item>ic_battery_tips_lightbulb</item>
+        <item>ic_battery_tips_warning_icon</item>
+    </string-array>
+
+    <string-array name="battery_tips_card_colors" translatable="false">
+        <item>color_accent_selector</item>
+        <item>color_battery_anomaly_yellow_selector</item>
+    </string-array>
+
     <!-- The following 3 arrays are for power anomaly tips card. Please keep them the same size. -->
     <string-array name="power_anomaly_titles">
         <item>Turn on adaptive brightness to extend battery life</item>
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
index 075b706..ea5534d 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.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 @@
 
     private String mAnomalyEventId;
     private PowerAnomalyKey mPowerAnomalyKey;
+    private int mIconResourceId = 0;
+    private int mMainButtonStrokeColorResourceId = 0;
 
     @VisibleForTesting
     CharSequence mMainButtonLabel;
@@ -74,6 +77,26 @@
     }
 
     /**
+     * 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.
      */
     public void setAnomalyEventId(final String anomalyEventId) {
@@ -159,9 +182,15 @@
         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 9e46f90..80b2695 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -77,23 +77,29 @@
         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<WarningBannerInfo, String> warningBannerInfoSupplier,
                              Function<WarningItemInfo, String> 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 @@
             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 @@
         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 e1ba84e..ac9de1f 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.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 @@
         // 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 @@
 
         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 @@
 
         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 @@
         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 136431d..3297d1e 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.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 @@
                 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 @@
         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 @@
         }
     }
 
-    /** 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 @@
         }
     }
 
-    /** 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 @@
         return intent;
     }
 
-    /** Configures the incompatible charger environment. */
+    /**
+     * Configures the incompatible charger environment.
+     */
     public static void setupIncompatibleEvent(
             UsbPort mockUsbPort, UsbManager mockUsbManager, UsbPortStatus mockUsbPortStatus) {
         final List<UsbPort> usbPorts = new ArrayList<>();
@@ -203,12 +222,16 @@
                 .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 @@
                 .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 @@
                 .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 @@
                         .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();
+    }
 }