/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.emergency.preferences; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.res.TypedArray; import android.graphics.Rect; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.preference.DialogPreference; import android.text.TextUtils; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.widget.AutoCompleteTextView; import android.widget.TextView; import com.android.emergency.R; import com.android.internal.annotations.VisibleForTesting; /** * Almost a copy of EditTextPreference that shows a {@link AutoCompleteTextView} instead of the * basic EditText. It always show the suggested options. */ public class AutoCompleteEditTextPreference extends DialogPreference { /** * The edit text shown in the dialog. */ private AutoCompleteTextView mAutoCompleteTextView; private String mText; private boolean mTextSet; public AutoCompleteEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mAutoCompleteTextView = new InstantAutoCompleteTextView(context, attrs); // Give it an ID so it can be saved/restored mAutoCompleteTextView.setId(R.id.edit); /* * The preference framework and view framework both have an 'enabled' * attribute. Most likely, the 'enabled' specified in this XML is for * the preference framework, but it was also given to the view framework. * We reset the enabled state. */ mAutoCompleteTextView.setEnabled(true); mAutoCompleteTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_DONE) { onClick(getDialog(), DialogInterface.BUTTON_POSITIVE); getDialog().dismiss(); return true; } return false; } }); setDialogLayoutResource(R.layout.preference_dialog_autocomplete_edittext); } public AutoCompleteEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public AutoCompleteEditTextPreference(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.dialogPreferenceStyle); } public AutoCompleteEditTextPreference(Context context) { this(context, null); } public AutoCompleteTextView getAutoCompleteTextView() { return mAutoCompleteTextView; } /** * Saves the text to the {@link SharedPreferences}. * * @param text The text to save */ public void setText(String text) { // Always persist/notify the first time. final boolean changed = !TextUtils.equals(mText, text); if (changed || !mTextSet) { mText = text; mTextSet = true; persistString(text); if (changed) { notifyDependencyChange(shouldDisableDependents()); notifyChanged(); } } } @Override public void showDialog(Bundle state) { super.showDialog(state); Window window = getDialog().getWindow(); window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); } @VisibleForTesting @Override public void onClick() { super.onClick(); } /** * Gets the text from the {@link SharedPreferences}. * * @return The current preference value. */ public String getText() { return mText; } @Override protected void onBindDialogView(View view) { super.onBindDialogView(view); AutoCompleteTextView editText = mAutoCompleteTextView; editText.setText(getText()); ViewParent oldParent = editText.getParent(); if (oldParent != view) { if (oldParent != null) { ((ViewGroup) oldParent).removeView(editText); } onAddEditTextToDialogView(view, editText); } } /** * Adds the AutoCompleteTextView widget of this preference to the dialog's view. * * @param dialogView The dialog view. */ protected void onAddEditTextToDialogView(View dialogView, AutoCompleteTextView editText) { ViewGroup container = (ViewGroup) dialogView .findViewById(R.id.autocomplete_edittext_container); if (container != null) { container.addView(editText, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } } @Override protected void onDialogClosed(boolean positiveResult) { super.onDialogClosed(positiveResult); if (positiveResult) { String value = mAutoCompleteTextView.getText().toString(); if (callChangeListener(value)) { setText(value); } } } @Override protected Object onGetDefaultValue(TypedArray a, int index) { return a.getString(index); } @Override protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { setText(restoreValue ? getPersistedString(mText) : (String) defaultValue); } @Override public boolean shouldDisableDependents() { return TextUtils.isEmpty(mText) || super.shouldDisableDependents(); } @Override protected Parcelable onSaveInstanceState() { final Parcelable superState = super.onSaveInstanceState(); if (isPersistent()) { // No need to save instance state since it's persistent return superState; } final SavedState myState = new SavedState(superState); myState.text = getText(); return myState; } @Override protected void onRestoreInstanceState(Parcelable state) { if (state == null || !state.getClass().equals(SavedState.class)) { // Didn't save state for us in onSaveInstanceState super.onRestoreInstanceState(state); return; } SavedState myState = (SavedState) state; super.onRestoreInstanceState(myState.getSuperState()); setText(myState.text); } private static class SavedState extends BaseSavedState { String text; public SavedState(Parcel source) { super(source); text = source.readString(); } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeString(text); } public SavedState(Parcelable superState) { super(superState); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public SavedState createFromParcel(Parcel in) { return new SavedState(in); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; } /** {@link AutoCompleteTextView} that always shows the suggestions. */ private class InstantAutoCompleteTextView extends AutoCompleteTextView { public InstantAutoCompleteTextView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean enoughToFilter() { return true; } @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(focused, direction, previouslyFocusedRect); showDropDownIfFocused(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); showDropDownIfFocused(); } private void showDropDownIfFocused() { if (isFocused() && getWindowVisibility() == View.VISIBLE) { showDropDown(); } } } }