Home | History | Annotate | Download | only in accessibility
      1 /*
      2  * Copyright (C) 2013 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 com.android.settings.accessibility;
     18 
     19 import android.app.AlertDialog;
     20 import android.app.Dialog;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.res.TypedArray;
     24 import android.os.Parcel;
     25 import android.os.Parcelable;
     26 import android.util.AttributeSet;
     27 import android.view.LayoutInflater;
     28 import android.view.View;
     29 import android.view.ViewGroup;
     30 import android.widget.AbsListView;
     31 import android.widget.AdapterView;
     32 import android.widget.BaseAdapter;
     33 
     34 import com.android.settingslib.CustomDialogPreference;
     35 
     36 /**
     37  * Abstract dialog preference that displays a set of values and optional titles.
     38  */
     39 public abstract class ListDialogPreference extends CustomDialogPreference {
     40     private CharSequence[] mEntryTitles;
     41     private int[] mEntryValues;
     42 
     43     private OnValueChangedListener mOnValueChangedListener;
     44 
     45     /** The layout resource to use for grid items. */
     46     private int mListItemLayout;
     47 
     48     /** The current value of this preference. */
     49     private int mValue;
     50 
     51     /** The index within the value set of the current value. */
     52     private int mValueIndex;
     53 
     54     /** Whether the value had been set using {@link #setValue}. */
     55     private boolean mValueSet;
     56 
     57     public ListDialogPreference(Context context, AttributeSet attrs) {
     58         super(context, attrs);
     59     }
     60 
     61     /**
     62      * Sets a listened to invoke when the value of this preference changes.
     63      *
     64      * @param listener the listener to invoke
     65      */
     66     public void setOnValueChangedListener(OnValueChangedListener listener) {
     67         mOnValueChangedListener = listener;
     68     }
     69 
     70     /**
     71      * Sets the layout to use for grid items.
     72      *
     73      * @param layoutResId the layout to use for displaying grid items
     74      */
     75     public void setListItemLayoutResource(int layoutResId) {
     76         mListItemLayout = layoutResId;
     77     }
     78 
     79     /**
     80      * Sets the list of item values. Values must be distinct.
     81      *
     82      * @param values the list of item values
     83      */
     84     public void setValues(int[] values) {
     85         mEntryValues = values;
     86 
     87         if (mValueSet && mValueIndex == AbsListView.INVALID_POSITION) {
     88             mValueIndex = getIndexForValue(mValue);
     89         }
     90     }
     91 
     92     /**
     93      * Sets the list of item titles. May be null if no titles are specified, or
     94      * may be shorter than the list of values to leave some titles unspecified.
     95      *
     96      * @param titles the list of item titles
     97      */
     98     public void setTitles(CharSequence[] titles) {
     99         mEntryTitles = titles;
    100     }
    101 
    102     /**
    103      * Populates a list item view with data for the specified index.
    104      *
    105      * @param view the view to populate
    106      * @param index the index for which to populate the view
    107      * @see #setListItemLayoutResource(int)
    108      * @see #getValueAt(int)
    109      * @see #getTitleAt(int)
    110      */
    111     protected abstract void onBindListItem(View view, int index);
    112 
    113     /**
    114      * @return the title at the specified index, or null if none specified
    115      */
    116     protected CharSequence getTitleAt(int index) {
    117         if (mEntryTitles == null || mEntryTitles.length <= index) {
    118             return null;
    119         }
    120 
    121         return mEntryTitles[index];
    122     }
    123 
    124     /**
    125      * @return the value at the specified index
    126      */
    127     protected int getValueAt(int index) {
    128         return mEntryValues[index];
    129     }
    130 
    131     @Override
    132     public CharSequence getSummary() {
    133         if (mValueIndex >= 0) {
    134             return getTitleAt(mValueIndex);
    135         }
    136 
    137         return null;
    138     }
    139 
    140     @Override
    141     protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
    142             DialogInterface.OnClickListener listener) {
    143         super.onPrepareDialogBuilder(builder, listener);
    144 
    145         final Context context = getContext();
    146         final int dialogLayout = getDialogLayoutResource();
    147         final View picker = LayoutInflater.from(context).inflate(dialogLayout, null);
    148         final ListPreferenceAdapter adapter = new ListPreferenceAdapter();
    149         final AbsListView list = (AbsListView) picker.findViewById(android.R.id.list);
    150         list.setAdapter(adapter);
    151         list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    152             @Override
    153             public void onItemClick(AdapterView<?> adapter, View v, int position, long id) {
    154                 if (callChangeListener((int) id)) {
    155                     setValue((int) id);
    156                 }
    157 
    158                 final Dialog dialog = getDialog();
    159                 if (dialog != null) {
    160                     dialog.dismiss();
    161                 }
    162             }
    163         });
    164 
    165         // Set initial selection.
    166         final int selectedPosition = getIndexForValue(mValue);
    167         if (selectedPosition != AbsListView.INVALID_POSITION) {
    168             list.setSelection(selectedPosition);
    169         }
    170 
    171         builder.setView(picker);
    172         builder.setPositiveButton(null, null);
    173     }
    174 
    175     /**
    176      * @return the index of the specified value within the list of entry values,
    177      *         or {@link AbsListView#INVALID_POSITION} if not found
    178      */
    179     protected int getIndexForValue(int value) {
    180         final int[] values = mEntryValues;
    181         if (values != null) {
    182             final int count = values.length;
    183             for (int i = 0; i < count; i++) {
    184                 if (values[i] == value) {
    185                     return i;
    186                 }
    187             }
    188         }
    189 
    190         return AbsListView.INVALID_POSITION;
    191     }
    192 
    193     /**
    194      * Sets the current value. If the value exists within the set of entry
    195      * values, updates the selection index.
    196      *
    197      * @param value the value to set
    198      */
    199     public void setValue(int value) {
    200         final boolean changed = mValue != value;
    201         if (changed || !mValueSet) {
    202             mValue = value;
    203             mValueIndex = getIndexForValue(value);
    204             mValueSet = true;
    205             persistInt(value);
    206             if (changed) {
    207                 notifyDependencyChange(shouldDisableDependents());
    208                 notifyChanged();
    209             }
    210             if (mOnValueChangedListener != null) {
    211                 mOnValueChangedListener.onValueChanged(this, value);
    212             }
    213         }
    214     }
    215 
    216     /**
    217      * @return the current value
    218      */
    219     public int getValue() {
    220         return mValue;
    221     }
    222 
    223     @Override
    224     protected Object onGetDefaultValue(TypedArray a, int index) {
    225         return a.getInt(index, 0);
    226     }
    227 
    228     @Override
    229     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
    230         setValue(restoreValue ? getPersistedInt(mValue) : (Integer) defaultValue);
    231     }
    232 
    233     @Override
    234     protected Parcelable onSaveInstanceState() {
    235         final Parcelable superState = super.onSaveInstanceState();
    236         if (isPersistent()) {
    237             // No need to save instance state since it's persistent
    238             return superState;
    239         }
    240 
    241         final SavedState myState = new SavedState(superState);
    242         myState.value = getValue();
    243         return myState;
    244     }
    245 
    246     @Override
    247     protected void onRestoreInstanceState(Parcelable state) {
    248         if (state == null || !state.getClass().equals(SavedState.class)) {
    249             // Didn't save state for us in onSaveInstanceState
    250             super.onRestoreInstanceState(state);
    251             return;
    252         }
    253 
    254         SavedState myState = (SavedState) state;
    255         super.onRestoreInstanceState(myState.getSuperState());
    256         setValue(myState.value);
    257     }
    258 
    259     private class ListPreferenceAdapter extends BaseAdapter {
    260         private LayoutInflater mInflater;
    261 
    262         @Override
    263         public int getCount() {
    264             return mEntryValues.length;
    265         }
    266 
    267         @Override
    268         public Integer getItem(int position) {
    269             return mEntryValues[position];
    270         }
    271 
    272         @Override
    273         public long getItemId(int position) {
    274             return mEntryValues[position];
    275         }
    276 
    277         @Override
    278         public boolean hasStableIds() {
    279             return true;
    280         }
    281 
    282         @Override
    283         public View getView(int position, View convertView, ViewGroup parent) {
    284             if (convertView == null) {
    285                 if (mInflater == null) {
    286                     mInflater = LayoutInflater.from(parent.getContext());
    287                 }
    288                 convertView = mInflater.inflate(mListItemLayout, parent, false);
    289             }
    290             onBindListItem(convertView, position);
    291             return convertView;
    292         }
    293     }
    294 
    295     private static class SavedState extends BaseSavedState {
    296         public int value;
    297 
    298         public SavedState(Parcel source) {
    299             super(source);
    300             value = source.readInt();
    301         }
    302 
    303         @Override
    304         public void writeToParcel(Parcel dest, int flags) {
    305             super.writeToParcel(dest, flags);
    306             dest.writeInt(value);
    307         }
    308 
    309         public SavedState(Parcelable superState) {
    310             super(superState);
    311         }
    312 
    313         @SuppressWarnings({ "hiding", "unused" })
    314         public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
    315             @Override
    316             public SavedState createFromParcel(Parcel in) {
    317                 return new SavedState(in);
    318             }
    319 
    320             @Override
    321             public SavedState[] newArray(int size) {
    322                 return new SavedState[size];
    323             }
    324         };
    325     }
    326 
    327     public interface OnValueChangedListener {
    328         public void onValueChanged(ListDialogPreference preference, int value);
    329     }
    330 }
    331