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