• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AutoCompleteEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)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 
AutoCompleteEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr)86     public AutoCompleteEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
87         this(context, attrs, defStyleAttr, 0);
88     }
89 
AutoCompleteEditTextPreference(Context context, AttributeSet attrs)90     public AutoCompleteEditTextPreference(Context context, AttributeSet attrs) {
91         this(context, attrs, android.R.attr.dialogPreferenceStyle);
92     }
93 
AutoCompleteEditTextPreference(Context context)94     public AutoCompleteEditTextPreference(Context context) {
95         this(context, null);
96     }
97 
getAutoCompleteTextView()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      */
setText(String text)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
showDialog(Bundle state)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
onClick()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      */
getText()139     public String getText() {
140         return mText;
141     }
142 
143     @Override
onBindDialogView(View view)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      */
onAddEditTextToDialogView(View dialogView, AutoCompleteTextView editText)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
onDialogClosed(boolean positiveResult)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
onGetDefaultValue(TypedArray a, int index)187     protected Object onGetDefaultValue(TypedArray a, int index) {
188         return a.getString(index);
189     }
190 
191     @Override
onSetInitialValue(boolean restoreValue, Object defaultValue)192     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
193         setText(restoreValue ? getPersistedString(mText) : (String) defaultValue);
194     }
195 
196     @Override
shouldDisableDependents()197     public boolean shouldDisableDependents() {
198         return TextUtils.isEmpty(mText) || super.shouldDisableDependents();
199     }
200 
201     @Override
onSaveInstanceState()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
onRestoreInstanceState(Parcelable state)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 
SavedState(Parcel source)230         public SavedState(Parcel source) {
231             super(source);
232             text = source.readString();
233         }
234 
235         @Override
writeToParcel(Parcel dest, int flags)236         public void writeToParcel(Parcel dest, int flags) {
237             super.writeToParcel(dest, flags);
238             dest.writeString(text);
239         }
240 
SavedState(Parcelable superState)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 {
InstantAutoCompleteTextView(Context context, AttributeSet attrs)259         public InstantAutoCompleteTextView(Context context, AttributeSet attrs) {
260             super(context, attrs);
261         }
262 
263         @Override
enoughToFilter()264         public boolean enoughToFilter() {
265             return true;
266         }
267 
268         @Override
onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect)269         protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
270             super.onFocusChanged(focused, direction, previouslyFocusedRect);
271 
272             showDropDownIfFocused();
273         }
274 
275         @Override
onAttachedToWindow()276         protected void onAttachedToWindow() {
277             super.onAttachedToWindow();
278             showDropDownIfFocused();
279         }
280 
showDropDownIfFocused()281         private void showDropDownIfFocused() {
282             if (isFocused() && getWindowVisibility() == View.VISIBLE) {
283                 showDropDown();
284             }
285         }
286     }
287 
288 }
289