Merge changes from topic "improve_battery_usage" into main

* changes:
  [Expressive Battery] Implement the expressive style for anomaly hint chip
  [Expressive Battery] Refactor pref with anomaly hint.
This commit is contained in:
Xinyi Mao
2025-02-13 00:32:59 -08:00
committed by Android (Google) Code Review
15 changed files with 284 additions and 263 deletions

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2025 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/settingslib_expressive_radius_medium" />
<stroke android:width="1dp" android:color="@color/settingslib_materialColorOutline" />
</shape>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2025 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.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:drawable="@drawable/expressive_battery_hints_chip_bg"/>
</ripple>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?><!--
~ Copyright (C) 2025 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:orientation="vertical">
<include layout="@layout/settingslib_expressive_preference"
android:id="@+id/preference_frame"/>
<LinearLayout
android:id="@+id/warning_chip_frame"
android:visibility="gone"
android:clickable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/settingslib_expressive_space_small1"
android:layout_marginTop="-8dp">
<Space
android:id="@+id/warning_padding_placeholder"
android:layout_width="@dimen/settingslib_expressive_space_medium3"
android:layout_height="1px"
android:layout_marginEnd="@dimen/settingslib_expressive_space_extrasmall6"/>
<include layout="@layout/power_anomaly_hints"/>
</LinearLayout>
</LinearLayout>

View File

@@ -17,13 +17,12 @@
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical|start" android:gravity="center_vertical|start"
android:padding="8dp" android:id="@+id/warning_chip"
android:background="@drawable/battery_hints_chip_bg_ripple"> android:padding="8dp">
<ImageView <ImageView
android:layout_width="16dp" android:layout_width="16dp"

View File

@@ -1,49 +0,0 @@
<?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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:orientation="vertical">
<TextView
android:id="@+id/time_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorPrimary" />
<TextView
android:id="@+id/time_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
<include layout="@layout/power_anomaly_hints"
android:visibility="gone"
android:id="@+id/anomaly_hints"
android:paddingBottom="20dp"/>
</LinearLayout>

View File

@@ -22,7 +22,7 @@
<include layout="@layout/preference_app"/> <include layout="@layout/preference_app"/>
<LinearLayout <LinearLayout
android:id="@+id/warning_chip" android:id="@+id/warning_chip_frame"
android:visibility="gone" android:visibility="gone"
android:clickable="false" android:clickable="false"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -32,13 +32,12 @@
android:orientation="horizontal" android:orientation="horizontal"
android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<Space <Space
android:id="@+id/warning_padding_placeholder"
android:layout_width="@dimen/secondary_app_icon_size" android:layout_width="@dimen/secondary_app_icon_size"
android:layout_height="wrap_content" android:layout_height="1px"
android:layout_marginEnd="16dp"/> android:layout_marginEnd="16dp"/>
<include layout="@layout/power_anomaly_hints"/> <include layout="@layout/power_anomaly_hints"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -93,10 +93,10 @@ public class PowerUsageTimeController extends BasePreferenceController {
|| (summaryTimeMs == 0 && !TextUtils.equals(anomalyHintKey, preference.getKey()))) { || (summaryTimeMs == 0 && !TextUtils.equals(anomalyHintKey, preference.getKey()))) {
return false; return false;
} }
preference.setTimeTitle(mContext.getString(titleResId)); preference.setTitle(mContext.getString(titleResId));
preference.setTimeSummary(getPowerUsageTimeInfo(summaryTimeMs)); preference.setSummary(getPowerUsageTimeInfo(summaryTimeMs));
if (TextUtils.equals(anomalyHintKey, preference.getKey())) { if (TextUtils.equals(anomalyHintKey, preference.getKey())) {
preference.setAnomalyHint(anomalyHintText); preference.setHint(anomalyHintText);
} }
preference.setVisible(true); preference.setVisible(true);
return true; return true;

View File

@@ -17,74 +17,17 @@
package com.android.settings.fuelgauge; package com.android.settings.fuelgauge;
import android.content.Context; import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting; import com.android.settingslib.widget.GroupSectionDividerMixin;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
/** Custom preference for displaying the app power usage time. */ /** Custom preference for displaying the app power usage time. */
public class PowerUsageTimePreference extends Preference { public class PowerUsageTimePreference extends WarningFramePreference implements
GroupSectionDividerMixin {
private static final String TAG = "PowerUsageTimePreference"; private static final String TAG = "PowerUsageTimePreference";
@VisibleForTesting CharSequence mTimeTitle;
@VisibleForTesting CharSequence mTimeSummary;
@VisibleForTesting CharSequence mAnomalyHintText;
public PowerUsageTimePreference(Context context, AttributeSet attrs) { public PowerUsageTimePreference(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
setLayoutResource(R.layout.power_usage_time); setSelectable(false);
}
void setTimeTitle(CharSequence timeTitle) {
if (!TextUtils.equals(mTimeTitle, timeTitle)) {
mTimeTitle = timeTitle;
notifyChanged();
}
}
void setTimeSummary(CharSequence timeSummary) {
if (!TextUtils.equals(mTimeSummary, timeSummary)) {
mTimeSummary = timeSummary;
notifyChanged();
}
}
void setAnomalyHint(CharSequence anomalyHintText) {
if (!TextUtils.equals(mAnomalyHintText, anomalyHintText)) {
mAnomalyHintText = anomalyHintText;
notifyChanged();
}
}
private void showAnomalyHint(PreferenceViewHolder view) {
if (TextUtils.isEmpty(mAnomalyHintText)) {
return;
}
final View anomalyHintView = view.findViewById(R.id.anomaly_hints);
if (anomalyHintView == null) {
return;
}
final TextView warningInfo = anomalyHintView.findViewById(R.id.warning_info);
if (warningInfo == null) {
return;
}
warningInfo.setText(mAnomalyHintText);
anomalyHintView.setVisibility(View.VISIBLE);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
((TextView) view.findViewById(R.id.time_title)).setText(mTimeTitle);
((TextView) view.findViewById(R.id.time_summary)).setText(mTimeSummary);
showAnomalyHint(view);
} }
} }

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2025 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;
import android.annotation.Nullable;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.android.settingslib.Utils;
import com.android.settingslib.widget.SettingsThemeHelper;
/**
* Custom preference for displaying the {@link Preference} with an optional hint chip.
*/
public class WarningFramePreference extends Preference {
private final int mTitleColorNormal;
private final int mSummaryColorNormal;
private final int mWarningChipBackgroundResId;
private final boolean mIsExpressiveTheme;
@Nullable private CharSequence mHintText;
public WarningFramePreference(Context context, AttributeSet attrs) {
super(context, attrs);
mIsExpressiveTheme = SettingsThemeHelper.isExpressiveTheme(context);
int layoutResId =
mIsExpressiveTheme
? R.layout.expressive_warning_frame_preference
: R.layout.warning_frame_preference;
setLayoutResource(layoutResId);
mWarningChipBackgroundResId =
mIsExpressiveTheme
? R.drawable.expressive_battery_hints_chip_bg_ripple
: R.drawable.battery_hints_chip_bg_ripple;
mTitleColorNormal =
Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
mSummaryColorNormal =
Utils.getColorAttrDefaultColor(context, android.R.attr.textColorSecondary);
}
/** Sets the text of hint to show. */
public void setHint(@Nullable CharSequence hintText) {
if (!TextUtils.equals(mHintText, hintText)) {
mHintText = hintText;
notifyChanged();
}
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
if (mIsExpressiveTheme) {
final View preferenceFrame = view.findViewById(R.id.preference_frame);
preferenceFrame.setBackground(null);
preferenceFrame.setPadding(0, 0, 0, 0);
}
final View warningChipFrame = view.findViewById(R.id.warning_chip_frame);
warningChipFrame
.findViewById(R.id.warning_padding_placeholder)
.setVisibility(getIcon() != null ? View.VISIBLE : View.GONE);
if (!TextUtils.isEmpty(mHintText)) {
((TextView) warningChipFrame.findViewById(R.id.warning_info)).setText(mHintText);
warningChipFrame.setVisibility(View.VISIBLE);
warningChipFrame
.findViewById(R.id.warning_chip)
.setBackgroundResource(mWarningChipBackgroundResId);
} else {
warningChipFrame.setVisibility(View.GONE);
}
((TextView) view.findViewById(android.R.id.title)).setTextColor(mTitleColorNormal);
((TextView) view.findViewById(android.R.id.summary)).setTextColor(mSummaryColorNormal);
}
}

View File

@@ -1,61 +0,0 @@
/*
* 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.annotation.Nullable;
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
class AnomalyAppItemPreference extends PowerGaugePreference {
private static final String TAG = "AnomalyAppItemPreference";
private CharSequence mAnomalyHintText;
AnomalyAppItemPreference(Context context) {
super(context, /* attrs */ null);
setLayoutResource(R.layout.anomaly_app_item_preference);
}
void setAnomalyHint(@Nullable CharSequence anomalyHintText) {
if (!TextUtils.equals(mAnomalyHintText, anomalyHintText)) {
mAnomalyHintText = anomalyHintText;
notifyChanged();
}
}
@Override
public void onBindViewHolder(PreferenceViewHolder viewHolder) {
super.onBindViewHolder(viewHolder);
final LinearLayout warningChipView =
(LinearLayout) viewHolder.findViewById(R.id.warning_chip);
if (!TextUtils.isEmpty(mAnomalyHintText)) {
((TextView) warningChipView.findViewById(R.id.warning_info)).setText(mAnomalyHintText);
warningChipView.setVisibility(View.VISIBLE);
} else {
warningChipView.setVisibility(View.GONE);
}
}
}

View File

@@ -381,15 +381,15 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
continue; continue;
} }
final String prefKey = entry.getKey(); final String prefKey = entry.getKey();
AnomalyAppItemPreference preference = mRootPreferenceGroup.findPreference(prefKey); PowerGaugePreference preference = mRootPreferenceGroup.findPreference(prefKey);
if (preference != null) { if (preference != null) {
isAdded = true; isAdded = true;
} else { } else {
preference = (AnomalyAppItemPreference) mPreferenceCache.get(prefKey); preference = (PowerGaugePreference) mPreferenceCache.get(prefKey);
} }
// Creates new instance if cached preference is not found. // Creates new instance if cached preference is not found.
if (preference == null) { if (preference == null) {
preference = new AnomalyAppItemPreference(mPrefContext); preference = new PowerGaugePreference(mPrefContext);
preference.setKey(prefKey); preference.setKey(prefKey);
mPreferenceCache.put(prefKey, preference); mPreferenceCache.put(prefKey, preference);
} }
@@ -398,7 +398,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
preference.setOrder(++preferenceOrder); preference.setOrder(++preferenceOrder);
preference.setSingleLineTitle(true); preference.setSingleLineTitle(true);
// Updates App item preference style // Updates App item preference style
preference.setAnomalyHint(isAnomalyBatteryDiffEntry(entry) ? mAnomalyHintString : null); preference.setHint(isAnomalyBatteryDiffEntry(entry) ? mAnomalyHintString : null);
// Sets the BatteryDiffEntry to preference for launching detailed page. // Sets the BatteryDiffEntry to preference for launching detailed page.
preference.setBatteryDiffEntry(entry); preference.setBatteryDiffEntry(entry);
preference.setSelectable(entry.validForRestriction()); preference.setSelectable(entry.validForRestriction());

View File

@@ -28,7 +28,7 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settingslib.widget.AppPreference; import com.android.settings.fuelgauge.WarningFramePreference;
/** /**
* Custom preference for displaying battery usage info as a bar and an icon on the left for the * Custom preference for displaying battery usage info as a bar and an icon on the left for the
@@ -37,7 +37,7 @@ import com.android.settingslib.widget.AppPreference;
* <p>The battery usage info could be usage percentage or usage time. The preference won't show any * <p>The battery usage info could be usage percentage or usage time. The preference won't show any
* icon if it is null. * icon if it is null.
*/ */
public class PowerGaugePreference extends AppPreference { public class PowerGaugePreference extends WarningFramePreference {
// Please see go/battery-usage-app-list-alpha // Please see go/battery-usage-app-list-alpha
private static final float SELECTABLE_ALPHA = 1f; private static final float SELECTABLE_ALPHA = 1f;
@@ -51,7 +51,6 @@ public class PowerGaugePreference extends AppPreference {
private CharSequence mContentDescription; private CharSequence mContentDescription;
private CharSequence mProgress; private CharSequence mProgress;
private CharSequence mProgressContentDescription; private CharSequence mProgressContentDescription;
private boolean mShowAnomalyIcon;
public PowerGaugePreference( public PowerGaugePreference(
Context context, Drawable icon, CharSequence contentDescription, BatteryEntry info) { Context context, Drawable icon, CharSequence contentDescription, BatteryEntry info) {
@@ -79,7 +78,6 @@ public class PowerGaugePreference extends AppPreference {
setWidgetLayoutResource(R.layout.preference_widget_summary); setWidgetLayoutResource(R.layout.preference_widget_summary);
mInfo = info; mInfo = info;
mContentDescription = contentDescription; mContentDescription = contentDescription;
mShowAnomalyIcon = false;
mTitleColorNormal = mTitleColorNormal =
Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary); Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
} }
@@ -108,17 +106,6 @@ public class PowerGaugePreference extends AppPreference {
return mProgress.toString(); return mProgress.toString();
} }
/** Sets whether to show anomaly icon */
public void shouldShowAnomalyIcon(boolean showAnomalyIcon) {
mShowAnomalyIcon = showAnomalyIcon;
notifyChanged();
}
/** Gets whether to show anomaly icon */
public boolean showAnomalyIcon() {
return mShowAnomalyIcon;
}
public void setBatteryDiffEntry(BatteryDiffEntry entry) { public void setBatteryDiffEntry(BatteryDiffEntry entry) {
mBatteryDiffEntry = entry; mBatteryDiffEntry = entry;
} }
@@ -149,12 +136,6 @@ public class PowerGaugePreference extends AppPreference {
if (!TextUtils.isEmpty(mProgressContentDescription)) { if (!TextUtils.isEmpty(mProgressContentDescription)) {
subtitle.setContentDescription(mProgressContentDescription); subtitle.setContentDescription(mProgressContentDescription);
} }
if (mShowAnomalyIcon) {
subtitle.setCompoundDrawablesRelativeWithIntrinsicBounds(
R.drawable.ic_warning_24dp, 0, 0, 0);
} else {
subtitle.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0);
}
if (mContentDescription != null) { if (mContentDescription != null) {
final TextView titleView = (TextView) view.findViewById(android.R.id.title); final TextView titleView = (TextView) view.findViewById(android.R.id.title);
titleView.setContentDescription(mContentDescription); titleView.setContentDescription(mContentDescription);

View File

@@ -99,9 +99,9 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyOnePreferenceInvisible(mBackgroundTimePreference); verifyOnePreferenceInvisible(mBackgroundTimePreference);
verify(mScreenTimePreference).setTimeTitle("Screen time"); verify(mScreenTimePreference).setTitle("Screen time");
verify(mScreenTimePreference).setTimeSummary("1 min"); verify(mScreenTimePreference).setSummary("1 min");
verify(mScreenTimePreference, never()).setAnomalyHint(anyString()); verify(mScreenTimePreference, never()).setHint(anyString());
} }
@Test @Test
@@ -117,9 +117,9 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyOnePreferenceInvisible(mScreenTimePreference); verifyOnePreferenceInvisible(mScreenTimePreference);
verify(mBackgroundTimePreference).setTimeTitle("Background time"); verify(mBackgroundTimePreference).setTitle("Background time");
verify(mBackgroundTimePreference).setTimeSummary("2 min"); verify(mBackgroundTimePreference).setSummary("2 min");
verify(mBackgroundTimePreference, never()).setAnomalyHint(anyString()); verify(mBackgroundTimePreference, never()).setHint(anyString());
} }
@Test @Test
@@ -135,12 +135,12 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeTitle("Screen time"); verify(mScreenTimePreference).setTitle("Screen time");
verify(mScreenTimePreference).setTimeSummary("1 min"); verify(mScreenTimePreference).setSummary("1 min");
verify(mScreenTimePreference, never()).setAnomalyHint(anyString()); verify(mScreenTimePreference, never()).setHint(anyString());
verify(mBackgroundTimePreference).setTimeTitle("Background time"); verify(mBackgroundTimePreference).setTitle("Background time");
verify(mBackgroundTimePreference).setTimeSummary("2 min"); verify(mBackgroundTimePreference).setSummary("2 min");
verify(mBackgroundTimePreference, never()).setAnomalyHint(anyString()); verify(mBackgroundTimePreference, never()).setHint(anyString());
verify(mPowerUsageTimeCategory).setTitle("App usage for 12 am-2 am"); verify(mPowerUsageTimeCategory).setTitle("App usage for 12 am-2 am");
} }
@@ -173,8 +173,8 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeSummary("1 min"); verify(mScreenTimePreference).setSummary("1 min");
verify(mBackgroundTimePreference).setTimeSummary("Less than a minute"); verify(mBackgroundTimePreference).setSummary("Less than a minute");
} }
@Test @Test
@@ -190,8 +190,8 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeSummary("Less than a minute"); verify(mScreenTimePreference).setSummary("Less than a minute");
verify(mBackgroundTimePreference).setTimeSummary("2 min"); verify(mBackgroundTimePreference).setSummary("2 min");
} }
@Test @Test
@@ -207,8 +207,8 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeSummary("Less than a minute"); verify(mScreenTimePreference).setSummary("Less than a minute");
verify(mBackgroundTimePreference).setTimeSummary("Less than a minute"); verify(mBackgroundTimePreference).setSummary("Less than a minute");
} }
@Test @Test
@@ -224,8 +224,8 @@ public final class PowerUsageTimeControllerTest {
TEST_ANOMALY_HINT_TEXT); TEST_ANOMALY_HINT_TEXT);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setAnomalyHint(TEST_ANOMALY_HINT_TEXT); verify(mScreenTimePreference).setHint(TEST_ANOMALY_HINT_TEXT);
verify(mBackgroundTimePreference, never()).setAnomalyHint(anyString()); verify(mBackgroundTimePreference, never()).setHint(anyString());
} }
@Test @Test
@@ -241,8 +241,8 @@ public final class PowerUsageTimeControllerTest {
TEST_ANOMALY_HINT_TEXT); TEST_ANOMALY_HINT_TEXT);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference, never()).setAnomalyHint(anyString()); verify(mScreenTimePreference, never()).setHint(anyString());
verify(mBackgroundTimePreference).setAnomalyHint(TEST_ANOMALY_HINT_TEXT); verify(mBackgroundTimePreference).setHint(TEST_ANOMALY_HINT_TEXT);
} }
@Test @Test
@@ -258,9 +258,9 @@ public final class PowerUsageTimeControllerTest {
TEST_ANOMALY_HINT_TEXT); TEST_ANOMALY_HINT_TEXT);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeSummary("Less than a minute"); verify(mScreenTimePreference).setSummary("Less than a minute");
verify(mScreenTimePreference).setAnomalyHint(TEST_ANOMALY_HINT_TEXT); verify(mScreenTimePreference).setHint(TEST_ANOMALY_HINT_TEXT);
verify(mBackgroundTimePreference, never()).setAnomalyHint(anyString()); verify(mBackgroundTimePreference, never()).setHint(anyString());
} }
private void verifySetPrefToVisible(Preference pref, boolean isVisible) { private void verifySetPrefToVisible(Preference pref, boolean isVisible) {

View File

@@ -67,7 +67,7 @@ public final class BatteryUsageBreakdownControllerTest {
@Mock private PreferenceGroup mRootPreferenceGroup; @Mock private PreferenceGroup mRootPreferenceGroup;
@Mock private Drawable mDrawable; @Mock private Drawable mDrawable;
@Mock private BatteryHistEntry mBatteryHistEntry; @Mock private BatteryHistEntry mBatteryHistEntry;
@Mock private AnomalyAppItemPreference mAnomalyAppItemPreference; @Mock private PowerGaugePreference mPowerGaugePreference;
private Context mContext; private Context mContext;
private FakeFeatureFactory mFeatureFactory; private FakeFeatureFactory mFeatureFactory;
@@ -131,13 +131,13 @@ public final class BatteryUsageBreakdownControllerTest {
BatteryDiffEntry.sResourceCache.put( BatteryDiffEntry.sResourceCache.put(
"fakeBatteryDiffEntryKey", "fakeBatteryDiffEntryKey",
new BatteryEntry.NameAndIcon("fakeName", /* icon= */ null, /* iconId= */ 1)); new BatteryEntry.NameAndIcon("fakeName", /* icon= */ null, /* iconId= */ 1));
doReturn(mAnomalyAppItemPreference).when(mRootPreferenceGroup).findPreference(PREF_KEY); doReturn(mPowerGaugePreference).when(mRootPreferenceGroup).findPreference(PREF_KEY);
} }
@Test @Test
public void onDestroy_clearPreferenceCacheAndPreferenceGroupRemoveAll() { public void onDestroy_clearPreferenceCacheAndPreferenceGroupRemoveAll() {
// Ensures the testing environment is correct. // Ensures the testing environment is correct.
mBatteryUsageBreakdownController.mPreferenceCache.put(PREF_KEY, mAnomalyAppItemPreference); mBatteryUsageBreakdownController.mPreferenceCache.put(PREF_KEY, mPowerGaugePreference);
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).hasSize(1); assertThat(mBatteryUsageBreakdownController.mPreferenceCache).hasSize(1);
mBatteryUsageBreakdownController.onDestroy(); mBatteryUsageBreakdownController.onDestroy();
@@ -204,25 +204,25 @@ public final class BatteryUsageBreakdownControllerTest {
@Test @Test
public void removeAndCacheAllUnusedPreferences_removePref_buildCacheAndRemoveAllPreference() { public void removeAndCacheAllUnusedPreferences_removePref_buildCacheAndRemoveAllPreference() {
doReturn(1).when(mRootPreferenceGroup).getPreferenceCount(); doReturn(1).when(mRootPreferenceGroup).getPreferenceCount();
doReturn(mAnomalyAppItemPreference).when(mRootPreferenceGroup).getPreference(0); doReturn(mPowerGaugePreference).when(mRootPreferenceGroup).getPreference(0);
doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey(); doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey();
doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey(); doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
// Ensures the testing data is correct. // Ensures the testing data is correct.
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty(); assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences(); mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences();
assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY)) assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY))
.isEqualTo(mAnomalyAppItemPreference); .isEqualTo(mPowerGaugePreference);
verify(mRootPreferenceGroup).removePreference(mAnomalyAppItemPreference); verify(mRootPreferenceGroup).removePreference(mPowerGaugePreference);
} }
@Test @Test
public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() { public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
doReturn(1).when(mRootPreferenceGroup).getPreferenceCount(); doReturn(1).when(mRootPreferenceGroup).getPreferenceCount();
doReturn(mAnomalyAppItemPreference).when(mRootPreferenceGroup).getPreference(0); doReturn(mPowerGaugePreference).when(mRootPreferenceGroup).getPreference(0);
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey(); doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey(); doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
// Ensures the testing data is correct. // Ensures the testing data is correct.
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty(); assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
@@ -246,11 +246,11 @@ public final class BatteryUsageBreakdownControllerTest {
@Test @Test
public void handlePreferenceTreeClick_forAppEntry_returnTrue() { public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry(); doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
assertThat( assertThat(
mBatteryUsageBreakdownController.handlePreferenceTreeClick( mBatteryUsageBreakdownController.handlePreferenceTreeClick(
mAnomalyAppItemPreference)) mPowerGaugePreference))
.isTrue(); .isTrue();
verify(mMetricsFeatureProvider) verify(mMetricsFeatureProvider)
.action( .action(
@@ -264,11 +264,11 @@ public final class BatteryUsageBreakdownControllerTest {
@Test @Test
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() { public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY; mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry(); doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
assertThat( assertThat(
mBatteryUsageBreakdownController.handlePreferenceTreeClick( mBatteryUsageBreakdownController.handlePreferenceTreeClick(
mAnomalyAppItemPreference)) mPowerGaugePreference))
.isTrue(); .isTrue();
verify(mMetricsFeatureProvider) verify(mMetricsFeatureProvider)
.action( .action(

View File

@@ -19,19 +19,20 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.Space;
import androidx.preference.PreferenceViewHolder; import androidx.preference.PreferenceViewHolder;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.widget.SettingsThemeHelper;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
@@ -48,17 +49,17 @@ public class PowerGaugePreferenceTest {
private View mWidgetView; private View mWidgetView;
private PreferenceViewHolder mPreferenceViewHolder; private PreferenceViewHolder mPreferenceViewHolder;
@Mock Drawable mMockIcon;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = RuntimeEnvironment.application;
mPowerGaugePreference = new PowerGaugePreference(mContext);
mRootView = mRootView =
LayoutInflater.from(mContext) LayoutInflater.from(mContext)
.inflate( .inflate(mPowerGaugePreference.getLayoutResource(), null);
com.android.settingslib.widget.preference.app.R.layout
.preference_app,
null);
mWidgetView = mWidgetView =
LayoutInflater.from(mContext).inflate(R.layout.preference_widget_summary, null); LayoutInflater.from(mContext).inflate(R.layout.preference_widget_summary, null);
final LinearLayout widgetFrame = mRootView.findViewById(android.R.id.widget_frame); final LinearLayout widgetFrame = mRootView.findViewById(android.R.id.widget_frame);
@@ -66,31 +67,56 @@ public class PowerGaugePreferenceTest {
widgetFrame.addView(mWidgetView); widgetFrame.addView(mWidgetView);
mPreferenceViewHolder = PreferenceViewHolder.createInstanceForTests(mRootView); mPreferenceViewHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
mPowerGaugePreference = new PowerGaugePreference(mContext);
assertThat(mPowerGaugePreference.getLayoutResource()) assertThat(mPowerGaugePreference.getLayoutResource())
.isEqualTo(com.android.settingslib.widget.preference.app.R.layout.preference_app); .isEqualTo(
SettingsThemeHelper.isExpressiveTheme(mContext)
? R.layout.expressive_warning_frame_preference
: R.layout.warning_frame_preference);
} }
@Test @Test
public void testOnBindViewHolder_showAnomaly_bindAnomalyIcon() { public void testOnBindViewHolder_showHint_hasHintChip() {
mPowerGaugePreference.shouldShowAnomalyIcon(true); mPowerGaugePreference.setHint("Hint Text");
mPowerGaugePreference.setIcon(mMockIcon);
mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder); mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder);
TextView widgetSummary = (TextView) mPreferenceViewHolder.findViewById(R.id.widget_summary); final LinearLayout warningChipFrame =
final Drawable[] drawables = widgetSummary.getCompoundDrawablesRelative(); (LinearLayout) mPreferenceViewHolder.findViewById(R.id.warning_chip_frame);
final Space warningPaddingPlaceHolder =
warningChipFrame.findViewById(R.id.warning_padding_placeholder);
assertThat(drawables[0]).isInstanceOf(VectorDrawable.class); assertThat(warningChipFrame.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(warningPaddingPlaceHolder.getVisibility()).isEqualTo(View.VISIBLE);
} }
@Test @Test
public void testOnBindViewHolder_notShowAnomaly_bindAnomalyIcon() { public void testOnBindViewHolder_emptyHintText_withoutHintChip() {
mPowerGaugePreference.shouldShowAnomalyIcon(false); mPowerGaugePreference.setHint("");
mPowerGaugePreference.setIcon(mMockIcon);
mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder); mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder);
TextView widgetSummary = (TextView) mPreferenceViewHolder.findViewById(R.id.widget_summary); final LinearLayout warningChipFrame =
final Drawable[] drawables = widgetSummary.getCompoundDrawablesRelative(); (LinearLayout) mPreferenceViewHolder.findViewById(R.id.warning_chip_frame);
final Space warningPaddingPlaceholder =
warningChipFrame.findViewById(R.id.warning_padding_placeholder);
assertThat(drawables[0]).isNull(); assertThat(warningChipFrame.getVisibility()).isEqualTo(View.GONE);
assertThat(warningPaddingPlaceholder.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void testOnBindViewHolder_noAppIconWithHintText_hasChipWithoutPaddingPlaceholder() {
mPowerGaugePreference.setHint("Anomaly Hint Text");
mPowerGaugePreference.setIcon(null);
mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder);
final LinearLayout warningChipFrame =
(LinearLayout) mPreferenceViewHolder.findViewById(R.id.warning_chip_frame);
final Space warningPaddingPlaceHolder =
warningChipFrame.findViewById(R.id.warning_padding_placeholder);
assertThat(warningChipFrame.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(warningPaddingPlaceHolder.getVisibility()).isEqualTo(View.GONE);
} }
@Test @Test