1/*
2 * Copyright (C) 2007 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
17package android.preference;
18
19
20import android.content.Context;
21import android.content.SharedPreferences;
22import android.content.res.TypedArray;
23import android.os.Parcel;
24import android.os.Parcelable;
25import android.text.TextUtils;
26import android.util.AttributeSet;
27import android.view.View;
28import android.view.ViewGroup;
29import android.view.ViewParent;
30import android.widget.EditText;
31
32/**
33 * A {@link Preference} that allows for string
34 * input.
35 * <p>
36 * It is a subclass of {@link DialogPreference} and shows the {@link EditText}
37 * in a dialog. This {@link EditText} can be modified either programmatically
38 * via {@link #getEditText()}, or through XML by setting any EditText
39 * attributes on the EditTextPreference.
40 * <p>
41 * This preference will store a string into the SharedPreferences.
42 * <p>
43 * See {@link android.R.styleable#EditText EditText Attributes}.
44 */
45public class EditTextPreference extends DialogPreference {
46    /**
47     * The edit text shown in the dialog.
48     */
49    private EditText mEditText;
50
51    private String mText;
52
53    public EditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
54        super(context, attrs, defStyleAttr, defStyleRes);
55
56        mEditText = new EditText(context, attrs);
57
58        // Give it an ID so it can be saved/restored
59        mEditText.setId(com.android.internal.R.id.edit);
60
61        /*
62         * The preference framework and view framework both have an 'enabled'
63         * attribute. Most likely, the 'enabled' specified in this XML is for
64         * the preference framework, but it was also given to the view framework.
65         * We reset the enabled state.
66         */
67        mEditText.setEnabled(true);
68    }
69
70    public EditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
71        this(context, attrs, defStyleAttr, 0);
72    }
73
74    public EditTextPreference(Context context, AttributeSet attrs) {
75        this(context, attrs, com.android.internal.R.attr.editTextPreferenceStyle);
76    }
77
78    public EditTextPreference(Context context) {
79        this(context, null);
80    }
81
82    /**
83     * Saves the text to the {@link SharedPreferences}.
84     *
85     * @param text The text to save
86     */
87    public void setText(String text) {
88        final boolean wasBlocking = shouldDisableDependents();
89
90        mText = text;
91
92        persistString(text);
93
94        final boolean isBlocking = shouldDisableDependents();
95        if (isBlocking != wasBlocking) {
96            notifyDependencyChange(isBlocking);
97        }
98    }
99
100    /**
101     * Gets the text from the {@link SharedPreferences}.
102     *
103     * @return The current preference value.
104     */
105    public String getText() {
106        return mText;
107    }
108
109    @Override
110    protected void onBindDialogView(View view) {
111        super.onBindDialogView(view);
112
113        EditText editText = mEditText;
114        editText.setText(getText());
115
116        ViewParent oldParent = editText.getParent();
117        if (oldParent != view) {
118            if (oldParent != null) {
119                ((ViewGroup) oldParent).removeView(editText);
120            }
121            onAddEditTextToDialogView(view, editText);
122        }
123    }
124
125    /**
126     * Adds the EditText widget of this preference to the dialog's view.
127     *
128     * @param dialogView The dialog view.
129     */
130    protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
131        ViewGroup container = (ViewGroup) dialogView
132                .findViewById(com.android.internal.R.id.edittext_container);
133        if (container != null) {
134            container.addView(editText, ViewGroup.LayoutParams.MATCH_PARENT,
135                    ViewGroup.LayoutParams.WRAP_CONTENT);
136        }
137    }
138
139    @Override
140    protected void onDialogClosed(boolean positiveResult) {
141        super.onDialogClosed(positiveResult);
142
143        if (positiveResult) {
144            String value = mEditText.getText().toString();
145            if (callChangeListener(value)) {
146                setText(value);
147            }
148        }
149    }
150
151    @Override
152    protected Object onGetDefaultValue(TypedArray a, int index) {
153        return a.getString(index);
154    }
155
156    @Override
157    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
158        setText(restoreValue ? getPersistedString(mText) : (String) defaultValue);
159    }
160
161    @Override
162    public boolean shouldDisableDependents() {
163        return TextUtils.isEmpty(mText) || super.shouldDisableDependents();
164    }
165
166    /**
167     * Returns the {@link EditText} widget that will be shown in the dialog.
168     *
169     * @return The {@link EditText} widget that will be shown in the dialog.
170     */
171    public EditText getEditText() {
172        return mEditText;
173    }
174
175    /** @hide */
176    @Override
177    protected boolean needInputMethod() {
178        // We want the input method to show, if possible, when dialog is displayed
179        return true;
180    }
181
182    @Override
183    protected Parcelable onSaveInstanceState() {
184        final Parcelable superState = super.onSaveInstanceState();
185        if (isPersistent()) {
186            // No need to save instance state since it's persistent
187            return superState;
188        }
189
190        final SavedState myState = new SavedState(superState);
191        myState.text = getText();
192        return myState;
193    }
194
195    @Override
196    protected void onRestoreInstanceState(Parcelable state) {
197        if (state == null || !state.getClass().equals(SavedState.class)) {
198            // Didn't save state for us in onSaveInstanceState
199            super.onRestoreInstanceState(state);
200            return;
201        }
202
203        SavedState myState = (SavedState) state;
204        super.onRestoreInstanceState(myState.getSuperState());
205        setText(myState.text);
206    }
207
208    private static class SavedState extends BaseSavedState {
209        String text;
210
211        public SavedState(Parcel source) {
212            super(source);
213            text = source.readString();
214        }
215
216        @Override
217        public void writeToParcel(Parcel dest, int flags) {
218            super.writeToParcel(dest, flags);
219            dest.writeString(text);
220        }
221
222        public SavedState(Parcelable superState) {
223            super(superState);
224        }
225
226        public static final Parcelable.Creator<SavedState> CREATOR =
227                new Parcelable.Creator<SavedState>() {
228            public SavedState createFromParcel(Parcel in) {
229                return new SavedState(in);
230            }
231
232            public SavedState[] newArray(int size) {
233                return new SavedState[size];
234            }
235        };
236    }
237
238}
239