Home | History | Annotate | Download | only in preference
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.preference;
     18 
     19 import android.content.Context;
     20 import android.content.res.TypedArray;
     21 import android.os.Bundle;
     22 import android.text.TextUtils;
     23 import android.util.AttributeSet;
     24 
     25 import java.util.ArrayList;
     26 import java.util.Collections;
     27 import java.util.List;
     28 
     29 /**
     30  * A container for multiple
     31  * {@link Preference} objects. It is a base class for  Preference objects that are
     32  * parents, such as {@link PreferenceCategory} and {@link PreferenceScreen}.
     33  *
     34  * <div class="special reference">
     35  * <h3>Developer Guides</h3>
     36  * <p>For information about building a settings UI with Preferences,
     37  * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
     38  * guide.</p>
     39  * </div>
     40  *
     41  * @attr ref android.R.styleable#PreferenceGroup_orderingFromXml
     42  *
     43  * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
     44  *      <a href="{@docRoot}reference/androidx/preference/package-summary.html">
     45  *      Preference Library</a> for consistent behavior across all devices. For more information on
     46  *      using the AndroidX Preference Library see
     47  *      <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>.
     48  */
     49 @Deprecated
     50 public abstract class PreferenceGroup extends Preference implements GenericInflater.Parent<Preference> {
     51     /**
     52      * The container for child {@link Preference}s. This is sorted based on the
     53      * ordering, please use {@link #addPreference(Preference)} instead of adding
     54      * to this directly.
     55      */
     56     private List<Preference> mPreferenceList;
     57 
     58     private boolean mOrderingAsAdded = true;
     59 
     60     private int mCurrentPreferenceOrder = 0;
     61 
     62     private boolean mAttachedToActivity = false;
     63 
     64     public PreferenceGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     65         super(context, attrs, defStyleAttr, defStyleRes);
     66 
     67         mPreferenceList = new ArrayList<Preference>();
     68 
     69         final TypedArray a = context.obtainStyledAttributes(
     70                 attrs, com.android.internal.R.styleable.PreferenceGroup, defStyleAttr, defStyleRes);
     71         mOrderingAsAdded = a.getBoolean(com.android.internal.R.styleable.PreferenceGroup_orderingFromXml,
     72                 mOrderingAsAdded);
     73         a.recycle();
     74     }
     75 
     76     public PreferenceGroup(Context context, AttributeSet attrs, int defStyleAttr) {
     77         this(context, attrs, defStyleAttr, 0);
     78     }
     79 
     80     public PreferenceGroup(Context context, AttributeSet attrs) {
     81         this(context, attrs, 0);
     82     }
     83 
     84     /**
     85      * Whether to order the {@link Preference} children of this group as they
     86      * are added. If this is false, the ordering will follow each Preference
     87      * order and default to alphabetic for those without an order.
     88      * <p>
     89      * If this is called after preferences are added, they will not be
     90      * re-ordered in the order they were added, hence call this method early on.
     91      *
     92      * @param orderingAsAdded Whether to order according to the order added.
     93      * @see Preference#setOrder(int)
     94      */
     95     public void setOrderingAsAdded(boolean orderingAsAdded) {
     96         mOrderingAsAdded = orderingAsAdded;
     97     }
     98 
     99     /**
    100      * Whether this group is ordering preferences in the order they are added.
    101      *
    102      * @return Whether this group orders based on the order the children are added.
    103      * @see #setOrderingAsAdded(boolean)
    104      */
    105     public boolean isOrderingAsAdded() {
    106         return mOrderingAsAdded;
    107     }
    108 
    109     /**
    110      * Called by the inflater to add an item to this group.
    111      */
    112     public void addItemFromInflater(Preference preference) {
    113         addPreference(preference);
    114     }
    115 
    116     /**
    117      * Returns the number of children {@link Preference}s.
    118      * @return The number of preference children in this group.
    119      */
    120     public int getPreferenceCount() {
    121         return mPreferenceList.size();
    122     }
    123 
    124     /**
    125      * Returns the {@link Preference} at a particular index.
    126      *
    127      * @param index The index of the {@link Preference} to retrieve.
    128      * @return The {@link Preference}.
    129      */
    130     public Preference getPreference(int index) {
    131         return mPreferenceList.get(index);
    132     }
    133 
    134     /**
    135      * Adds a {@link Preference} at the correct position based on the
    136      * preference's order.
    137      *
    138      * @param preference The preference to add.
    139      * @return Whether the preference is now in this group.
    140      */
    141     public boolean addPreference(Preference preference) {
    142         if (mPreferenceList.contains(preference)) {
    143             // Exists
    144             return true;
    145         }
    146 
    147         if (preference.getOrder() == Preference.DEFAULT_ORDER) {
    148             if (mOrderingAsAdded) {
    149                 preference.setOrder(mCurrentPreferenceOrder++);
    150             }
    151 
    152             if (preference instanceof PreferenceGroup) {
    153                 // TODO: fix (method is called tail recursively when inflating,
    154                 // so we won't end up properly passing this flag down to children
    155                 ((PreferenceGroup)preference).setOrderingAsAdded(mOrderingAsAdded);
    156             }
    157         }
    158 
    159         if (!onPrepareAddPreference(preference)) {
    160             return false;
    161         }
    162 
    163         synchronized(this) {
    164             int insertionIndex = Collections.binarySearch(mPreferenceList, preference);
    165             if (insertionIndex < 0) {
    166                 insertionIndex = insertionIndex * -1 - 1;
    167             }
    168             mPreferenceList.add(insertionIndex, preference);
    169         }
    170 
    171         preference.onAttachedToHierarchy(getPreferenceManager());
    172         preference.assignParent(this);
    173 
    174         if (mAttachedToActivity) {
    175             preference.onAttachedToActivity();
    176         }
    177 
    178         notifyHierarchyChanged();
    179 
    180         return true;
    181     }
    182 
    183     /**
    184      * Removes a {@link Preference} from this group.
    185      *
    186      * @param preference The preference to remove.
    187      * @return Whether the preference was found and removed.
    188      */
    189     public boolean removePreference(Preference preference) {
    190         final boolean returnValue = removePreferenceInt(preference);
    191         notifyHierarchyChanged();
    192         return returnValue;
    193     }
    194 
    195     private boolean removePreferenceInt(Preference preference) {
    196         synchronized(this) {
    197             preference.onPrepareForRemoval();
    198             if (preference.getParent() == this) {
    199                 preference.assignParent(null);
    200             }
    201             return mPreferenceList.remove(preference);
    202         }
    203     }
    204 
    205     /**
    206      * Removes all {@link Preference Preferences} from this group.
    207      */
    208     public void removeAll() {
    209         synchronized(this) {
    210             List<Preference> preferenceList = mPreferenceList;
    211             for (int i = preferenceList.size() - 1; i >= 0; i--) {
    212                 removePreferenceInt(preferenceList.get(0));
    213             }
    214         }
    215         notifyHierarchyChanged();
    216     }
    217 
    218     /**
    219      * Prepares a {@link Preference} to be added to the group.
    220      *
    221      * @param preference The preference to add.
    222      * @return Whether to allow adding the preference (true), or not (false).
    223      */
    224     protected boolean onPrepareAddPreference(Preference preference) {
    225         preference.onParentChanged(this, shouldDisableDependents());
    226         return true;
    227     }
    228 
    229     /**
    230      * Finds a {@link Preference} based on its key. If two {@link Preference}
    231      * share the same key (not recommended), the first to appear will be
    232      * returned (to retrieve the other preference with the same key, call this
    233      * method on the first preference). If this preference has the key, it will
    234      * not be returned.
    235      * <p>
    236      * This will recursively search for the preference into children that are
    237      * also {@link PreferenceGroup PreferenceGroups}.
    238      *
    239      * @param key The key of the preference to retrieve.
    240      * @return The {@link Preference} with the key, or null.
    241      */
    242     public Preference findPreference(CharSequence key) {
    243         if (TextUtils.equals(getKey(), key)) {
    244             return this;
    245         }
    246         final int preferenceCount = getPreferenceCount();
    247         for (int i = 0; i < preferenceCount; i++) {
    248             final Preference preference = getPreference(i);
    249             final String curKey = preference.getKey();
    250 
    251             if (curKey != null && curKey.equals(key)) {
    252                 return preference;
    253             }
    254 
    255             if (preference instanceof PreferenceGroup) {
    256                 final Preference returnedPreference = ((PreferenceGroup)preference)
    257                         .findPreference(key);
    258                 if (returnedPreference != null) {
    259                     return returnedPreference;
    260                 }
    261             }
    262         }
    263 
    264         return null;
    265     }
    266 
    267     /**
    268      * Whether this preference group should be shown on the same screen as its
    269      * contained preferences.
    270      *
    271      * @return True if the contained preferences should be shown on the same
    272      *         screen as this preference.
    273      */
    274     protected boolean isOnSameScreenAsChildren() {
    275         return true;
    276     }
    277 
    278     @Override
    279     protected void onAttachedToActivity() {
    280         super.onAttachedToActivity();
    281 
    282         // Mark as attached so if a preference is later added to this group, we
    283         // can tell it we are already attached
    284         mAttachedToActivity = true;
    285 
    286         // Dispatch to all contained preferences
    287         final int preferenceCount = getPreferenceCount();
    288         for (int i = 0; i < preferenceCount; i++) {
    289             getPreference(i).onAttachedToActivity();
    290         }
    291     }
    292 
    293     @Override
    294     protected void onPrepareForRemoval() {
    295         super.onPrepareForRemoval();
    296 
    297         // We won't be attached to the activity anymore
    298         mAttachedToActivity = false;
    299     }
    300 
    301     @Override
    302     public void notifyDependencyChange(boolean disableDependents) {
    303         super.notifyDependencyChange(disableDependents);
    304 
    305         // Child preferences have an implicit dependency on their containing
    306         // group. Dispatch dependency change to all contained preferences.
    307         final int preferenceCount = getPreferenceCount();
    308         for (int i = 0; i < preferenceCount; i++) {
    309             getPreference(i).onParentChanged(this, disableDependents);
    310         }
    311     }
    312 
    313     void sortPreferences() {
    314         synchronized (this) {
    315             Collections.sort(mPreferenceList);
    316         }
    317     }
    318 
    319     @Override
    320     protected void dispatchSaveInstanceState(Bundle container) {
    321         super.dispatchSaveInstanceState(container);
    322 
    323         // Dispatch to all contained preferences
    324         final int preferenceCount = getPreferenceCount();
    325         for (int i = 0; i < preferenceCount; i++) {
    326             getPreference(i).dispatchSaveInstanceState(container);
    327         }
    328     }
    329 
    330     @Override
    331     protected void dispatchRestoreInstanceState(Bundle container) {
    332         super.dispatchRestoreInstanceState(container);
    333 
    334         // Dispatch to all contained preferences
    335         final int preferenceCount = getPreferenceCount();
    336         for (int i = 0; i < preferenceCount; i++) {
    337             getPreference(i).dispatchRestoreInstanceState(container);
    338         }
    339     }
    340 
    341 }
    342