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