diff --git a/res/layout/preference_tab.xml b/res/layout/preference_spinner.xml similarity index 51% rename from res/layout/preference_tab.xml rename to res/layout/preference_spinner.xml index f9a78819550..41293033841 100644 --- a/res/layout/preference_tab.xml +++ b/res/layout/preference_spinner.xml @@ -1,6 +1,5 @@ - - - - - - - - + android:layout_marginStart="24dp" + android:layout_marginTop="8dp" + android:theme="@style/Widget.PopupWindow.Settings" /> diff --git a/res/values/strings.xml b/res/values/strings.xml index 927f84d046f..c64ba93fee3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5175,13 +5175,13 @@ Hourly battery usage chart - Usage proportional breakdown since last full charge + Battery usage since last full charge - Usage proportional breakdown for %s - - App - - System + Battery usage for %s + + Breakdown by apps + + Breakdown by system diff --git a/res/xml/power_usage_advanced.xml b/res/xml/power_usage_advanced.xml index 4371995b71d..af6152abfd2 100644 --- a/res/xml/power_usage_advanced.xml +++ b/res/xml/power_usage_advanced.xml @@ -32,8 +32,8 @@ "com.android.settings.fuelgauge.batteryusage.BatteryUsageBreakdownController" settings:isPreferenceVisible="false"> - mPreferenceCache = new HashMap<>(); - private int mTabPosition; + private int mSpinnerPosition; private String mSlotTimestamp; @VisibleForTesting @@ -77,7 +78,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController @VisibleForTesting PreferenceCategory mRootPreference; @VisibleForTesting - TabPreference mTabPreference; + SpinnerPreference mSpinnerPreference; @VisibleForTesting PreferenceGroup mAppListPreferenceGroup; @VisibleForTesting @@ -145,26 +146,33 @@ public class BatteryUsageBreakdownController extends BasePreferenceController super.displayPreference(screen); mPrefContext = screen.getContext(); mRootPreference = screen.findPreference(ROOT_PREFERENCE_KEY); - mTabPreference = screen.findPreference(TAB_PREFERENCE_KEY); + mSpinnerPreference = screen.findPreference(SPINNER_PREFERENCE_KEY); mAppListPreferenceGroup = screen.findPreference(APP_LIST_PREFERENCE_KEY); mFooterPreference = screen.findPreference(FOOTER_PREFERENCE_KEY); mAppListPreferenceGroup.setOrderingAsAdded(false); - mTabPreference.initializeTabs(mFragment, new String[]{ - mPrefContext.getString(R.string.battery_usage_app_tab), - mPrefContext.getString(R.string.battery_usage_system_tab) - }); - mTabPreference.setOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { - @Override - public void onPageSelected(int position) { - super.onPageSelected(position); - mTabPosition = position; - mHandler.post(() -> { - removeAndCacheAllPreferences(); - addAllPreferences(); + mSpinnerPreference.initializeSpinner( + new String[]{ + mPrefContext.getString(R.string.battery_usage_spinner_breakdown_by_apps), + mPrefContext.getString(R.string.battery_usage_spinner_breakdown_by_system) + }, + new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected( + AdapterView parent, View view, int position, long id) { + if (mSpinnerPosition != position) { + mSpinnerPosition = position; + mHandler.post(() -> { + removeAndCacheAllPreferences(); + addAllPreferences(); + }); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + } }); - } - }); } /** @@ -182,7 +190,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController mSlotTimestamp = slotTimestamp; showCategoryTitle(slotTimestamp); - showTabAndAppList(); + showSpinnerAndAppList(); showFooterPreference(isAllUsageDataEmpty); } @@ -204,12 +212,12 @@ public class BatteryUsageBreakdownController extends BasePreferenceController mFooterPreference.setVisible(true); } - private void showTabAndAppList() { + private void showSpinnerAndAppList() { removeAndCacheAllPreferences(); if (mBatteryDiffData == null) { return; } - mTabPreference.setVisible(true); + mSpinnerPreference.setVisible(true); mAppListPreferenceGroup.setVisible(true); mHandler.post(() -> { addAllPreferences(); @@ -222,7 +230,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController return; } final long start = System.currentTimeMillis(); - final List entries = mTabPosition == 0 + final List entries = mSpinnerPosition == 0 ? mBatteryDiffData.getAppDiffEntryList() : mBatteryDiffData.getSystemDiffEntryList(); int prefIndex = mAppListPreferenceGroup.getPreferenceCount(); diff --git a/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java new file mode 100644 index 00000000000..47e051c2c0d --- /dev/null +++ b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java @@ -0,0 +1,121 @@ +/* + * 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) { + mSpinner = (Spinner) view.findViewById(R.id.spinner); + mSpinner.setAdapter(new SpinnerAdapter(getContext(), mItems)); + mSpinner.setSelection(mSavedSpinnerPosition); + if (mOnItemSelectedListener != null) { + mSpinner.setOnItemSelectedListener(mOnItemSelectedListener); + } + } + + @Override + protected Parcelable 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.getClass().equals(SavedState.class)) { + super.onRestoreInstanceState(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 { + 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]; + } + } +} diff --git a/src/com/android/settings/fuelgauge/batteryusage/TabPreference.java b/src/com/android/settings/fuelgauge/batteryusage/TabPreference.java deleted file mode 100644 index 0c5a69977e4..00000000000 --- a/src/com/android/settings/fuelgauge/batteryusage/TabPreference.java +++ /dev/null @@ -1,152 +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 android.content.Context; -import android.os.Parcelable; -import android.util.AttributeSet; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; -import androidx.viewpager2.adapter.FragmentStateAdapter; -import androidx.viewpager2.widget.ViewPager2; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.settings.R; - -import com.google.android.material.tabs.TabLayout; -import com.google.android.material.tabs.TabLayoutMediator; - -/** A preference which contains a tab selection. */ -public class TabPreference extends Preference { - private static final String TAG = "TabPreference"; - - private Fragment mRootFragment; - private ViewPager2 mViewPager; - private ViewPager2.OnPageChangeCallback mOnPageChangeCallback; - - @VisibleForTesting - String[] mTabTitles; - @VisibleForTesting - int mSavedTabPosition; - @VisibleForTesting - TabLayout mTabLayout; - - public TabPreference(Context context, AttributeSet attrs) { - super(context, attrs); - setLayoutResource(R.layout.preference_tab); - } - - void initializeTabs(Fragment rootFragment, String[] tabTitles) { - mRootFragment = rootFragment; - mTabTitles = tabTitles; - } - - void setOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback) { - mOnPageChangeCallback = callback; - } - - @Override - public void onBindViewHolder(PreferenceViewHolder view) { - super.onBindViewHolder(view); - if (mViewPager != null && mTabLayout != null) { - return; - } - - mViewPager = (ViewPager2) view.findViewById(R.id.view_pager); - mViewPager.setAdapter(new FragmentAdapter(mRootFragment, mTabTitles.length)); - mViewPager.setUserInputEnabled(false); - if (mOnPageChangeCallback != null) { - mViewPager.registerOnPageChangeCallback(mOnPageChangeCallback); - } - - mTabLayout = (TabLayout) view.findViewById(R.id.tabs); - new TabLayoutMediator( - mTabLayout, mViewPager, /* autoRefresh= */ true, /* smoothScroll= */ false, - (tab, position) -> tab.setText(mTabTitles[position])).attach(); - mTabLayout.getTabAt(mSavedTabPosition).select(); - } - - @Override - public void onDetached() { - super.onDetached(); - if (mViewPager != null && mOnPageChangeCallback != null) { - mViewPager.unregisterOnPageChangeCallback(mOnPageChangeCallback); - } - } - - @Override - protected Parcelable onSaveInstanceState() { - Log.d(TAG, "onSaveInstanceState() tabPosition=" + mTabLayout.getSelectedTabPosition()); - return new SavedState(super.onSaveInstanceState(), mTabLayout.getSelectedTabPosition()); - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - if (state == null || !state.getClass().equals(SavedState.class)) { - super.onRestoreInstanceState(state); - return; - } - SavedState savedState = (SavedState) state; - super.onRestoreInstanceState(savedState.getSuperState()); - mSavedTabPosition = savedState.getTabPosition(); - Log.d(TAG, "onRestoreInstanceState() tabPosition=" + savedState.getTabPosition()); - } - - @VisibleForTesting - static class SavedState extends BaseSavedState { - private int mTabPosition; - - SavedState(Parcelable superState, int tabPosition) { - super(superState); - mTabPosition = tabPosition; - } - - int getTabPosition() { - return mTabPosition; - } - } - - private static class FragmentAdapter extends FragmentStateAdapter { - private final int mItemCount; - private final Fragment[] mItemFragments; - - FragmentAdapter(@NonNull Fragment rootFragment, int itemCount) { - super(rootFragment); - mItemCount = itemCount; - mItemFragments = new Fragment[mItemCount]; - for (int i = 0; i < mItemCount; i++) { - // Empty tab pages. - mItemFragments[i] = new Fragment(); - } - } - - @NonNull - @Override - public Fragment createFragment(int position) { - return mItemFragments[position]; - } - - @Override - public int getItemCount() { - return mItemCount; - } - } -} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TabPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreferenceTest.java similarity index 56% rename from tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TabPreferenceTest.java rename to tests/robotests/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreferenceTest.java index c106b48d457..4c2192c4c21 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TabPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreferenceTest.java @@ -22,14 +22,12 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import android.content.Context; +import android.widget.Spinner; -import androidx.fragment.app.Fragment; import androidx.preference.Preference; import com.android.settings.R; -import com.google.android.material.tabs.TabLayout; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,50 +37,47 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) -public final class TabPreferenceTest { +public final class SpinnerPreferenceTest { private Context mContext; - private TabPreference mTabPreference; + private SpinnerPreference mSpinnerPreference; @Mock - private Fragment mMockFragment; - @Mock - private TabLayout mMockTabLayout; - - private final String[] mTabTitles = new String[]{"tab1", "tab2"}; + private Spinner mMockSpinner; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - mTabPreference = new TabPreference(mContext, /*attrs=*/ null); + mSpinnerPreference = new SpinnerPreference(mContext, /*attrs=*/ null); } @Test public void constructor_returnExpectedResult() { - assertThat(mTabPreference.getLayoutResource()).isEqualTo(R.layout.preference_tab); + assertThat(mSpinnerPreference.getLayoutResource()).isEqualTo(R.layout.preference_spinner); } @Test - public void initializeTabs_returnExpectedResult() { - mTabPreference.initializeTabs(mMockFragment, mTabTitles); - assertThat(mTabPreference.mTabTitles).isEqualTo(mTabTitles); + 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(mMockTabLayout).getSelectedTabPosition(); - mTabPreference.mTabLayout = mMockTabLayout; - TabPreference.SavedState savedState = - (TabPreference.SavedState) mTabPreference.onSaveInstanceState(); - assertThat(savedState.getTabPosition()).isEqualTo(1); + 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() { - TabPreference.SavedState savedState = - new TabPreference.SavedState(Preference.BaseSavedState.EMPTY_STATE, 2); - mTabPreference.onRestoreInstanceState(savedState); - assertThat(mTabPreference.mSavedTabPosition).isEqualTo(2); + SpinnerPreference.SavedState savedState = + new SpinnerPreference.SavedState(Preference.BaseSavedState.EMPTY_STATE, 2); + mSpinnerPreference.onRestoreInstanceState(savedState); + assertThat(mSpinnerPreference.mSavedSpinnerPosition).isEqualTo(2); } }