PreferenceGroup.java revision c4276fe96c5c73539a249bcd8c39ce8fb22859b5
16904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler/*
26904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * Copyright (C) 2015 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
146904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * limitations under the License
156904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler */
166904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
176904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerpackage android.support.v7.preference;
186904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
196904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.content.Context;
206904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.content.res.TypedArray;
216904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.os.Bundle;
22c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantlerimport android.os.Handler;
2384765eaea7da18d0576db557959129e9d0db8e8cTony Mantlerimport android.support.v4.content.res.TypedArrayUtils;
24c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantlerimport android.support.v4.util.SimpleArrayMap;
256904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.text.TextUtils;
266904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport android.util.AttributeSet;
276904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
286904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport java.util.ArrayList;
296904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport java.util.Collections;
306904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerimport java.util.List;
316904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
326904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler/**
336904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * A container for multiple
346904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * {@link Preference} objects. It is a base class for  Preference objects that are
356904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * parents, such as {@link PreferenceCategory} and {@link PreferenceScreen}.
366904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler *
376904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * <div class="special reference">
386904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * <h3>Developer Guides</h3>
396904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * <p>For information about building a settings UI with Preferences,
406904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
416904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * guide.</p>
426904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * </div>
436904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler *
446904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler * @attr ref android.R.styleable#PreferenceGroup_orderingFromXml
456904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler */
466904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantlerpublic abstract class PreferenceGroup extends Preference {
476904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
486904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * The container for child {@link Preference}s. This is sorted based on the
496904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * ordering, please use {@link #addPreference(Preference)} instead of adding
506904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * to this directly.
516904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
526904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    private List<Preference> mPreferenceList;
536904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
546904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    private boolean mOrderingAsAdded = true;
556904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
566904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    private int mCurrentPreferenceOrder = 0;
576904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
58e61b4475e1837034d8926593aff9d35f8dfaebe2Tony Mantler    private boolean mAttachedToHierarchy = false;
596904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
60c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler    private final SimpleArrayMap<String, Long> mIdRecycleCache = new SimpleArrayMap<>();
61c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler    private final Handler mHandler = new Handler();
62c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler    private final Runnable mClearRecycleCacheRunnable = new Runnable() {
63c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        @Override
64c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        public void run() {
65c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler            synchronized (this) {
66c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                mIdRecycleCache.clear();
67c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler            }
68c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        }
69c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler    };
70c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler
716904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public PreferenceGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
726904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        super(context, attrs, defStyleAttr, defStyleRes);
736904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
746904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        mPreferenceList = new ArrayList<>();
756904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
766904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        final TypedArray a = context.obtainStyledAttributes(
776904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                attrs, R.styleable.PreferenceGroup, defStyleAttr, defStyleRes);
7884765eaea7da18d0576db557959129e9d0db8e8cTony Mantler
7984765eaea7da18d0576db557959129e9d0db8e8cTony Mantler        mOrderingAsAdded =
8084765eaea7da18d0576db557959129e9d0db8e8cTony Mantler                TypedArrayUtils.getBoolean(a, R.styleable.PreferenceGroup_orderingFromXml,
8184765eaea7da18d0576db557959129e9d0db8e8cTony Mantler                        R.styleable.PreferenceGroup_orderingFromXml, true);
8284765eaea7da18d0576db557959129e9d0db8e8cTony Mantler
836904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        a.recycle();
846904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
856904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
866904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public PreferenceGroup(Context context, AttributeSet attrs, int defStyleAttr) {
876904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        this(context, attrs, defStyleAttr, 0);
886904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
896904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
906904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public PreferenceGroup(Context context, AttributeSet attrs) {
916904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        this(context, attrs, 0);
926904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
936904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
946904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
956904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Whether to order the {@link Preference} children of this group as they
966904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * are added. If this is false, the ordering will follow each Preference
976904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * order and default to alphabetic for those without an order.
986904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * <p>
996904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * If this is called after preferences are added, they will not be
1006904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * re-ordered in the order they were added, hence call this method early on.
1016904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     *
1026904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @param orderingAsAdded Whether to order according to the order added.
1036904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @see Preference#setOrder(int)
1046904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
1056904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public void setOrderingAsAdded(boolean orderingAsAdded) {
1066904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        mOrderingAsAdded = orderingAsAdded;
1076904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
1086904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1096904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
1106904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Whether this group is ordering preferences in the order they are added.
1116904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     *
1126904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @return Whether this group orders based on the order the children are added.
1136904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @see #setOrderingAsAdded(boolean)
1146904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
1156904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public boolean isOrderingAsAdded() {
1166904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        return mOrderingAsAdded;
1176904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
1186904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1196904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
1206904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Called by the inflater to add an item to this group.
1216904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
1226904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public void addItemFromInflater(Preference preference) {
1236904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        addPreference(preference);
1246904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
1256904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1266904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
1276904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Returns the number of children {@link Preference}s.
1286904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @return The number of preference children in this group.
1296904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
1306904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public int getPreferenceCount() {
1316904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        return mPreferenceList.size();
1326904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
1336904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1346904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
1356904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Returns the {@link Preference} at a particular index.
1366904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     *
1376904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @param index The index of the {@link Preference} to retrieve.
1386904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @return The {@link Preference}.
1396904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
1406904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public Preference getPreference(int index) {
1416904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        return mPreferenceList.get(index);
1426904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
1436904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1446904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
1456904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Adds a {@link Preference} at the correct position based on the
1466904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * preference's order.
1476904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     *
1486904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @param preference The preference to add.
1496904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @return Whether the preference is now in this group.
1506904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
1516904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public boolean addPreference(Preference preference) {
1526904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        if (mPreferenceList.contains(preference)) {
1536904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            // Exists
1546904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            return true;
1556904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
1566904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1576904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        if (preference.getOrder() == DEFAULT_ORDER) {
1586904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            if (mOrderingAsAdded) {
1596904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                preference.setOrder(mCurrentPreferenceOrder++);
1606904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            }
1616904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1626904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            if (preference instanceof PreferenceGroup) {
1636904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                // TODO: fix (method is called tail recursively when inflating,
1646904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                // so we won't end up properly passing this flag down to children
1656904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                ((PreferenceGroup)preference).setOrderingAsAdded(mOrderingAsAdded);
1666904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            }
1676904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
1686904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1696904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        int insertionIndex = Collections.binarySearch(mPreferenceList, preference);
1706904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        if (insertionIndex < 0) {
1716904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            insertionIndex = insertionIndex * -1 - 1;
1726904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
1736904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1746904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        if (!onPrepareAddPreference(preference)) {
1756904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            return false;
1766904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
1776904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1786904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        synchronized(this) {
1796904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            mPreferenceList.add(insertionIndex, preference);
1806904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
1816904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
182c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        final PreferenceManager preferenceManager = getPreferenceManager();
183c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        final String key = preference.getKey();
184c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        final long id;
185c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        if (key != null && mIdRecycleCache.containsKey(key)) {
186c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler            id = mIdRecycleCache.get(key);
187c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler            mIdRecycleCache.remove(key);
188c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        } else {
189c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler            id = preferenceManager.getNextId();
190c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        }
191c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler        preference.onAttachedToHierarchy(preferenceManager, id);
1926904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
193e61b4475e1837034d8926593aff9d35f8dfaebe2Tony Mantler        if (mAttachedToHierarchy) {
1946904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            preference.onAttached();
1956904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
1966904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1976904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        notifyHierarchyChanged();
1986904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
1996904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        return true;
2006904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
2016904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
2026904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
2036904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Removes a {@link Preference} from this group.
2046904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     *
2056904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @param preference The preference to remove.
2066904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @return Whether the preference was found and removed.
2076904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
2086904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public boolean removePreference(Preference preference) {
2096904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        final boolean returnValue = removePreferenceInt(preference);
2106904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        notifyHierarchyChanged();
2116904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        return returnValue;
2126904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
2136904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
2146904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    private boolean removePreferenceInt(Preference preference) {
2156904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        synchronized(this) {
2166904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            preference.onPrepareForRemoval();
2178f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk            boolean success = mPreferenceList.remove(preference);
218c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler            if (success) {
219c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // If this preference, or another preference with the same key, gets re-added
220c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // immediately, we want it to have the same id so that it can be correctly tracked
221c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // in the adapter by RecyclerView, to make it appear as if it has only been
222c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // seamlessly updated. If the preference is not re-added by the time the handler
223c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // runs, we take that as a signal that the preference will not be re-added soon
224c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // in which case it does not need to retain the same id.
225c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler
226c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // If two (or more) preferences have the same (or null) key and both are removed
227c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // and then re-added, only one id will be recycled and the second (and later)
228c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // preferences will receive a newly generated id. This use pattern of the preference
229c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                // API is strongly discouraged.
230c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                final String key = preference.getKey();
231c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                if (key != null) {
232c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                    mIdRecycleCache.put(key, preference.getId());
233c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                    mHandler.removeCallbacks(mClearRecycleCacheRunnable);
234c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                    mHandler.post(mClearRecycleCacheRunnable);
235c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                }
236c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                if (mAttachedToHierarchy) {
237c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                    preference.onDetached();
238c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler                }
2398f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk            }
240c4276fe96c5c73539a249bcd8c39ce8fb22859b5Tony Mantler
2418f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk            return success;
2426904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
2436904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
2446904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
2456904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
2466904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Removes all {@link Preference Preferences} from this group.
2476904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
2486904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public void removeAll() {
2496904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        synchronized(this) {
2506904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            List<Preference> preferenceList = mPreferenceList;
2516904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            for (int i = preferenceList.size() - 1; i >= 0; i--) {
2526904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                removePreferenceInt(preferenceList.get(0));
2536904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            }
2546904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
2556904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        notifyHierarchyChanged();
2566904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
2576904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
2586904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
2596904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Prepares a {@link Preference} to be added to the group.
2606904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     *
2616904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @param preference The preference to add.
2626904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @return Whether to allow adding the preference (true), or not (false).
2636904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
2646904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    protected boolean onPrepareAddPreference(Preference preference) {
2656904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        preference.onParentChanged(this, shouldDisableDependents());
2666904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        return true;
2676904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
2686904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
2696904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
2706904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Finds a {@link Preference} based on its key. If two {@link Preference}
2716904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * share the same key (not recommended), the first to appear will be
2726904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * returned (to retrieve the other preference with the same key, call this
2736904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * method on the first preference). If this preference has the key, it will
2746904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * not be returned.
2756904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * <p>
2766904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * This will recursively search for the preference into children that are
2776904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * also {@link PreferenceGroup PreferenceGroups}.
2786904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     *
2796904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @param key The key of the preference to retrieve.
2806904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @return The {@link Preference} with the key, or null.
2816904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
2826904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public Preference findPreference(CharSequence key) {
2836904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        if (TextUtils.equals(getKey(), key)) {
2846904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            return this;
2856904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
2866904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        final int preferenceCount = getPreferenceCount();
2876904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        for (int i = 0; i < preferenceCount; i++) {
2886904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            final Preference preference = getPreference(i);
2896904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            final String curKey = preference.getKey();
2906904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
2916904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            if (curKey != null && curKey.equals(key)) {
2926904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                return preference;
2936904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            }
2946904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
2956904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            if (preference instanceof PreferenceGroup) {
2966904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                final Preference returnedPreference = ((PreferenceGroup)preference)
2976904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                        .findPreference(key);
2986904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                if (returnedPreference != null) {
2996904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                    return returnedPreference;
3006904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler                }
3016904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            }
3026904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
3036904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3046904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        return null;
3056904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
3066904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3076904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    /**
3086904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * Whether this preference group should be shown on the same screen as its
3096904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * contained preferences.
3106904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     *
3116904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     * @return True if the contained preferences should be shown on the same
3126904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     *         screen as this preference.
3136904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler     */
3146904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    protected boolean isOnSameScreenAsChildren() {
3156904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        return true;
3166904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
3176904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3186904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    @Override
319e61b4475e1837034d8926593aff9d35f8dfaebe2Tony Mantler    public void onAttached() {
3206904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        super.onAttached();
3216904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3226904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        // Mark as attached so if a preference is later added to this group, we
3236904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        // can tell it we are already attached
324e61b4475e1837034d8926593aff9d35f8dfaebe2Tony Mantler        mAttachedToHierarchy = true;
3256904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3266904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        // Dispatch to all contained preferences
3276904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        final int preferenceCount = getPreferenceCount();
3286904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        for (int i = 0; i < preferenceCount; i++) {
3296904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            getPreference(i).onAttached();
3306904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
3316904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
3326904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3336904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    @Override
3348f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk    public void onDetached() {
3358f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk        super.onDetached();
3366904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3376904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        // We won't be attached to the activity anymore
338e61b4475e1837034d8926593aff9d35f8dfaebe2Tony Mantler        mAttachedToHierarchy = false;
3398f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk
3408f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk        // Dispatch to all contained preferences
3418f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk        final int preferenceCount = getPreferenceCount();
3428f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk        for (int i = 0; i < preferenceCount; i++) {
3438f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk            getPreference(i).onDetached();
3448f7f0d48fac8f83e90a04ba67f9a03f93c6ed262Jason Monk        }
3456904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
3466904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3476904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    @Override
3486904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    public void notifyDependencyChange(boolean disableDependents) {
3496904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        super.notifyDependencyChange(disableDependents);
3506904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3516904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        // Child preferences have an implicit dependency on their containing
3526904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        // group. Dispatch dependency change to all contained preferences.
3536904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        final int preferenceCount = getPreferenceCount();
3546904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        for (int i = 0; i < preferenceCount; i++) {
3556904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            getPreference(i).onParentChanged(this, disableDependents);
3566904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
3576904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
3586904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3596904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    void sortPreferences() {
3606904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        synchronized (this) {
3616904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            Collections.sort(mPreferenceList);
3626904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
3636904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
3646904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3656904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    @Override
3666904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    protected void dispatchSaveInstanceState(Bundle container) {
3676904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        super.dispatchSaveInstanceState(container);
3686904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3696904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        // Dispatch to all contained preferences
3706904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        final int preferenceCount = getPreferenceCount();
3716904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        for (int i = 0; i < preferenceCount; i++) {
3726904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            getPreference(i).dispatchSaveInstanceState(container);
3736904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
3746904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
3756904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3766904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    @Override
3776904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    protected void dispatchRestoreInstanceState(Bundle container) {
3786904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        super.dispatchRestoreInstanceState(container);
3796904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3806904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        // Dispatch to all contained preferences
3816904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        final int preferenceCount = getPreferenceCount();
3826904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        for (int i = 0; i < preferenceCount; i++) {
3836904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler            getPreference(i).dispatchRestoreInstanceState(container);
3846904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler        }
3856904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler    }
3866904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler
3876904f67c96a28a0e5966b4fb6d37a0ad5f136858Tony Mantler}
388