Loading res/layout/preference_tab.xml→res/layout/preference_spinner.xml +7 −20 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2022 The Android Open Source Project ~ 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. Loading @@ -15,23 +14,11 @@ ~ limitations under the License. --> <LinearLayout <Spinner xmlns:android="http://schemas.android.com/apk/res/android" android:theme="@style/Theme.TabTheme" android:id="@+id/tab_container" android:clipToPadding="true" android:clipChildren="true" android:layout_width="match_parent" android:id="@+id/spinner" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <com.google.android.material.tabs.TabLayout android:id="@+id/tabs" style="@style/SettingsLibTabsStyle" /> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> android:layout_marginStart="24dp" android:layout_marginTop="8dp" android:theme="@style/Widget.PopupWindow.Settings" /> res/values/strings.xml +6 −6 Original line number Diff line number Diff line Loading @@ -5175,13 +5175,13 @@ <!-- [CHAR_LIMIT=NONE] Accessibility content description for hourly battery chart view. --> <string name="hourly_battery_usage_chart">Hourly battery usage chart</string> <!-- [CHAR_LIMIT=NONE] Battery usage breakdown title since last full charge --> <string name="battery_usage_breakdown_title_since_last_full_charge">Usage proportional breakdown since last full charge</string> <string name="battery_usage_breakdown_title_since_last_full_charge">Battery usage since last full charge</string> <!-- [CHAR_LIMIT=NONE] Battery usage breakdown title for a selected slot --> <string name="battery_usage_breakdown_title_for_slot">Usage proportional breakdown for <xliff:g id="slot">%s</xliff:g></string> <!-- [CHAR_LIMIT=NONE] The tab title in the battery usage breakdown. --> <string name="battery_usage_app_tab">App</string> <!-- [CHAR_LIMIT=NONE] The tab title in the battery usage breakdown. --> <string name="battery_usage_system_tab">System</string> <string name="battery_usage_breakdown_title_for_slot">Battery usage for <xliff:g id="slot">%s</xliff:g></string> <!-- [CHAR_LIMIT=NONE] The spinner item text in the battery usage breakdown. --> <string name="battery_usage_spinner_breakdown_by_apps">Breakdown by apps</string> <!-- [CHAR_LIMIT=NONE] The spinner item text in the battery usage breakdown. --> <string name="battery_usage_spinner_breakdown_by_system">Breakdown by system</string> <!-- Process Stats strings --> <skip /> Loading res/xml/power_usage_advanced.xml +2 −2 Original line number Diff line number Diff line Loading @@ -32,8 +32,8 @@ "com.android.settings.fuelgauge.batteryusage.BatteryUsageBreakdownController" settings:isPreferenceVisible="false"> <com.android.settings.fuelgauge.batteryusage.TabPreference android:key="battery_usage_tab" <com.android.settings.fuelgauge.batteryusage.SpinnerPreference android:key="battery_usage_spinner" settings:isPreferenceVisible="false" /> <PreferenceCategory Loading src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java +31 −23 Original line number Diff line number Diff line Loading @@ -24,12 +24,13 @@ import android.os.Looper; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; import android.view.View; import android.widget.AdapterView; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; import androidx.viewpager2.widget.ViewPager2; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; Loading @@ -55,7 +56,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController 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"; private static final String TAB_PREFERENCE_KEY = "battery_usage_tab"; private static final String SPINNER_PREFERENCE_KEY = "battery_usage_spinner"; private static final String APP_LIST_PREFERENCE_KEY = "app_list"; private static final String PACKAGE_NAME_NONE = "none"; private static final int ENABLED_ICON_ALPHA = 255; Loading @@ -69,7 +70,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController @VisibleForTesting final Map<String, Preference> mPreferenceCache = new HashMap<>(); private int mTabPosition; private int mSpinnerPosition; private String mSlotTimestamp; @VisibleForTesting Loading @@ -77,7 +78,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController @VisibleForTesting PreferenceCategory mRootPreference; @VisibleForTesting TabPreference mTabPreference; SpinnerPreference mSpinnerPreference; @VisibleForTesting PreferenceGroup mAppListPreferenceGroup; @VisibleForTesting Loading Loading @@ -145,25 +146,32 @@ 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() { 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 onPageSelected(int position) { super.onPageSelected(position); mTabPosition = position; 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) { } }); } Loading @@ -182,7 +190,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController mSlotTimestamp = slotTimestamp; showCategoryTitle(slotTimestamp); showTabAndAppList(); showSpinnerAndAppList(); showFooterPreference(isAllUsageDataEmpty); } Loading @@ -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(); Loading @@ -222,7 +230,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController return; } final long start = System.currentTimeMillis(); final List<BatteryDiffEntry> entries = mTabPosition == 0 final List<BatteryDiffEntry> entries = mSpinnerPosition == 0 ? mBatteryDiffData.getAppDiffEntryList() : mBatteryDiffData.getSystemDiffEntryList(); int prefIndex = mAppListPreferenceGroup.getPreferenceCount(); Loading src/com/android/settings/fuelgauge/batteryusage/TabPreference.java→src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java +121 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * 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. Loading @@ -20,82 +20,54 @@ 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.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.android.settingslib.widget.SettingsSpinnerAdapter; import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayoutMediator; /** A preference which contains a spinner. */ public class SpinnerPreference extends Preference { private static final String TAG = "SpinnerPreference"; /** 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; private AdapterView.OnItemSelectedListener mOnItemSelectedListener; @VisibleForTesting String[] mTabTitles; Spinner mSpinner; @VisibleForTesting int mSavedTabPosition; String[] mItems; @VisibleForTesting TabLayout mTabLayout; int mSavedSpinnerPosition; public TabPreference(Context context, AttributeSet attrs) { public SpinnerPreference(Context context, AttributeSet attrs) { super(context, attrs); setLayoutResource(R.layout.preference_tab); } void initializeTabs(Fragment rootFragment, String[] tabTitles) { mRootFragment = rootFragment; mTabTitles = tabTitles; setLayoutResource(R.layout.preference_spinner); } void setOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback) { mOnPageChangeCallback = callback; void initializeSpinner( String[] items, AdapterView.OnItemSelectedListener onItemSelectedListener) { mItems = items; mOnItemSelectedListener = onItemSelectedListener; } @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); 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() tabPosition=" + mTabLayout.getSelectedTabPosition()); return new SavedState(super.onSaveInstanceState(), mTabLayout.getSelectedTabPosition()); Log.d(TAG, "onSaveInstanceState() spinnerPosition=" + mSpinner.getSelectedItemPosition()); return new SavedState(super.onSaveInstanceState(), mSpinner.getSelectedItemPosition()); } @Override Loading @@ -106,47 +78,44 @@ public class TabPreference extends Preference { } SavedState savedState = (SavedState) state; super.onRestoreInstanceState(savedState.getSuperState()); mSavedTabPosition = savedState.getTabPosition(); Log.d(TAG, "onRestoreInstanceState() tabPosition=" + savedState.getTabPosition()); 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 mTabPosition; private int mSpinnerPosition; SavedState(Parcelable superState, int tabPosition) { SavedState(Parcelable superState, int spinnerPosition) { super(superState); mTabPosition = tabPosition; mSpinnerPosition = spinnerPosition; } int getTabPosition() { return mTabPosition; int getSpinnerPosition() { return mSpinnerPosition; } } private static class FragmentAdapter extends FragmentStateAdapter { private final int mItemCount; private final Fragment[] mItemFragments; private static class SpinnerAdapter extends SettingsSpinnerAdapter<CharSequence> { private final String[] mItems; 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(); } SpinnerAdapter(Context context, String[] items) { super(context); mItems = items; } @NonNull @Override public Fragment createFragment(int position) { return mItemFragments[position]; public int getCount() { return mItems.length; } @Override public int getItemCount() { return mItemCount; public CharSequence getItem(int position) { return mItems[position]; } } } Loading
res/layout/preference_tab.xml→res/layout/preference_spinner.xml +7 −20 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2022 The Android Open Source Project ~ 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. Loading @@ -15,23 +14,11 @@ ~ limitations under the License. --> <LinearLayout <Spinner xmlns:android="http://schemas.android.com/apk/res/android" android:theme="@style/Theme.TabTheme" android:id="@+id/tab_container" android:clipToPadding="true" android:clipChildren="true" android:layout_width="match_parent" android:id="@+id/spinner" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <com.google.android.material.tabs.TabLayout android:id="@+id/tabs" style="@style/SettingsLibTabsStyle" /> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> android:layout_marginStart="24dp" android:layout_marginTop="8dp" android:theme="@style/Widget.PopupWindow.Settings" />
res/values/strings.xml +6 −6 Original line number Diff line number Diff line Loading @@ -5175,13 +5175,13 @@ <!-- [CHAR_LIMIT=NONE] Accessibility content description for hourly battery chart view. --> <string name="hourly_battery_usage_chart">Hourly battery usage chart</string> <!-- [CHAR_LIMIT=NONE] Battery usage breakdown title since last full charge --> <string name="battery_usage_breakdown_title_since_last_full_charge">Usage proportional breakdown since last full charge</string> <string name="battery_usage_breakdown_title_since_last_full_charge">Battery usage since last full charge</string> <!-- [CHAR_LIMIT=NONE] Battery usage breakdown title for a selected slot --> <string name="battery_usage_breakdown_title_for_slot">Usage proportional breakdown for <xliff:g id="slot">%s</xliff:g></string> <!-- [CHAR_LIMIT=NONE] The tab title in the battery usage breakdown. --> <string name="battery_usage_app_tab">App</string> <!-- [CHAR_LIMIT=NONE] The tab title in the battery usage breakdown. --> <string name="battery_usage_system_tab">System</string> <string name="battery_usage_breakdown_title_for_slot">Battery usage for <xliff:g id="slot">%s</xliff:g></string> <!-- [CHAR_LIMIT=NONE] The spinner item text in the battery usage breakdown. --> <string name="battery_usage_spinner_breakdown_by_apps">Breakdown by apps</string> <!-- [CHAR_LIMIT=NONE] The spinner item text in the battery usage breakdown. --> <string name="battery_usage_spinner_breakdown_by_system">Breakdown by system</string> <!-- Process Stats strings --> <skip /> Loading
res/xml/power_usage_advanced.xml +2 −2 Original line number Diff line number Diff line Loading @@ -32,8 +32,8 @@ "com.android.settings.fuelgauge.batteryusage.BatteryUsageBreakdownController" settings:isPreferenceVisible="false"> <com.android.settings.fuelgauge.batteryusage.TabPreference android:key="battery_usage_tab" <com.android.settings.fuelgauge.batteryusage.SpinnerPreference android:key="battery_usage_spinner" settings:isPreferenceVisible="false" /> <PreferenceCategory Loading
src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java +31 −23 Original line number Diff line number Diff line Loading @@ -24,12 +24,13 @@ import android.os.Looper; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; import android.view.View; import android.widget.AdapterView; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; import androidx.viewpager2.widget.ViewPager2; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; Loading @@ -55,7 +56,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController 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"; private static final String TAB_PREFERENCE_KEY = "battery_usage_tab"; private static final String SPINNER_PREFERENCE_KEY = "battery_usage_spinner"; private static final String APP_LIST_PREFERENCE_KEY = "app_list"; private static final String PACKAGE_NAME_NONE = "none"; private static final int ENABLED_ICON_ALPHA = 255; Loading @@ -69,7 +70,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController @VisibleForTesting final Map<String, Preference> mPreferenceCache = new HashMap<>(); private int mTabPosition; private int mSpinnerPosition; private String mSlotTimestamp; @VisibleForTesting Loading @@ -77,7 +78,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController @VisibleForTesting PreferenceCategory mRootPreference; @VisibleForTesting TabPreference mTabPreference; SpinnerPreference mSpinnerPreference; @VisibleForTesting PreferenceGroup mAppListPreferenceGroup; @VisibleForTesting Loading Loading @@ -145,25 +146,32 @@ 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() { 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 onPageSelected(int position) { super.onPageSelected(position); mTabPosition = position; 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) { } }); } Loading @@ -182,7 +190,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController mSlotTimestamp = slotTimestamp; showCategoryTitle(slotTimestamp); showTabAndAppList(); showSpinnerAndAppList(); showFooterPreference(isAllUsageDataEmpty); } Loading @@ -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(); Loading @@ -222,7 +230,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController return; } final long start = System.currentTimeMillis(); final List<BatteryDiffEntry> entries = mTabPosition == 0 final List<BatteryDiffEntry> entries = mSpinnerPosition == 0 ? mBatteryDiffData.getAppDiffEntryList() : mBatteryDiffData.getSystemDiffEntryList(); int prefIndex = mAppListPreferenceGroup.getPreferenceCount(); Loading
src/com/android/settings/fuelgauge/batteryusage/TabPreference.java→src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java +121 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * 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. Loading @@ -20,82 +20,54 @@ 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.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.android.settingslib.widget.SettingsSpinnerAdapter; import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayoutMediator; /** A preference which contains a spinner. */ public class SpinnerPreference extends Preference { private static final String TAG = "SpinnerPreference"; /** 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; private AdapterView.OnItemSelectedListener mOnItemSelectedListener; @VisibleForTesting String[] mTabTitles; Spinner mSpinner; @VisibleForTesting int mSavedTabPosition; String[] mItems; @VisibleForTesting TabLayout mTabLayout; int mSavedSpinnerPosition; public TabPreference(Context context, AttributeSet attrs) { public SpinnerPreference(Context context, AttributeSet attrs) { super(context, attrs); setLayoutResource(R.layout.preference_tab); } void initializeTabs(Fragment rootFragment, String[] tabTitles) { mRootFragment = rootFragment; mTabTitles = tabTitles; setLayoutResource(R.layout.preference_spinner); } void setOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback) { mOnPageChangeCallback = callback; void initializeSpinner( String[] items, AdapterView.OnItemSelectedListener onItemSelectedListener) { mItems = items; mOnItemSelectedListener = onItemSelectedListener; } @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); 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() tabPosition=" + mTabLayout.getSelectedTabPosition()); return new SavedState(super.onSaveInstanceState(), mTabLayout.getSelectedTabPosition()); Log.d(TAG, "onSaveInstanceState() spinnerPosition=" + mSpinner.getSelectedItemPosition()); return new SavedState(super.onSaveInstanceState(), mSpinner.getSelectedItemPosition()); } @Override Loading @@ -106,47 +78,44 @@ public class TabPreference extends Preference { } SavedState savedState = (SavedState) state; super.onRestoreInstanceState(savedState.getSuperState()); mSavedTabPosition = savedState.getTabPosition(); Log.d(TAG, "onRestoreInstanceState() tabPosition=" + savedState.getTabPosition()); 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 mTabPosition; private int mSpinnerPosition; SavedState(Parcelable superState, int tabPosition) { SavedState(Parcelable superState, int spinnerPosition) { super(superState); mTabPosition = tabPosition; mSpinnerPosition = spinnerPosition; } int getTabPosition() { return mTabPosition; int getSpinnerPosition() { return mSpinnerPosition; } } private static class FragmentAdapter extends FragmentStateAdapter { private final int mItemCount; private final Fragment[] mItemFragments; private static class SpinnerAdapter extends SettingsSpinnerAdapter<CharSequence> { private final String[] mItems; 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(); } SpinnerAdapter(Context context, String[] items) { super(context); mItems = items; } @NonNull @Override public Fragment createFragment(int position) { return mItemFragments[position]; public int getCount() { return mItems.length; } @Override public int getItemCount() { return mItemCount; public CharSequence getItem(int position) { return mItems[position]; } } }