Migrate Spinner on Battery Usage to settingsLib Spinner widget.

Bug: 359429437
Test: visual
Test: atest BatteryUsageBreakdownControllerTest
Flag: EXEMPT bug fix
Change-Id: I71bd1f31db302d407603c71d1a1163ed22fafed8
This commit is contained in:
mxyyiyi
2024-08-16 12:33:51 +08:00
parent a2c65ecec4
commit 05e857de6a
6 changed files with 46 additions and 246 deletions

View File

@@ -1,24 +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.
-->
<Spinner
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:theme="@style/Widget.PopupWindow.Settings" />

View File

@@ -57,7 +57,7 @@
"com.android.settings.fuelgauge.batteryusage.BatteryUsageBreakdownController"
settings:isPreferenceVisible="false">
<com.android.settings.fuelgauge.batteryusage.SpinnerPreference
<com.android.settingslib.widget.SettingsSpinnerPreference
android:key="battery_usage_spinner"
settings:isPreferenceVisible="false" />

View File

@@ -20,6 +20,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
@@ -46,9 +47,13 @@ import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.SettingsSpinnerAdapter;
import com.android.settingslib.widget.SettingsSpinnerPreference;
import java.util.ArrayList;
import java.util.List;
@@ -58,7 +63,7 @@ import java.util.Set;
/** Controller for battery usage breakdown preference group. */
public class BatteryUsageBreakdownController extends BasePreferenceController
implements LifecycleObserver, OnResume, OnDestroy {
implements LifecycleObserver, OnResume, OnDestroy, OnCreate, OnSaveInstanceState {
private static final String TAG = "BatteryUsageBreakdownController";
private static final String ROOT_PREFERENCE_KEY = "battery_usage_breakdown";
private static final String FOOTER_PREFERENCE_KEY = "battery_usage_footer";
@@ -67,6 +72,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
private static final String PACKAGE_NAME_NONE = "none";
private static final String SLOT_TIMESTAMP = "slot_timestamp";
private static final String ANOMALY_KEY = "anomaly_key";
private static final String KEY_SPINNER_POSITION = "spinner_position";
private static final List<BatteryDiffEntry> EMPTY_ENTRY_LIST = new ArrayList<>();
private static int sUiMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
@@ -78,12 +84,12 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
@VisibleForTesting final Map<String, Preference> mPreferenceCache = new ArrayMap<>();
private int mSpinnerPosition;
private String mSlotInformation;
private SettingsSpinnerPreference mSpinnerPreference;
private SettingsSpinnerAdapter<CharSequence> mSpinnerAdapter;
@VisibleForTesting Context mPrefContext;
@VisibleForTesting PreferenceCategory mRootPreference;
@VisibleForTesting SpinnerPreference mSpinnerPreference;
@VisibleForTesting PreferenceGroup mAppListPreferenceGroup;
@VisibleForTesting FooterPreference mFooterPreference;
@VisibleForTesting BatteryDiffData mBatteryDiffData;
@@ -92,6 +98,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
@VisibleForTesting String mPercentLessThanThresholdContentDescription;
@VisibleForTesting boolean mIsHighlightSlot;
@VisibleForTesting int mAnomalyKeyNumber;
@VisibleForTesting int mSpinnerPosition;
@VisibleForTesting String mAnomalyEntryKey;
@VisibleForTesting String mAnomalyHintString;
@VisibleForTesting String mAnomalyHintPrefKey;
@@ -110,6 +117,15 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState == null) {
return;
}
mSpinnerPosition = savedInstanceState.getInt(KEY_SPINNER_POSITION, mSpinnerPosition);
Log.d(TAG, "onCreate() spinnerPosition=" + mSpinnerPosition);
}
@Override
public void onResume() {
final int currentUiMode =
@@ -140,6 +156,15 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
return false;
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
if (savedInstanceState == null) {
return;
}
savedInstanceState.putInt(KEY_SPINNER_POSITION, mSpinnerPosition);
Log.d(TAG, "onSaveInstanceState() spinnerPosition=" + mSpinnerPosition);
}
private boolean isAnomalyBatteryDiffEntry(BatteryDiffEntry entry) {
return mIsHighlightSlot
&& mAnomalyEntryKey != null
@@ -218,11 +243,14 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
formatPercentage);
mAppListPreferenceGroup.setOrderingAsAdded(false);
mSpinnerPreference.initializeSpinner(
mSpinnerAdapter = new SettingsSpinnerAdapter<>(mPrefContext);
mSpinnerAdapter.addAll(
new String[] {
mPrefContext.getString(R.string.battery_usage_spinner_view_by_apps),
mPrefContext.getString(R.string.battery_usage_spinner_view_by_systems)
},
});
mSpinnerPreference.setAdapter(mSpinnerAdapter);
mSpinnerPreference.setOnItemSelectedListener(
new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(
@@ -244,6 +272,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
mSpinnerPreference.setSelection(mSpinnerPosition);
}
/**

View File

@@ -1,134 +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.content.Context;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.AdapterView;
import android.widget.Spinner;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settingslib.widget.SettingsSpinnerAdapter;
/** A preference which contains a spinner. */
public class SpinnerPreference extends Preference {
private static final String TAG = "SpinnerPreference";
private AdapterView.OnItemSelectedListener mOnItemSelectedListener;
@VisibleForTesting Spinner mSpinner;
@VisibleForTesting String[] mItems;
@VisibleForTesting int mSavedSpinnerPosition;
public SpinnerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.preference_spinner);
}
void initializeSpinner(
String[] items, AdapterView.OnItemSelectedListener onItemSelectedListener) {
mItems = items;
mOnItemSelectedListener = onItemSelectedListener;
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
if (mSpinner != null) {
return;
}
mSpinner = (Spinner) view.findViewById(R.id.spinner);
mSpinner.setAdapter(new SpinnerAdapter(getContext(), mItems));
mSpinner.setSelection(mSavedSpinnerPosition);
mSpinner.setLongClickable(false);
if (mOnItemSelectedListener != null) {
mSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
}
}
@Override
protected Parcelable onSaveInstanceState() {
if (mSpinner == null) {
return super.onSaveInstanceState();
}
Log.d(TAG, "onSaveInstanceState() spinnerPosition=" + mSpinner.getSelectedItemPosition());
return new SavedState(super.onSaveInstanceState(), mSpinner.getSelectedItemPosition());
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || state == BaseSavedState.EMPTY_STATE) {
super.onRestoreInstanceState(state);
return;
}
if (!(state instanceof SavedState)) {
// To avoid the IllegalArgumentException, return the BaseSavedState.EMPTY_STATE.
super.onRestoreInstanceState(BaseSavedState.EMPTY_STATE);
return;
}
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
mSavedSpinnerPosition = savedState.getSpinnerPosition();
if (mOnItemSelectedListener != null) {
mOnItemSelectedListener.onItemSelected(
/* parent= */ null,
/* view= */ null,
savedState.getSpinnerPosition(),
/* id= */ 0);
}
Log.d(TAG, "onRestoreInstanceState() spinnerPosition=" + savedState.getSpinnerPosition());
}
@VisibleForTesting
static class SavedState extends BaseSavedState {
private int mSpinnerPosition;
SavedState(Parcelable superState, int spinnerPosition) {
super(superState);
mSpinnerPosition = spinnerPosition;
}
int getSpinnerPosition() {
return mSpinnerPosition;
}
}
private static class SpinnerAdapter extends SettingsSpinnerAdapter<CharSequence> {
private final String[] mItems;
SpinnerAdapter(Context context, String[] items) {
super(context);
mItems = items;
}
@Override
public int getCount() {
return mItems.length;
}
@Override
public CharSequence getItem(int position) {
return mItems[position];
}
}
}

View File

@@ -29,6 +29,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.LocaleList;
import android.text.format.DateUtils;
@@ -57,6 +58,7 @@ public final class BatteryUsageBreakdownControllerTest {
private static final String PREF_KEY = "pref_key";
private static final String PREF_KEY2 = "pref_key2";
private static final String PREF_SUMMARY = "fake preference summary";
private static final String KEY_SPINNER_POSITION = "spinner_position";
private static final long TIME_LESS_THAN_HALF_MINUTE = DateUtils.MINUTE_IN_MILLIS / 2 - 1;
@Mock private InstrumentedPreferenceFragment mFragment;
@@ -148,6 +150,15 @@ public final class BatteryUsageBreakdownControllerTest {
verify(mAppListPreferenceGroup).removeAll();
}
@Test
public void onSaveInstanceState_returnExpectedResult() {
mBatteryUsageBreakdownController.mSpinnerPosition = 1;
final Bundle savedInstanceState = new Bundle();
mBatteryUsageBreakdownController.onSaveInstanceState(savedInstanceState);
assertThat(savedInstanceState.getInt(KEY_SPINNER_POSITION)).isEqualTo(1);
}
@Test
public void addAllPreferences_addAllPreferences() {
final String appLabel = "fake app label";

View File

@@ -1,82 +0,0 @@
/*
* Copyright (C) 2022 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.doReturn;
import static org.mockito.Mockito.spy;
import android.content.Context;
import android.widget.Spinner;
import androidx.preference.Preference;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public final class SpinnerPreferenceTest {
private Context mContext;
private SpinnerPreference mSpinnerPreference;
@Mock private Spinner mMockSpinner;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mSpinnerPreference = new SpinnerPreference(mContext, /* attrs= */ null);
}
@Test
public void constructor_returnExpectedResult() {
assertThat(mSpinnerPreference.getLayoutResource()).isEqualTo(R.layout.preference_spinner);
}
@Test
public void initializeSpinner_returnExpectedResult() {
final String[] items = new String[] {"item1", "item2"};
mSpinnerPreference.initializeSpinner(items, null);
assertThat(mSpinnerPreference.mItems).isEqualTo(items);
}
@Test
public void onSaveInstanceState_returnExpectedResult() {
doReturn(1).when(mMockSpinner).getSelectedItemPosition();
mSpinnerPreference.mSpinner = mMockSpinner;
SpinnerPreference.SavedState savedState =
(SpinnerPreference.SavedState) mSpinnerPreference.onSaveInstanceState();
assertThat(savedState.getSpinnerPosition()).isEqualTo(1);
}
@Test
public void onRestoreInstanceState_returnExpectedResult() {
SpinnerPreference.SavedState savedState =
new SpinnerPreference.SavedState(Preference.BaseSavedState.EMPTY_STATE, 2);
mSpinnerPreference.onRestoreInstanceState(savedState);
assertThat(mSpinnerPreference.mSavedSpinnerPosition).isEqualTo(2);
}
}