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