diff --git a/res/drawable/battery_tips_all_rounded_bg.xml b/res/drawable/battery_tips_all_rounded_bg.xml
new file mode 100644
index 00000000000..4f61f544074
--- /dev/null
+++ b/res/drawable/battery_tips_all_rounded_bg.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/battery_tips_half_rounded_bottom_bg.xml b/res/drawable/battery_tips_half_rounded_bottom_bg.xml
new file mode 100644
index 00000000000..7766de63400
--- /dev/null
+++ b/res/drawable/battery_tips_half_rounded_bottom_bg.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/battery_tips_half_rounded_top_bg.xml b/res/drawable/battery_tips_half_rounded_top_bg.xml
new file mode 100644
index 00000000000..aba1a4fb329
--- /dev/null
+++ b/res/drawable/battery_tips_half_rounded_top_bg.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/ic_battery_tips_close.xml b/res/drawable/ic_battery_tips_close.xml
new file mode 100644
index 00000000000..7ef571b52f9
--- /dev/null
+++ b/res/drawable/ic_battery_tips_close.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/res/drawable/ic_battery_tips_close_icon.xml b/res/drawable/ic_battery_tips_close_icon.xml
new file mode 100644
index 00000000000..b7664740450
--- /dev/null
+++ b/res/drawable/ic_battery_tips_close_icon.xml
@@ -0,0 +1,32 @@
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/ic_battery_tips_lightbulb.xml b/res/drawable/ic_battery_tips_lightbulb.xml
new file mode 100644
index 00000000000..f1449f9bb5b
--- /dev/null
+++ b/res/drawable/ic_battery_tips_lightbulb.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/ic_battery_tips_thumb_down.xml b/res/drawable/ic_battery_tips_thumb_down.xml
new file mode 100644
index 00000000000..cd7656b220f
--- /dev/null
+++ b/res/drawable/ic_battery_tips_thumb_down.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/ic_battery_tips_thumb_up.xml b/res/drawable/ic_battery_tips_thumb_up.xml
new file mode 100644
index 00000000000..b1d4cb66c70
--- /dev/null
+++ b/res/drawable/ic_battery_tips_thumb_up.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
new file mode 100644
index 00000000000..d2edb51c0ab
--- /dev/null
+++ b/res/layout/battery_tips_card.xml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a7a124a32c5..e272c15109b 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -373,6 +373,10 @@
1dp
2dp
+
+ 4dp
+ 24dp
+
174dp
28dp
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 840cef422f2..08632498e69 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -9686,6 +9686,24 @@
Set battery usage for apps
+
+ Optimize
+
+
+ Is this message helpful?
+
+
+ Turn on adaptive brightness to extend battery life
+
+
+ It will help reduce your daily battery drain by 10%
+
+
+ Reduce screen timeout to extend battery life
+
+
+ It will help reduce your daily battery drain by 10%
+
Unrestricted
diff --git a/res/xml/power_usage_advanced.xml b/res/xml/power_usage_advanced.xml
index 2a1a23c78fe..c1294535a74 100644
--- a/res/xml/power_usage_advanced.xml
+++ b/res/xml/power_usage_advanced.xml
@@ -21,6 +21,18 @@
android:title="@string/advanced_battery_title"
settings:keywords="@string/keywords_battery_usage">
+
+
+
+
+
+
mHourlyViewModels;
private OnBatteryUsageUpdatedListener mOnBatteryUsageUpdatedListener;
private OnScreenOnTimeUpdatedListener mOnScreenOnTimeUpdatedListener;
+ private OnBatteryTipsUpdatedListener mOnBatteryTipsUpdatedListener;
private final SettingsActivity mActivity;
private final MetricsFeatureProvider mMetricsFeatureProvider;
@@ -209,6 +224,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
mOnScreenOnTimeUpdatedListener = listener;
}
+ void setOnBatteryTipsUpdatedListener(OnBatteryTipsUpdatedListener listener) {
+ mOnBatteryTipsUpdatedListener = listener;
+ }
+
void setBatteryHistoryMap(
final Map> batteryHistoryMap) {
Log.d(TAG, "setBatteryHistoryMap() " + (batteryHistoryMap == null ? "null"
@@ -344,6 +363,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
}
mOnBatteryUsageUpdatedListener.onBatteryUsageUpdated(
slotUsageData, getSlotInformation(), isBatteryUsageMapNullOrEmpty());
+
+ if (mOnBatteryTipsUpdatedListener != null) {
+ mOnBatteryTipsUpdatedListener.onBatteryTipsUpdated(null, null);
+ }
}
return true;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
new file mode 100644
index 00000000000..89e2ce937a5
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreference.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.fuelgauge.batteryusage;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+
+import com.google.android.material.button.MaterialButton;
+
+/**
+ * A preference for displaying the battery tips card view.
+ */
+public class BatteryTipsCardPreference extends Preference implements View.OnClickListener {
+
+ private static final String TAG = "BatteryTipsCardPreference";
+
+ private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
+
+ private MaterialButton mActionButton;
+ private ImageButton mDismissButton;
+ private ImageButton mThumbUpButton;
+ private ImageButton mThumbDownButton;
+ private CharSequence mTitle;
+ private CharSequence mSummary;
+
+ public BatteryTipsCardPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setLayoutResource(R.layout.battery_tips_card);
+ setSelectable(false);
+ mPowerUsageFeatureProvider = FeatureFactory.getFeatureFactory()
+ .getPowerUsageFeatureProvider();
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ notifyChanged();
+ }
+
+ @Override
+ public void setSummary(CharSequence summary) {
+ mSummary = summary;
+ notifyChanged();
+ }
+
+ @Override
+ public void onClick(View view) {
+ // TODO: replace with the settings anomaly obtained from detectSettingsAnomaly();
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder view) {
+ super.onBindViewHolder(view);
+
+ ((TextView) view.findViewById(R.id.title)).setText(mTitle);
+ ((TextView) view.findViewById(R.id.summary)).setText(mSummary);
+
+ mActionButton = (MaterialButton) view.findViewById(R.id.action_button);
+ mActionButton.setOnClickListener(this);
+ mDismissButton = (ImageButton) view.findViewById(R.id.dismiss_button);
+ mDismissButton.setOnClickListener(this);
+
+ if (!mPowerUsageFeatureProvider.isBatteryTipsFeedbackEnabled()) {
+ return;
+ }
+ view.findViewById(R.id.tips_card)
+ .setBackgroundResource(R.drawable.battery_tips_half_rounded_top_bg);
+ view.findViewById(R.id.feedback_card).setVisibility(View.VISIBLE);
+
+ mThumbUpButton = (ImageButton) view.findViewById(R.id.thumb_up);
+ mThumbUpButton.setOnClickListener(this);
+ mThumbDownButton = (ImageButton) view.findViewById(R.id.thumb_down);
+ mThumbDownButton.setOnClickListener(this);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
new file mode 100644
index 00000000000..87c43a1757c
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.fuelgauge.batteryusage;
+
+import android.content.Context;
+
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+
+/** Controls the update for battery tips card */
+public class BatteryTipsController extends BasePreferenceController {
+
+ private static final String TAG = "BatteryTipsController";
+ private static final String ROOT_PREFERENCE_KEY = "battery_tips_category";
+ private static final String CARD_PREFERENCE_KEY = "battery_tips_card";
+
+ private final PowerUsageFeatureProvider mPowerUsageFeatureProvider;
+
+ private Context mPrefContext;
+ private BatteryTipsCardPreference mCardPreference;
+
+ public BatteryTipsController(Context context) {
+ super(context, ROOT_PREFERENCE_KEY);
+ mPowerUsageFeatureProvider = FeatureFactory.getFeatureFactory()
+ .getPowerUsageFeatureProvider();
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPrefContext = screen.getContext();
+ mCardPreference = screen.findPreference(CARD_PREFERENCE_KEY);
+ }
+
+ /**
+ * Update the card visibility and contents.
+ * @param title a string not extend 2 lines.
+ * @param summary a string not extend 10 lines.
+ */
+ // TODO: replace parameters with SettingsAnomaly Data Proto
+ public void handleBatteryTipsCardUpdated(String title, String summary) {
+ if (!mPowerUsageFeatureProvider.isBatteryTipsEnabled()) {
+ mCardPreference.setVisible(false);
+ return;
+ }
+ if (title == null || summary == null) {
+ mCardPreference.setVisible(false);
+ return;
+ }
+ mCardPreference.setTitle(title);
+ mCardPreference.setSummary(summary);
+ mCardPreference.setVisible(true);
+ }
+
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index 7c4478e66c6..5a96fb40abc 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
@@ -34,6 +34,8 @@ import androidx.loader.content.Loader;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
@@ -143,6 +145,16 @@ public class PowerUsageAdvanced extends PowerUsageBase {
controllers.add(screenOnTimeController);
controllers.add(batteryUsageBreakdownController);
setBatteryChartPreferenceController();
+
+ final PowerUsageFeatureProvider powerUsageFeatureProvider =
+ FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
+ if (powerUsageFeatureProvider.isBatteryTipsEnabled()) {
+ BatteryTipsController batteryTipsController = new BatteryTipsController(context);
+ mBatteryChartPreferenceController.setOnBatteryTipsUpdatedListener(
+ batteryTipsController::handleBatteryTipsCardUpdated);
+ controllers.add(batteryTipsController);
+ }
+
return controllers;
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index 1a43dbbe8d2..c9591a51b08 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -67,6 +67,15 @@ public class PowerUsageFeatureProviderImplTest {
assertThat(mPowerFeatureProvider.isBatteryUsageEnabled()).isTrue();
}
+ @Test
+ public void testIsBatteryTipsEnabled_returnFalse() {
+ assertThat(mPowerFeatureProvider.isBatteryTipsEnabled()).isFalse();
+ }
+
+ @Test
+ public void testIsBatteryTipsFeedbackEnabled_returnTrue() {
+ assertThat(mPowerFeatureProvider.isBatteryTipsFeedbackEnabled()).isTrue();
+ }
@Test
public void testGetBatteryUsageListConsumePowerThreshold_return0() {
assertThat(mPowerFeatureProvider.getBatteryUsageListConsumePowerThreshold()).isEqualTo(0.0);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
new file mode 100644
index 00000000000..6f9a47416ae
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsCardPreferenceTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.fuelgauge.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public final class BatteryTipsCardPreferenceTest {
+
+ private Context mContext;
+ private BatteryTipsCardPreference mBatteryTipsCardPreference;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+ mBatteryTipsCardPreference = new BatteryTipsCardPreference(mContext, /*attrs=*/ null);
+ }
+
+ @Test
+ public void constructor_returnExpectedResult() {
+ assertThat(mBatteryTipsCardPreference.getLayoutResource()).isEqualTo(
+ R.layout.battery_tips_card);
+ }
+}