Home | History | Annotate | Download | only in preferences
      1 /*
      2  * Copyright (C) 2016 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 package com.android.emergency.preferences;
     17 
     18 import android.content.Context;
     19 import android.content.DialogInterface;
     20 import android.content.SharedPreferences;
     21 import android.content.res.TypedArray;
     22 import android.graphics.Rect;
     23 import android.os.Bundle;
     24 import android.os.Parcel;
     25 import android.os.Parcelable;
     26 import android.preference.DialogPreference;
     27 import android.text.TextUtils;
     28 import android.util.AttributeSet;
     29 import android.view.KeyEvent;
     30 import android.view.View;
     31 import android.view.ViewGroup;
     32 import android.view.ViewParent;
     33 import android.view.Window;
     34 import android.view.WindowManager;
     35 import android.view.inputmethod.EditorInfo;
     36 import android.widget.AutoCompleteTextView;
     37 import android.widget.TextView;
     38 
     39 import com.android.emergency.R;
     40 import com.android.internal.annotations.VisibleForTesting;
     41 
     42 /**
     43  * Almost a copy of EditTextPreference that shows a {@link AutoCompleteTextView} instead of the
     44  * basic EditText. It always show the suggested options.
     45  */
     46 public class AutoCompleteEditTextPreference extends DialogPreference {
     47     /**
     48      * The edit text shown in the dialog.
     49      */
     50     private AutoCompleteTextView mAutoCompleteTextView;
     51 
     52     private String mText;
     53     private boolean mTextSet;
     54 
     55     public AutoCompleteEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr,
     56                                           int defStyleRes) {
     57         super(context, attrs, defStyleAttr, defStyleRes);
     58 
     59         mAutoCompleteTextView = new InstantAutoCompleteTextView(context, attrs);
     60 
     61         // Give it an ID so it can be saved/restored
     62         mAutoCompleteTextView.setId(R.id.edit);
     63 
     64         /*
     65          * The preference framework and view framework both have an 'enabled'
     66          * attribute. Most likely, the 'enabled' specified in this XML is for
     67          * the preference framework, but it was also given to the view framework.
     68          * We reset the enabled state.
     69          */
     70         mAutoCompleteTextView.setEnabled(true);
     71 
     72         mAutoCompleteTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
     73             @Override
     74             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
     75                 if (actionId == EditorInfo.IME_ACTION_DONE) {
     76                     onClick(getDialog(), DialogInterface.BUTTON_POSITIVE);
     77                     getDialog().dismiss();
     78                     return true;
     79                 }
     80                 return false;
     81             }
     82         });
     83         setDialogLayoutResource(R.layout.preference_dialog_autocomplete_edittext);
     84     }
     85 
     86     public AutoCompleteEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
     87         this(context, attrs, defStyleAttr, 0);
     88     }
     89 
     90     public AutoCompleteEditTextPreference(Context context, AttributeSet attrs) {
     91         this(context, attrs, android.R.attr.dialogPreferenceStyle);
     92     }
     93 
     94     public AutoCompleteEditTextPreference(Context context) {
     95         this(context, null);
     96     }
     97 
     98     public AutoCompleteTextView getAutoCompleteTextView() {
     99         return mAutoCompleteTextView;
    100     }
    101 
    102     /**
    103      * Saves the text to the {@link SharedPreferences}.
    104      *
    105      * @param text The text to save
    106      */
    107     public void setText(String text) {
    108         // Always persist/notify the first time.
    109         final boolean changed = !TextUtils.equals(mText, text);
    110         if (changed || !mTextSet) {
    111             mText = text;
    112             mTextSet = true;
    113             persistString(text);
    114             if (changed) {
    115                 notifyDependencyChange(shouldDisableDependents());
    116                 notifyChanged();
    117             }
    118         }
    119     }
    120 
    121     @Override
    122     public void showDialog(Bundle state) {
    123         super.showDialog(state);
    124         Window window = getDialog().getWindow();
    125         window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
    126     }
    127 
    128     @VisibleForTesting
    129     @Override
    130     public void onClick() {
    131         super.onClick();
    132     }
    133 
    134     /**
    135      * Gets the text from the {@link SharedPreferences}.
    136      *
    137      * @return The current preference value.
    138      */
    139     public String getText() {
    140         return mText;
    141     }
    142 
    143     @Override
    144     protected void onBindDialogView(View view) {
    145         super.onBindDialogView(view);
    146 
    147         AutoCompleteTextView editText = mAutoCompleteTextView;
    148         editText.setText(getText());
    149 
    150         ViewParent oldParent = editText.getParent();
    151         if (oldParent != view) {
    152             if (oldParent != null) {
    153                 ((ViewGroup) oldParent).removeView(editText);
    154             }
    155             onAddEditTextToDialogView(view, editText);
    156         }
    157         editText.setSelection(editText.getText().length());
    158     }
    159 
    160     /**
    161      * Adds the AutoCompleteTextView widget of this preference to the dialog's view.
    162      *
    163      * @param dialogView The dialog view.
    164      */
    165     protected void onAddEditTextToDialogView(View dialogView, AutoCompleteTextView editText) {
    166         ViewGroup container = (ViewGroup) dialogView
    167                 .findViewById(R.id.autocomplete_edittext_container);
    168         if (container != null) {
    169             container.addView(editText, ViewGroup.LayoutParams.MATCH_PARENT,
    170                     ViewGroup.LayoutParams.WRAP_CONTENT);
    171         }
    172     }
    173 
    174     @Override
    175     protected void onDialogClosed(boolean positiveResult) {
    176         super.onDialogClosed(positiveResult);
    177 
    178         if (positiveResult) {
    179             String value = mAutoCompleteTextView.getText().toString();
    180             if (callChangeListener(value)) {
    181                 setText(value);
    182             }
    183         }
    184     }
    185 
    186     @Override
    187     protected Object onGetDefaultValue(TypedArray a, int index) {
    188         return a.getString(index);
    189     }
    190 
    191     @Override
    192     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
    193         setText(restoreValue ? getPersistedString(mText) : (String) defaultValue);
    194     }
    195 
    196     @Override
    197     public boolean shouldDisableDependents() {
    198         return TextUtils.isEmpty(mText) || super.shouldDisableDependents();
    199     }
    200 
    201     @Override
    202     protected Parcelable onSaveInstanceState() {
    203         final Parcelable superState = super.onSaveInstanceState();
    204         if (isPersistent()) {
    205             // No need to save instance state since it's persistent
    206             return superState;
    207         }
    208 
    209         final SavedState myState = new SavedState(superState);
    210         myState.text = getText();
    211         return myState;
    212     }
    213 
    214     @Override
    215     protected void onRestoreInstanceState(Parcelable state) {
    216         if (state == null || !state.getClass().equals(SavedState.class)) {
    217             // Didn't save state for us in onSaveInstanceState
    218             super.onRestoreInstanceState(state);
    219             return;
    220         }
    221 
    222         SavedState myState = (SavedState) state;
    223         super.onRestoreInstanceState(myState.getSuperState());
    224         setText(myState.text);
    225     }
    226 
    227     private static class SavedState extends BaseSavedState {
    228         String text;
    229 
    230         public SavedState(Parcel source) {
    231             super(source);
    232             text = source.readString();
    233         }
    234 
    235         @Override
    236         public void writeToParcel(Parcel dest, int flags) {
    237             super.writeToParcel(dest, flags);
    238             dest.writeString(text);
    239         }
    240 
    241         public SavedState(Parcelable superState) {
    242             super(superState);
    243         }
    244 
    245         public static final Parcelable.Creator<SavedState> CREATOR =
    246                 new Parcelable.Creator<SavedState>() {
    247                     public SavedState createFromParcel(Parcel in) {
    248                         return new SavedState(in);
    249                     }
    250 
    251                     public SavedState[] newArray(int size) {
    252                         return new SavedState[size];
    253                     }
    254                 };
    255     }
    256 
    257     /** {@link AutoCompleteTextView} that always shows the suggestions. */
    258     private class InstantAutoCompleteTextView extends AutoCompleteTextView {
    259         public InstantAutoCompleteTextView(Context context, AttributeSet attrs) {
    260             super(context, attrs);
    261         }
    262 
    263         @Override
    264         public boolean enoughToFilter() {
    265             return true;
    266         }
    267 
    268         @Override
    269         protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
    270             super.onFocusChanged(focused, direction, previouslyFocusedRect);
    271 
    272             showDropDownIfFocused();
    273         }
    274 
    275         @Override
    276         protected void onAttachedToWindow() {
    277             super.onAttachedToWindow();
    278             showDropDownIfFocused();
    279         }
    280 
    281         private void showDropDownIfFocused() {
    282             if (isFocused() && getWindowVisibility() == View.VISIBLE) {
    283                 showDropDown();
    284             }
    285         }
    286     }
    287 
    288 }
    289