16904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler/* 2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project 36904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * 46904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * Licensed under the Apache License, Version 2.0 (the "License"); 56904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * you may not use this file except in compliance with the License. 66904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * You may obtain a copy of the License at 76904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * 86904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * http://www.apache.org/licenses/LICENSE-2.0 96904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * 106904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * Unless required by applicable law or agreed to in writing, software 116904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * distributed under the License is distributed on an "AS IS" BASIS, 126904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * See the License for the specific language governing permissions and 14ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * limitations under the License. 156904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler */ 166904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.preference; 186904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 208e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas 213fadd62b614e4a69aefe920aac640bdb629e502eJason Monkimport android.content.res.TypedArray; 223fadd62b614e4a69aefe920aac640bdb629e502eJason Monkimport android.graphics.drawable.Drawable; 236904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.os.Handler; 246904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.text.TextUtils; 256904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.view.LayoutInflater; 266904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.view.View; 276904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.view.ViewGroup; 286904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 29226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilichimport androidx.annotation.RestrictTo; 30226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilichimport androidx.annotation.VisibleForTesting; 31226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilichimport androidx.core.content.ContextCompat; 32226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilichimport androidx.core.view.ViewCompat; 33226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilichimport androidx.recyclerview.widget.DiffUtil; 34226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilichimport androidx.recyclerview.widget.RecyclerView; 35226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich 36ca95d1c53dd086c368cd21685179517d4dadabcdAurimas Liutikasimport java.util.ArrayList; 37ca95d1c53dd086c368cd21685179517d4dadabcdAurimas Liutikasimport java.util.List; 38ca95d1c53dd086c368cd21685179517d4dadabcdAurimas Liutikas 396904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler/** 406904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * An adapter that connects a RecyclerView to the {@link Preference} objects contained in the 416904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * associated {@link PreferenceGroup}. 426904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * 436904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * @hide 446904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler */ 458e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas@RestrictTo(LIBRARY_GROUP) 466904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerpublic class PreferenceGroupAdapter extends RecyclerView.Adapter<PreferenceViewHolder> 4766222008cbda61251014caf1442930a48561d25cTony Mantler implements Preference.OnPreferenceChangeInternalListener, 4866222008cbda61251014caf1442930a48561d25cTony Mantler PreferenceGroup.PreferencePositionCallback { 496904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 506904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler /** 516904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * The group that we are providing data from. 526904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler */ 536904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private PreferenceGroup mPreferenceGroup; 546904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 556904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler /** 566904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * Maps a position into this adapter -> {@link Preference}. These 576904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * {@link Preference}s don't have to be direct children of this 586904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * {@link PreferenceGroup}, they can be grand children or younger) 596904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler */ 606904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private List<Preference> mPreferenceList; 616904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 626904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler /** 636904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * Contains a sorted list of all preferences in this adapter regardless of visibility. This is 646904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * used to construct {@link #mPreferenceList} 656904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler */ 666904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private List<Preference> mPreferenceListInternal; 676904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 686904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler /** 696904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * List of unique Preference and its subclasses' names and layouts. 706904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler */ 716904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private List<PreferenceLayout> mPreferenceLayouts; 726904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 736904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 746904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private PreferenceLayout mTempPreferenceLayout = new PreferenceLayout(); 756904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 76c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling private Handler mHandler; 77c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling 78c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling private CollapsiblePreferenceGroupController mPreferenceGroupController; 796904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 806904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private Runnable mSyncRunnable = new Runnable() { 81dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 826904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public void run() { 836904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler syncMyPreferences(); 846904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 856904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler }; 866904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 876904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private static class PreferenceLayout { 88226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich private int mResId; 89226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich private int mWidgetResId; 90226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich private String mName; 916904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 92226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich PreferenceLayout() {} 9343bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler 94226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich PreferenceLayout(PreferenceLayout other) { 95226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich mResId = other.mResId; 96226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich mWidgetResId = other.mWidgetResId; 97226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich mName = other.mName; 9843bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler } 9943bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler 1006904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler @Override 1016904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public boolean equals(Object o) { 1026904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (!(o instanceof PreferenceLayout)) { 1036904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler return false; 1046904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 1056904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final PreferenceLayout other = (PreferenceLayout) o; 106226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich return mResId == other.mResId 107226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich && mWidgetResId == other.mWidgetResId 108226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich && TextUtils.equals(mName, other.mName); 1096904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 1106904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 1116904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler @Override 1126904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public int hashCode() { 1136904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler int result = 17; 114226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich result = 31 * result + mResId; 115226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich result = 31 * result + mWidgetResId; 116226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich result = 31 * result + mName.hashCode(); 1176904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler return result; 1186904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 1196904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 1206904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 1216904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public PreferenceGroupAdapter(PreferenceGroup preferenceGroup) { 122c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling this(preferenceGroup, new Handler()); 123c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling } 124c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling 125c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling private PreferenceGroupAdapter(PreferenceGroup preferenceGroup, Handler handler) { 1266904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mPreferenceGroup = preferenceGroup; 127c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling mHandler = handler; 128c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling mPreferenceGroupController = 129c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling new CollapsiblePreferenceGroupController(preferenceGroup, this); 1306904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler // If this group gets or loses any children, let us know 1316904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mPreferenceGroup.setOnPreferenceChangeInternalListener(this); 1326904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 1336904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mPreferenceList = new ArrayList<>(); 1346904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mPreferenceListInternal = new ArrayList<>(); 1356904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mPreferenceLayouts = new ArrayList<>(); 1366904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 13783deca7547a76f037c32fdc946173b4708b8d05bTony Mantler if (mPreferenceGroup instanceof PreferenceScreen) { 13883deca7547a76f037c32fdc946173b4708b8d05bTony Mantler setHasStableIds(((PreferenceScreen) mPreferenceGroup).shouldUseGeneratedIds()); 13983deca7547a76f037c32fdc946173b4708b8d05bTony Mantler } else { 14083deca7547a76f037c32fdc946173b4708b8d05bTony Mantler setHasStableIds(true); 14183deca7547a76f037c32fdc946173b4708b8d05bTony Mantler } 1426904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 1436904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler syncMyPreferences(); 1446904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 1456904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 146c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling @VisibleForTesting 147c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling static PreferenceGroupAdapter createInstanceWithCustomHandler(PreferenceGroup preferenceGroup, 148c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling Handler handler) { 149c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling return new PreferenceGroupAdapter(preferenceGroup, handler); 150c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling } 151c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling 1526904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private void syncMyPreferences() { 153121b3474bd6a697c9b3e3177ddef28c37ed77032Tony Mantler for (final Preference preference : mPreferenceListInternal) { 154121b3474bd6a697c9b3e3177ddef28c37ed77032Tony Mantler // Clear out the listeners in anticipation of some items being removed. This listener 155121b3474bd6a697c9b3e3177ddef28c37ed77032Tony Mantler // will be (re-)added to the remaining prefs when we flatten. 156121b3474bd6a697c9b3e3177ddef28c37ed77032Tony Mantler preference.setOnPreferenceChangeInternalListener(null); 157121b3474bd6a697c9b3e3177ddef28c37ed77032Tony Mantler } 1589c0823fe1738cae176c7b32e3364f0bec1dea13bTony Mantler final List<Preference> fullPreferenceList = new ArrayList<>(mPreferenceListInternal.size()); 1599c0823fe1738cae176c7b32e3364f0bec1dea13bTony Mantler flattenPreferenceGroup(fullPreferenceList, mPreferenceGroup); 1606904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 161c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling final List<Preference> visiblePreferenceList = 162226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich mPreferenceGroupController.createVisiblePreferencesList(mPreferenceGroup); 1636904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 16484352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler final List<Preference> oldVisibleList = mPreferenceList; 1659c0823fe1738cae176c7b32e3364f0bec1dea13bTony Mantler mPreferenceList = visiblePreferenceList; 1669c0823fe1738cae176c7b32e3364f0bec1dea13bTony Mantler mPreferenceListInternal = fullPreferenceList; 1676904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 16884352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler final PreferenceManager preferenceManager = mPreferenceGroup.getPreferenceManager(); 16984352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler if (preferenceManager != null 17084352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler && preferenceManager.getPreferenceComparisonCallback() != null) { 17184352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler final PreferenceManager.PreferenceComparisonCallback comparisonCallback = 17284352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler preferenceManager.getPreferenceComparisonCallback(); 17384352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler final DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() { 17484352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler @Override 17584352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler public int getOldListSize() { 17684352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler return oldVisibleList.size(); 17784352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler } 17884352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler 17984352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler @Override 18084352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler public int getNewListSize() { 18184352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler return visiblePreferenceList.size(); 18284352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler } 18384352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler 18484352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler @Override 18584352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { 18684352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler return comparisonCallback.arePreferenceItemsTheSame( 18784352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler oldVisibleList.get(oldItemPosition), 18884352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler visiblePreferenceList.get(newItemPosition)); 18984352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler } 19084352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler 19184352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler @Override 19284352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { 19384352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler return comparisonCallback.arePreferenceContentsTheSame( 19484352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler oldVisibleList.get(oldItemPosition), 19584352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler visiblePreferenceList.get(newItemPosition)); 19684352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler } 19784352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler }); 19884352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler 19984352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler result.dispatchUpdatesTo(this); 20084352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler } else { 20184352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler notifyDataSetChanged(); 20284352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler } 20384352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler 20484352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler for (final Preference preference : fullPreferenceList) { 20584352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler preference.clearWasDetached(); 20684352192fbccf572473bb953ba3e9ebede60fbcaTony Mantler } 2076904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2086904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2096904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private void flattenPreferenceGroup(List<Preference> preferences, PreferenceGroup group) { 2106904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler group.sortPreferences(); 2116904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2126904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final int groupSize = group.getPreferenceCount(); 2136904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler for (int i = 0; i < groupSize; i++) { 2146904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final Preference preference = group.getPreference(i); 2156904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2166904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler preferences.add(preference); 2176904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2186904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler addPreferenceClassName(preference); 2196904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2206904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (preference instanceof PreferenceGroup) { 2216904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final PreferenceGroup preferenceAsGroup = (PreferenceGroup) preference; 2226904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (preferenceAsGroup.isOnSameScreenAsChildren()) { 2236904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler flattenPreferenceGroup(preferences, preferenceAsGroup); 2246904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2256904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2266904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2276904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler preference.setOnPreferenceChangeInternalListener(this); 2286904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2296904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2306904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2316904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler /** 2326904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * Creates a string that includes the preference name, layout id and widget layout id. 2336904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * If a particular preference type uses 2 different resources, they will be treated as 2346904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * different view types. 2356904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler */ 2366904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private PreferenceLayout createPreferenceLayout(Preference preference, PreferenceLayout in) { 237226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich PreferenceLayout pl = in != null ? in : new PreferenceLayout(); 238226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich pl.mName = preference.getClass().getName(); 239226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich pl.mResId = preference.getLayoutResource(); 240226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich pl.mWidgetResId = preference.getWidgetLayoutResource(); 2416904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler return pl; 2426904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2436904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2446904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler private void addPreferenceClassName(Preference preference) { 2456904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final PreferenceLayout pl = createPreferenceLayout(preference, null); 2466904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (!mPreferenceLayouts.contains(pl)) { 2476904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mPreferenceLayouts.add(pl); 2486904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2496904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2506904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2516904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler @Override 2526904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public int getItemCount() { 2536904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler return mPreferenceList.size(); 2546904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2556904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2566904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public Preference getItem(int position) { 2576904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (position < 0 || position >= getItemCount()) return null; 2586904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler return mPreferenceList.get(position); 2596904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2606904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 261dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 2626904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public long getItemId(int position) { 26383deca7547a76f037c32fdc946173b4708b8d05bTony Mantler if (!hasStableIds()) { 26483deca7547a76f037c32fdc946173b4708b8d05bTony Mantler return RecyclerView.NO_ID; 26583deca7547a76f037c32fdc946173b4708b8d05bTony Mantler } 2666904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler return this.getItem(position).getId(); 2676904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2686904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 269dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 2706904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public void onPreferenceChange(Preference preference) { 2715c58355b66d26d4992d68ec2657d6d5ad9a53590Tony Mantler final int index = mPreferenceList.indexOf(preference); 2725c58355b66d26d4992d68ec2657d6d5ad9a53590Tony Mantler // If we don't find the preference, we don't need to notify anyone 2735c58355b66d26d4992d68ec2657d6d5ad9a53590Tony Mantler if (index != -1) { 2745c58355b66d26d4992d68ec2657d6d5ad9a53590Tony Mantler // Send the pref object as a placeholder to ensure the view holder is recycled in place 2755c58355b66d26d4992d68ec2657d6d5ad9a53590Tony Mantler notifyItemChanged(index, preference); 2765c58355b66d26d4992d68ec2657d6d5ad9a53590Tony Mantler } 2776904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2786904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 279dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 2806904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public void onPreferenceHierarchyChange(Preference preference) { 2816904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mHandler.removeCallbacks(mSyncRunnable); 2826904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mHandler.post(mSyncRunnable); 2836904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 2846904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2856904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler @Override 2866904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public void onPreferenceVisibilityChange(Preference preference) { 287121b3474bd6a697c9b3e3177ddef28c37ed77032Tony Mantler if (!mPreferenceListInternal.contains(preference)) { 288121b3474bd6a697c9b3e3177ddef28c37ed77032Tony Mantler return; 289121b3474bd6a697c9b3e3177ddef28c37ed77032Tony Mantler } 290c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling if (mPreferenceGroupController.onPreferenceVisibilityChange(preference)) { 291c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling return; 292c88dea08fa07d811eb7cfe77c7a523fd2b0ce339Doris Ling } 2936904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (preference.isVisible()) { 2946904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler // The preference has become visible, we need to add it in the correct location. 2956904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 2966904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler // Index (inferred) in mPreferenceList of the item preceding the newly visible pref 2976904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler int previousVisibleIndex = -1; 2986904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler for (final Preference pref : mPreferenceListInternal) { 2996904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (preference.equals(pref)) { 3006904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler break; 3016904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3026904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (pref.isVisible()) { 3036904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler previousVisibleIndex++; 3046904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3056904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3066904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler // Insert this preference into the active list just after the previous visible entry 3076904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mPreferenceList.add(previousVisibleIndex + 1, preference); 3086904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 3096904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler notifyItemInserted(previousVisibleIndex + 1); 3106904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } else { 311c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas // The preference has become invisible. Find it in the list and remove it. 3126904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 3136904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler int removalIndex; 3146904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final int listSize = mPreferenceList.size(); 3156904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler for (removalIndex = 0; removalIndex < listSize; removalIndex++) { 3166904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (preference.equals(mPreferenceList.get(removalIndex))) { 3176904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler break; 3186904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3196904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3206904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mPreferenceList.remove(removalIndex); 3216904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler notifyItemRemoved(removalIndex); 3226904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3236904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3246904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 3256904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler @Override 3266904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public int getItemViewType(int position) { 3276904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final Preference preference = this.getItem(position); 3286904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 3296904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout); 3306904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 33143bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler int viewType = mPreferenceLayouts.indexOf(mTempPreferenceLayout); 33243bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler if (viewType != -1) { 33343bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler return viewType; 33443bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler } else { 33543bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler viewType = mPreferenceLayouts.size(); 33643bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler mPreferenceLayouts.add(new PreferenceLayout(mTempPreferenceLayout)); 33743bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler return viewType; 33843bd2dbe877d980e72f7e575d4477e77fe2f6d92Tony Mantler } 3396904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3406904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 3416904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler @Override 3426904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public PreferenceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 3436904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final PreferenceLayout pl = mPreferenceLayouts.get(viewType); 3446904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 3453fadd62b614e4a69aefe920aac640bdb629e502eJason Monk TypedArray a 3463fadd62b614e4a69aefe920aac640bdb629e502eJason Monk = parent.getContext().obtainStyledAttributes(null, R.styleable.BackgroundStyle); 3473fadd62b614e4a69aefe920aac640bdb629e502eJason Monk Drawable background 3483fadd62b614e4a69aefe920aac640bdb629e502eJason Monk = a.getDrawable(R.styleable.BackgroundStyle_android_selectableItemBackground); 3493fadd62b614e4a69aefe920aac640bdb629e502eJason Monk if (background == null) { 350f82cdb0326f2cb78809fe0c536c5fbb527b7ae00Filip Pavlis background = ContextCompat.getDrawable(parent.getContext(), 351f82cdb0326f2cb78809fe0c536c5fbb527b7ae00Filip Pavlis android.R.drawable.list_selector_background); 3523fadd62b614e4a69aefe920aac640bdb629e502eJason Monk } 3533fadd62b614e4a69aefe920aac640bdb629e502eJason Monk a.recycle(); 3546904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 355226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich final View view = inflater.inflate(pl.mResId, parent, false); 35673886daee29a8a910a0f9208b7c5c885dda95eb1Jason Monk if (view.getBackground() == null) { 35747082c30c630c34829439a9eecd1cf7e8d255a86Aurimas Liutikas ViewCompat.setBackground(view, background); 35873886daee29a8a910a0f9208b7c5c885dda95eb1Jason Monk } 3596904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 360d1be3655c1de9af3174d285d42f9bd5b47ce9020Todd Volkert final ViewGroup widgetFrame = (ViewGroup) view.findViewById(android.R.id.widget_frame); 3616904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler if (widgetFrame != null) { 362226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich if (pl.mWidgetResId != 0) { 363226a42d7fbfb54e2173e6e04f997d32848c4da62Louis Pullen-Freilich inflater.inflate(pl.mWidgetResId, widgetFrame); 3646904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } else { 3656904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler widgetFrame.setVisibility(View.GONE); 3666904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3676904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3686904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 3696904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler return new PreferenceViewHolder(view); 3706904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 3716904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler 3726904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler @Override 3736904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler public void onBindViewHolder(PreferenceViewHolder holder, int position) { 3746904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler final Preference preference = getItem(position); 3756904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler preference.onBindViewHolder(holder); 3766904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler } 37766222008cbda61251014caf1442930a48561d25cTony Mantler 37866222008cbda61251014caf1442930a48561d25cTony Mantler @Override 37966222008cbda61251014caf1442930a48561d25cTony Mantler public int getPreferenceAdapterPosition(String key) { 38066222008cbda61251014caf1442930a48561d25cTony Mantler final int size = mPreferenceList.size(); 38166222008cbda61251014caf1442930a48561d25cTony Mantler for (int i = 0; i < size; i++) { 38266222008cbda61251014caf1442930a48561d25cTony Mantler final Preference candidate = mPreferenceList.get(i); 38366222008cbda61251014caf1442930a48561d25cTony Mantler if (TextUtils.equals(key, candidate.getKey())) { 38466222008cbda61251014caf1442930a48561d25cTony Mantler return i; 38566222008cbda61251014caf1442930a48561d25cTony Mantler } 38666222008cbda61251014caf1442930a48561d25cTony Mantler } 38766222008cbda61251014caf1442930a48561d25cTony Mantler return RecyclerView.NO_POSITION; 38866222008cbda61251014caf1442930a48561d25cTony Mantler } 38966222008cbda61251014caf1442930a48561d25cTony Mantler 39066222008cbda61251014caf1442930a48561d25cTony Mantler @Override 39166222008cbda61251014caf1442930a48561d25cTony Mantler public int getPreferenceAdapterPosition(Preference preference) { 39266222008cbda61251014caf1442930a48561d25cTony Mantler final int size = mPreferenceList.size(); 39366222008cbda61251014caf1442930a48561d25cTony Mantler for (int i = 0; i < size; i++) { 394c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas final Preference candidate = mPreferenceList.get(i); 395c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas if (candidate != null && candidate.equals(preference)) { 39666222008cbda61251014caf1442930a48561d25cTony Mantler return i; 39766222008cbda61251014caf1442930a48561d25cTony Mantler } 39866222008cbda61251014caf1442930a48561d25cTony Mantler } 39966222008cbda61251014caf1442930a48561d25cTony Mantler return RecyclerView.NO_POSITION; 40066222008cbda61251014caf1442930a48561d25cTony Mantler } 4016904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler} 402