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