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