TextFieldsEditorView.java revision da5bf1cf60beef3de5e651a569fa544293683926
1392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann/*
2392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Copyright (C) 2010 The Android Open Source Project
3392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
4392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * you may not use this file except in compliance with the License.
6392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * You may obtain a copy of the License at
7392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
8392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
10392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Unless required by applicable law or agreed to in writing, software
11392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * See the License for the specific language governing permissions and
14392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * limitations under the License.
15392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann */
16392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts.editor;
18392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
19392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.ContactsUtils;
20392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.R;
214597c92d655d45447780b32c7572acef110b6ed1Dmitri Plotnikovimport com.android.contacts.model.AccountType.EditField;
22405671a7b42d97ebf7ae7c0eeb4721f881139673Daisuke Miyakawaimport com.android.contacts.model.DataKind;
23392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.model.EntityDelta;
24392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.model.EntityDelta.ValuesDelta;
25da5bf1cf60beef3de5e651a569fa544293683926Dave Santoroimport com.android.contacts.util.NameConverter;
26392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
27392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.content.Context;
28392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.content.Entity;
29392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.graphics.Rect;
30da5bf1cf60beef3de5e651a569fa544293683926Dave Santoroimport android.graphics.Typeface;
31392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.os.Parcel;
32392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.os.Parcelable;
33a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
34392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.telephony.PhoneNumberFormattingTextWatcher;
35392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.text.Editable;
36392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.text.InputType;
37da5bf1cf60beef3de5e651a569fa544293683926Dave Santoroimport android.text.Spannable;
381b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.text.TextUtils;
39392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.text.TextWatcher;
40da5bf1cf60beef3de5e651a569fa544293683926Dave Santoroimport android.text.style.StyleSpan;
41392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.util.AttributeSet;
42392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.view.Gravity;
43392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.view.View;
4463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuanimport android.view.ViewGroup;
45392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.widget.EditText;
4612a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuanimport android.widget.ImageView;
47392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.widget.LinearLayout;
48da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
49da5bf1cf60beef3de5e651a569fa544293683926Dave Santoroimport java.util.Map;
50392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
51392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann/**
5263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan * Simple editor that handles labels and any {@link EditField} defined for the
5363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan * entry. Uses {@link ValuesDelta} to read any existing {@link Entity} values,
5463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan * and to correctly write any changes values.
55392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann */
56392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannpublic class TextFieldsEditorView extends LabeledEditorView {
57392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private EditText[] mFieldEditTexts = null;
5863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    private ViewGroup mFields = null;
5912a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    private View mExpansionViewContainer;
6012a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    private ImageView mExpansionView;
61392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private boolean mHideOptional = true;
62392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private boolean mHasShortAndLongForms;
63a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan    private int mEditorTextSize = 0;
64392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
65392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public TextFieldsEditorView(Context context) {
66392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(context);
67392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
68392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
69392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public TextFieldsEditorView(Context context, AttributeSet attrs) {
70392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(context, attrs);
71392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
72392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
73392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public TextFieldsEditorView(Context context, AttributeSet attrs, int defStyle) {
74392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(context, attrs, defStyle);
75392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
76392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
7763ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    /** {@inheritDoc} */
7891d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    @Override
7963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    protected void onFinishInflate() {
8063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        super.onFinishInflate();
8163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
8263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        setDrawingCacheEnabled(true);
8363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        setAlwaysDrawnWithCacheEnabled(true);
8463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
8563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        mFields = (ViewGroup) findViewById(R.id.editors);
8612a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan        mExpansionView = (ImageView) findViewById(R.id.expansion_view);
8712a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan        mExpansionViewContainer = findViewById(R.id.expansion_view_container);
8812a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan        mExpansionViewContainer.setOnClickListener(new OnClickListener() {
8963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            @Override
9063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            public void onClick(View v) {
9163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                // Save focus
9263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                final View focusedChild = getFocusedChild();
9363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                final int focusedViewId = focusedChild == null ? -1 : focusedChild.getId();
9463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
9563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                // Reconfigure GUI
9663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                mHideOptional = !mHideOptional;
9763ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                onOptionalFieldVisibilityChange();
9863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                rebuildValues();
9963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
10063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                // Restore focus
10163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                View newFocusView = findViewById(focusedViewId);
10263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                if (newFocusView == null || newFocusView.getVisibility() == GONE) {
10363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                    // find first visible child
10463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                    newFocusView = TextFieldsEditorView.this;
105392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
10663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                newFocusView.requestFocus();
107392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
10863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        });
109392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
110392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
111a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan    /**
112a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan     * Set the text size of the value of all fields in this class, which will override the default
113a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan     * text appearance style for the associated {@link DataKind}.
114a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan     */
11563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    public void setEditorTextSize(int textSize) {
116a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan        mEditorTextSize = textSize;
117392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
118392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
119392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
120392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setEnabled(boolean enabled) {
121392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super.setEnabled(enabled);
122392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
123392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mFieldEditTexts != null) {
124392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            for (int index = 0; index < mFieldEditTexts.length; index++) {
12502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                mFieldEditTexts[index].setEnabled(!isReadOnly() && enabled);
126392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
127392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
12812a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan        mExpansionView.setEnabled(!isReadOnly() && enabled);
129392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
130392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
131392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
132392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Creates or removes the type/label button. Doesn't do anything if already correctly configured
133392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
13412a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    private void setupExpansionView(boolean shouldExist, boolean collapsed) {
135392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (shouldExist) {
13612a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan            mExpansionViewContainer.setVisibility(View.VISIBLE);
13712a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan            mExpansionView.setImageResource(collapsed
138915ffc5ae1d10a7ed06d5541fe81da023fa3228fDaniel Lehmann                    ? R.drawable.ic_menu_expander_minimized_holo_light
139915ffc5ae1d10a7ed06d5541fe81da023fa3228fDaniel Lehmann                    : R.drawable.ic_menu_expander_maximized_holo_light);
14063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        } else {
14112a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan            mExpansionViewContainer.setVisibility(View.GONE);
142392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
143392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
144392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
145392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
146392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void requestFocusForFirstEditField() {
147392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mFieldEditTexts != null && mFieldEditTexts.length != 0) {
148392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            EditText firstField = null;
149392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            boolean anyFieldHasFocus = false;
150392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            for (EditText editText : mFieldEditTexts) {
151392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                if (firstField == null && editText.getVisibility() == View.VISIBLE) {
152392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    firstField = editText;
153392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
154392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                if (editText.hasFocus()) {
155392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    anyFieldHasFocus = true;
156392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    break;
157392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
158392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
159392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            if (!anyFieldHasFocus && firstField != null) {
160392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                firstField.requestFocus();
161392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
162392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
163392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
164392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
165392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
166392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
167392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            ViewIdGenerator vig) {
168392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super.setValues(kind, entry, state, readOnly, vig);
169392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // Remove edit texts that we currently have
170392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mFieldEditTexts != null) {
171392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            for (EditText fieldEditText : mFieldEditTexts) {
17263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                mFields.removeView(fieldEditText);
173392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
174392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
175392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        boolean hidePossible = false;
176392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
177392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        int fieldCount = kind.fieldList.size();
178392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mFieldEditTexts = new EditText[fieldCount];
179392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        for (int index = 0; index < fieldCount; index++) {
180392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            final EditField field = kind.fieldList.get(index);
181392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            final EditText fieldView = new EditText(mContext);
182392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            fieldView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
183392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    LayoutParams.WRAP_CONTENT));
184a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan            fieldView.setTextAppearance(getContext(), kind.textAppearanceResourceId);
185a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan            if (mEditorTextSize != 0) {
186a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan                fieldView.setTextSize(mEditorTextSize);
187a2d4a9652fb4db9ee222abc7a637366c6c50427cKatherine Kuan            }
188392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            fieldView.setGravity(Gravity.TOP);
189392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mFieldEditTexts[index] = fieldView;
190392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            fieldView.setId(vig.getId(state, kind, entry, index));
191392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            if (field.titleRes > 0) {
192392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                fieldView.setHint(field.titleRes);
193392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
194392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            int inputType = field.inputType;
195392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            fieldView.setInputType(inputType);
196da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            if (field.isFullName) {
197da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                fieldView.addTextChangedListener(new NameFormattingTextWatcher());
198da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            }
199392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            if (inputType == InputType.TYPE_CLASS_PHONE) {
200392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                fieldView.addTextChangedListener(new PhoneNumberFormattingTextWatcher(
201392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                        ContactsUtils.getCurrentCountryIso(mContext)));
202392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
203392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            fieldView.setMinLines(field.minLines);
204392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
205392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            // Read current value from state
206392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            final String column = field.column;
207392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            final String value = entry.getAsString(column);
208392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            fieldView.setText(value);
209392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
210392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            // Prepare listener for writing changes
211392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            fieldView.addTextChangedListener(new TextWatcher() {
212392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                @Override
213392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                public void afterTextChanged(Editable s) {
214392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    // Trigger event for newly changed value
215392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    onFieldChanged(column, s.toString());
216392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
217392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
218392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                @Override
219392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
220392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
221392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
222392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                @Override
223392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                public void onTextChanged(CharSequence s, int start, int before, int count) {
224392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
225392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            });
226392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
22702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            fieldView.setEnabled(isEnabled() && !readOnly);
228392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
229392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            if (field.shortForm) {
230392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                hidePossible = true;
231392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                mHasShortAndLongForms = true;
232392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                fieldView.setVisibility(mHideOptional ? View.VISIBLE : View.GONE);
233392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            } else if (field.longForm) {
234392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                hidePossible = true;
235392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                mHasShortAndLongForms = true;
236392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                fieldView.setVisibility(mHideOptional ? View.GONE : View.VISIBLE);
237392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            } else {
238392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                // Hide field when empty and optional value
239392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                final boolean couldHide = (!ContactsUtils.isGraphic(value) && field.optional);
240392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                final boolean willHide = (mHideOptional && couldHide);
241392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                fieldView.setVisibility(willHide ? View.GONE : View.VISIBLE);
242392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                hidePossible = hidePossible || couldHide;
243392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
244392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
24563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            mFields.addView(fieldView);
246392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
247392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
248392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // When hiding fields, place expandable
24912a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan        setupExpansionView(hidePossible, mHideOptional);
25012a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan        mExpansionView.setEnabled(!readOnly && isEnabled());
251392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
252392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
2532591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan    @Override
2542591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan    public boolean isEmpty() {
2551b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        for (int i = 0; i < mFields.getChildCount(); i++) {
2561b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            EditText editText = (EditText) mFields.getChildAt(i);
2572591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan            if (!TextUtils.isEmpty(editText.getText())) {
2582591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan                return false;
2591b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            }
2601b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        }
2612591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        return true;
2621b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    }
2631b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan
264392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
265392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Returns true if the editor is currently configured to show optional fields.
266392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
267392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public boolean areOptionalFieldsVisible() {
268392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return !mHideOptional;
269392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
270392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
271392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public boolean hasShortAndLongForms() {
272392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mHasShortAndLongForms;
273392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
274392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
275392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
276392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Populates the bound rectangle with the bounds of the last editor field inside this view.
277392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
278392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void acquireEditorBounds(Rect bounds) {
279392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mFieldEditTexts != null) {
280392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            for (int i = mFieldEditTexts.length; --i >= 0;) {
281392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                EditText editText = mFieldEditTexts[i];
282392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                if (editText.getVisibility() == View.VISIBLE) {
283392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    bounds.set(editText.getLeft(), editText.getTop(), editText.getRight(),
284392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                            editText.getBottom());
285392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    return;
286392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
287392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
288392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
289392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
290392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
291392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
292392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Saves the visibility of the child EditTexts, and mHideOptional.
293392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
294392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
295392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected Parcelable onSaveInstanceState() {
296392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        Parcelable superState = super.onSaveInstanceState();
297392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        SavedState ss = new SavedState(superState);
298392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
299392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        ss.mHideOptional = mHideOptional;
300392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
3015ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov        final int numChildren = mFieldEditTexts == null ? 0 : mFieldEditTexts.length;
302392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        ss.mVisibilities = new int[numChildren];
303392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        for (int i = 0; i < numChildren; i++) {
304392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            ss.mVisibilities[i] = mFieldEditTexts[i].getVisibility();
305392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
306392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
307392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return ss;
308392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
309392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
310392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
311392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Restores the visibility of the child EditTexts, and mHideOptional.
312392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
313392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
314392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void onRestoreInstanceState(Parcelable state) {
315392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        SavedState ss = (SavedState) state;
316392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super.onRestoreInstanceState(ss.getSuperState());
317392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
318392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mHideOptional = ss.mHideOptional;
319392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
320392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        int numChildren = Math.min(mFieldEditTexts.length, ss.mVisibilities.length);
321392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        for (int i = 0; i < numChildren; i++) {
322392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mFieldEditTexts[i].setVisibility(ss.mVisibilities[i]);
323392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
324392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
325392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
326392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static class SavedState extends BaseSavedState {
327392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        public boolean mHideOptional;
328392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        public int[] mVisibilities;
329392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
330392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        SavedState(Parcelable superState) {
331392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            super(superState);
332392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
333392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
334392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        private SavedState(Parcel in) {
335392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            super(in);
336392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mVisibilities = new int[in.readInt()];
337392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            in.readIntArray(mVisibilities);
338392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
339392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
340392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        @Override
341392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        public void writeToParcel(Parcel out, int flags) {
342392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            super.writeToParcel(out, flags);
343392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            out.writeInt(mVisibilities.length);
344392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            out.writeIntArray(mVisibilities);
345392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
346392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
347cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann        @SuppressWarnings({"unused", "hiding" })
348392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        public static final Parcelable.Creator<SavedState> CREATOR
349392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                = new Parcelable.Creator<SavedState>() {
350392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            @Override
351392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            public SavedState createFromParcel(Parcel in) {
352392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                return new SavedState(in);
353392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
354392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
355392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            @Override
356392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            public SavedState[] newArray(int size) {
357392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                return new SavedState[size];
358392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
359392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        };
360392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
361da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
362da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro    private class NameFormattingTextWatcher implements TextWatcher {
363da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
364da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
365da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        @Override
366da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
367da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
368da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        @Override
369da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        public void onTextChanged(CharSequence s, int start, int before, int count) {}
370da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
371da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        @Override
372da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        public void afterTextChanged(Editable s) {
373da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            String displayName = s.toString();
374da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            Map<String, String> structuredName = NameConverter.displayNameToStructuredName(
375da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    getContext(), displayName);
376da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            String givenName = structuredName.get(StructuredName.GIVEN_NAME);
377da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            if (!TextUtils.isEmpty(givenName)) {
378da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                int spanStart = -1;
379da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                int spanEnd = -1;
380da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                if (displayName.startsWith(givenName + " ")) {
381da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    spanStart = 0;
382da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    spanEnd = givenName.length();
383da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                } else {
384da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    spanStart = displayName.lastIndexOf(" " + givenName);
385da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    if (spanStart > -1) {
386da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                        spanStart++;
387da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                        spanEnd = spanStart + givenName.length();
388da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    }
389da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                }
390da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
391da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                // If the requested range is already bolded, don't make any changes.
392da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                if (spanStart > -1) {
393da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    StyleSpan[] existingSpans = s.getSpans(0, s.length(), StyleSpan.class);
394da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    for (StyleSpan span : existingSpans) {
395da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                        if (span.getStyle() == Typeface.BOLD
396da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                                && s.getSpanStart(span.getUnderlying()) == spanStart
397da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                                && s.getSpanEnd(span.getUnderlying()) == spanEnd) {
398da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                            // Nothing to do - the correct portion is already bolded.
399da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                            return;
400da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                        }
401da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    }
402da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
403da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    // Clear any existing bold style spans.
404da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    for (StyleSpan span : existingSpans) {
405da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                        if (span.getStyle() == Typeface.BOLD) {
406da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                            s.removeSpan(span);
407da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                        }
408da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    }
409da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro
410da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    // Set the new bold span.
411da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                    s.setSpan(new StyleSpan(Typeface.BOLD), spanStart, spanEnd,
412da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
413da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro                }
414da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro            }
415da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro        }
416da5bf1cf60beef3de5e651a569fa544293683926Dave Santoro    }
417392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann}
418