Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2010 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 | |
Dmitri Plotnikov | 18ffaa2 | 2010-12-03 14:28:00 -0800 | [diff] [blame] | 17 | package com.android.contacts.editor; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 18 | |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 19 | import android.content.Context; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 20 | import android.graphics.Rect; |
Gary Mai | 3e9637f | 2016-09-06 18:22:55 -0700 | [diff] [blame] | 21 | import android.graphics.drawable.Drawable; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 22 | import android.os.Parcel; |
| 23 | import android.os.Parcelable; |
Tingting Wang | b6949dc | 2015-11-03 13:17:12 -0800 | [diff] [blame] | 24 | import android.provider.ContactsContract; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 25 | import android.text.Editable; |
| 26 | import android.text.InputType; |
Wenyi Wang | 1d89622 | 2016-03-24 16:50:48 -0700 | [diff] [blame] | 27 | import android.text.Spannable; |
Katherine Kuan | 1b22073 | 2011-04-28 18:45:39 -0700 | [diff] [blame] | 28 | import android.text.TextUtils; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 29 | import android.text.TextWatcher; |
Wenyi Wang | 1d89622 | 2016-03-24 16:50:48 -0700 | [diff] [blame] | 30 | import android.text.style.TtsSpan; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 31 | import android.util.AttributeSet; |
Josh Gargus | 26918da | 2012-02-02 16:58:04 -0800 | [diff] [blame] | 32 | import android.util.Log; |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 33 | import android.util.TypedValue; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 34 | import android.view.View; |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 35 | import android.view.ViewGroup; |
Katherine Kuan | 0af0258 | 2011-12-05 17:11:57 -0800 | [diff] [blame] | 36 | import android.view.inputmethod.EditorInfo; |
Josh Gargus | 26918da | 2012-02-02 16:58:04 -0800 | [diff] [blame] | 37 | import android.view.inputmethod.InputMethodManager; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 38 | import android.widget.EditText; |
Katherine Kuan | 12a9363 | 2011-05-05 13:38:01 -0700 | [diff] [blame] | 39 | import android.widget.ImageView; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 40 | import android.widget.LinearLayout; |
Dave Santoro | da5bf1c | 2011-05-03 10:30:34 -0700 | [diff] [blame] | 41 | |
Chiao Cheng | e0b2f1e | 2012-06-12 13:07:56 -0700 | [diff] [blame] | 42 | import com.android.contacts.R; |
Yorke Lee | cd321f6 | 2013-10-28 15:20:15 -0700 | [diff] [blame] | 43 | import com.android.contacts.common.ContactsUtils; |
Gary Mai | 3e9637f | 2016-09-06 18:22:55 -0700 | [diff] [blame] | 44 | import com.android.contacts.common.compat.PhoneNumberUtilsCompat; |
| 45 | import com.android.contacts.common.model.RawContactDelta; |
Chiao Cheng | 738ff86 | 2012-11-30 12:06:03 -0800 | [diff] [blame] | 46 | import com.android.contacts.common.model.ValuesDelta; |
Chiao Cheng | 428f008 | 2012-11-13 18:38:56 -0800 | [diff] [blame] | 47 | import com.android.contacts.common.model.account.AccountType.EditField; |
| 48 | import com.android.contacts.common.model.dataitem.DataKind; |
Chiao Cheng | 720ac2f | 2012-10-30 09:44:17 -0700 | [diff] [blame] | 49 | import com.android.contacts.common.util.PhoneNumberFormatter; |
Chiao Cheng | e0b2f1e | 2012-06-12 13:07:56 -0700 | [diff] [blame] | 50 | |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 51 | /** |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 52 | * Simple editor that handles labels and any {@link EditField} defined for the |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 53 | * entry. Uses {@link ValuesDelta} to read any existing {@link RawContact} values, |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 54 | * and to correctly write any changes values. |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 55 | */ |
| 56 | public class TextFieldsEditorView extends LabeledEditorView { |
Josh Gargus | 26918da | 2012-02-02 16:58:04 -0800 | [diff] [blame] | 57 | private static final String TAG = TextFieldsEditorView.class.getSimpleName(); |
| 58 | |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 59 | private EditText[] mFieldEditTexts = null; |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 60 | private ViewGroup mFields = null; |
Gary Mai | 1c6298b | 2016-09-09 14:34:52 -0700 | [diff] [blame] | 61 | protected View mExpansionViewContainer; |
| 62 | protected ImageView mExpansionView; |
| 63 | protected String mCollapseButtonDescription; |
| 64 | protected String mExpandButtonDescription; |
| 65 | protected String mCollapsedAnnouncement; |
| 66 | protected String mExpandedAnnouncement; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 67 | private boolean mHideOptional = true; |
| 68 | private boolean mHasShortAndLongForms; |
Katherine Kuan | 1ebbd5b | 2011-08-05 14:39:34 -0700 | [diff] [blame] | 69 | private int mMinFieldHeight; |
Yorke Lee | ba48d21 | 2012-12-26 13:25:48 -0800 | [diff] [blame] | 70 | private int mPreviousViewHeight; |
Brian Attwell | d690dff | 2014-12-02 15:04:56 -0800 | [diff] [blame] | 71 | private int mHintTextColorUnfocused; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 72 | |
| 73 | public TextFieldsEditorView(Context context) { |
| 74 | super(context); |
| 75 | } |
| 76 | |
| 77 | public TextFieldsEditorView(Context context, AttributeSet attrs) { |
| 78 | super(context, attrs); |
| 79 | } |
| 80 | |
| 81 | public TextFieldsEditorView(Context context, AttributeSet attrs, int defStyle) { |
| 82 | super(context, attrs, defStyle); |
| 83 | } |
| 84 | |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 85 | /** {@inheritDoc} */ |
| 86 | @Override |
| 87 | protected void onFinishInflate() { |
| 88 | super.onFinishInflate(); |
| 89 | |
| 90 | setDrawingCacheEnabled(true); |
| 91 | setAlwaysDrawnWithCacheEnabled(true); |
| 92 | |
Brian Attwell | f140227 | 2014-12-16 16:00:08 -0800 | [diff] [blame] | 93 | mMinFieldHeight = getContext().getResources().getDimensionPixelSize( |
Katherine Kuan | 1ebbd5b | 2011-08-05 14:39:34 -0700 | [diff] [blame] | 94 | R.dimen.editor_min_line_item_height); |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 95 | mFields = (ViewGroup) findViewById(R.id.editors); |
Brian Attwell | d690dff | 2014-12-02 15:04:56 -0800 | [diff] [blame] | 96 | mHintTextColorUnfocused = getResources().getColor(R.color.editor_disabled_text_color); |
Katherine Kuan | 12a9363 | 2011-05-05 13:38:01 -0700 | [diff] [blame] | 97 | mExpansionView = (ImageView) findViewById(R.id.expansion_view); |
Gary Mai | 1c6298b | 2016-09-09 14:34:52 -0700 | [diff] [blame] | 98 | mCollapseButtonDescription = getResources() |
| 99 | .getString(R.string.collapse_fields_description); |
| 100 | mCollapsedAnnouncement = getResources() |
| 101 | .getString(R.string.announce_collapsed_fields); |
| 102 | mExpandButtonDescription = getResources() |
| 103 | .getString(R.string.expand_fields_description); |
| 104 | mExpandedAnnouncement = getResources() |
| 105 | .getString(R.string.announce_expanded_fields); |
| 106 | |
Katherine Kuan | 12a9363 | 2011-05-05 13:38:01 -0700 | [diff] [blame] | 107 | mExpansionViewContainer = findViewById(R.id.expansion_view_container); |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 108 | if (mExpansionViewContainer != null) { |
| 109 | mExpansionViewContainer.setOnClickListener(new OnClickListener() { |
| 110 | @Override |
| 111 | public void onClick(View v) { |
| 112 | mPreviousViewHeight = mFields.getHeight(); |
Yorke Lee | ba48d21 | 2012-12-26 13:25:48 -0800 | [diff] [blame] | 113 | |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 114 | // Save focus |
Gary Mai | 698cee7 | 2016-09-19 16:09:54 -0700 | [diff] [blame] | 115 | final View focusedChild = findFocus(); |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 116 | final int focusedViewId = focusedChild == null ? -1 : focusedChild.getId(); |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 117 | |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 118 | // Reconfigure GUI |
| 119 | mHideOptional = !mHideOptional; |
| 120 | onOptionalFieldVisibilityChange(); |
| 121 | rebuildValues(); |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 122 | |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 123 | // Restore focus |
| 124 | View newFocusView = findViewById(focusedViewId); |
| 125 | if (newFocusView == null || newFocusView.getVisibility() == GONE) { |
| 126 | // find first visible child |
| 127 | newFocusView = TextFieldsEditorView.this; |
| 128 | } |
| 129 | newFocusView.requestFocus(); |
| 130 | |
| 131 | EditorAnimator.getInstance().slideAndFadeIn(mFields, mPreviousViewHeight); |
Gary Mai | 1c6298b | 2016-09-09 14:34:52 -0700 | [diff] [blame] | 132 | announceForAccessibility(mHideOptional ? |
| 133 | mCollapsedAnnouncement : mExpandedAnnouncement); |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 134 | } |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 135 | }); |
| 136 | } |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 137 | } |
| 138 | |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 139 | @Override |
Josh Gargus | 26918da | 2012-02-02 16:58:04 -0800 | [diff] [blame] | 140 | public void editNewlyAddedField() { |
| 141 | // Some editors may have multiple fields (eg: first-name/last-name), but since the user |
| 142 | // has not selected a particular one, it is reasonable to simply pick the first. |
| 143 | final View editor = mFields.getChildAt(0); |
| 144 | |
| 145 | // Show the soft-keyboard. |
Wenyi Wang | a07c90b | 2016-03-07 09:56:08 -0800 | [diff] [blame] | 146 | InputMethodManager imm = |
| 147 | (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE); |
| 148 | if (imm != null) { |
| 149 | if (!imm.showSoftInput(editor, InputMethodManager.SHOW_IMPLICIT)) { |
| 150 | Log.w(TAG, "Failed to show soft input method."); |
| 151 | } |
| 152 | } |
Josh Gargus | 26918da | 2012-02-02 16:58:04 -0800 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | @Override |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 156 | public void setEnabled(boolean enabled) { |
| 157 | super.setEnabled(enabled); |
| 158 | |
| 159 | if (mFieldEditTexts != null) { |
| 160 | for (int index = 0; index < mFieldEditTexts.length; index++) { |
Dmitri Plotnikov | 02bb125 | 2010-12-06 09:39:05 -0800 | [diff] [blame] | 161 | mFieldEditTexts[index].setEnabled(!isReadOnly() && enabled); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 162 | } |
| 163 | } |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 164 | if (mExpansionView != null) { |
| 165 | mExpansionView.setEnabled(!isReadOnly() && enabled); |
| 166 | } |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 167 | } |
| 168 | |
Brian Attwell | d690dff | 2014-12-02 15:04:56 -0800 | [diff] [blame] | 169 | private OnFocusChangeListener mTextFocusChangeListener = new OnFocusChangeListener() { |
| 170 | @Override |
| 171 | public void onFocusChange(View v, boolean hasFocus) { |
Brian Attwell | d690dff | 2014-12-02 15:04:56 -0800 | [diff] [blame] | 172 | if (getEditorListener() != null) { |
| 173 | getEditorListener().onRequest(EditorListener.EDITOR_FOCUS_CHANGED); |
| 174 | } |
| 175 | // Rebuild the label spinner using the new colors. |
| 176 | rebuildLabel(); |
| 177 | } |
| 178 | }; |
| 179 | |
| 180 | /** |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 181 | * Creates or removes the type/label button. Doesn't do anything if already correctly configured |
| 182 | */ |
Katherine Kuan | 12a9363 | 2011-05-05 13:38:01 -0700 | [diff] [blame] | 183 | private void setupExpansionView(boolean shouldExist, boolean collapsed) { |
Gary Mai | 3e9637f | 2016-09-06 18:22:55 -0700 | [diff] [blame] | 184 | final Drawable expandIcon = getContext().getDrawable(collapsed |
| 185 | ? R.drawable.ic_menu_expand_minimized_24dp |
| 186 | : R.drawable.ic_menu_expand_maximized_24dp); |
| 187 | mExpansionView.setImageDrawable(expandIcon); |
Gary Mai | 1c6298b | 2016-09-09 14:34:52 -0700 | [diff] [blame] | 188 | mExpansionView.setContentDescription(collapsed ? mExpandButtonDescription |
| 189 | : mCollapseButtonDescription); |
Brian Attwell | 93f22ec | 2015-03-04 14:21:15 -0800 | [diff] [blame] | 190 | mExpansionViewContainer.setVisibility(shouldExist ? View.VISIBLE : View.INVISIBLE); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 191 | } |
| 192 | |
| 193 | @Override |
| 194 | protected void requestFocusForFirstEditField() { |
| 195 | if (mFieldEditTexts != null && mFieldEditTexts.length != 0) { |
| 196 | EditText firstField = null; |
| 197 | boolean anyFieldHasFocus = false; |
| 198 | for (EditText editText : mFieldEditTexts) { |
| 199 | if (firstField == null && editText.getVisibility() == View.VISIBLE) { |
| 200 | firstField = editText; |
| 201 | } |
| 202 | if (editText.hasFocus()) { |
| 203 | anyFieldHasFocus = true; |
| 204 | break; |
| 205 | } |
| 206 | } |
| 207 | if (!anyFieldHasFocus && firstField != null) { |
| 208 | firstField.requestFocus(); |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | |
Chiao Cheng | 44cfc56 | 2012-09-13 13:06:23 -0700 | [diff] [blame] | 213 | public void setValue(int field, String value) { |
| 214 | mFieldEditTexts[field].setText(value); |
| 215 | } |
| 216 | |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 217 | @Override |
Maurice Chu | 851222a | 2012-06-21 11:43:08 -0700 | [diff] [blame] | 218 | public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly, |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 219 | ViewIdGenerator vig) { |
| 220 | super.setValues(kind, entry, state, readOnly, vig); |
| 221 | // Remove edit texts that we currently have |
| 222 | if (mFieldEditTexts != null) { |
| 223 | for (EditText fieldEditText : mFieldEditTexts) { |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 224 | mFields.removeView(fieldEditText); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 225 | } |
| 226 | } |
| 227 | boolean hidePossible = false; |
| 228 | |
Walter Jang | f5dfea4 | 2015-09-16 12:30:36 -0700 | [diff] [blame] | 229 | int fieldCount = kind.fieldList == null ? 0 : kind.fieldList.size(); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 230 | mFieldEditTexts = new EditText[fieldCount]; |
| 231 | for (int index = 0; index < fieldCount; index++) { |
| 232 | final EditField field = kind.fieldList.get(index); |
Brian Attwell | f140227 | 2014-12-16 16:00:08 -0800 | [diff] [blame] | 233 | final EditText fieldView = new EditText(getContext()); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 234 | fieldView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, |
Brian Attwell | 5cc21eb | 2014-06-03 21:08:01 -0700 | [diff] [blame] | 235 | LayoutParams.WRAP_CONTENT)); |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 236 | fieldView.setTextSize(TypedValue.COMPLEX_UNIT_PX, |
| 237 | getResources().getDimension(R.dimen.editor_form_text_size)); |
Brian Attwell | d690dff | 2014-12-02 15:04:56 -0800 | [diff] [blame] | 238 | fieldView.setHintTextColor(mHintTextColorUnfocused); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 239 | mFieldEditTexts[index] = fieldView; |
| 240 | fieldView.setId(vig.getId(state, kind, entry, index)); |
| 241 | if (field.titleRes > 0) { |
| 242 | fieldView.setHint(field.titleRes); |
| 243 | } |
| 244 | int inputType = field.inputType; |
| 245 | fieldView.setInputType(inputType); |
| 246 | if (inputType == InputType.TYPE_CLASS_PHONE) { |
guanxiongliu | 3d59049 | 2016-02-01 16:32:28 -0800 | [diff] [blame] | 247 | PhoneNumberFormatter.setPhoneNumberFormattingTextWatcher( |
Gary Mai | c03cfc0 | 2016-09-07 15:50:55 -0700 | [diff] [blame] | 248 | getContext(), fieldView, |
| 249 | /* formatAfterWatcherSet =*/ state.isContactInsert()); |
Yorke Lee | cbfb112 | 2013-05-03 17:41:07 -0700 | [diff] [blame] | 250 | fieldView.setTextDirection(View.TEXT_DIRECTION_LTR); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 251 | } |
Tingting Wang | 9f153a0 | 2015-11-05 18:11:04 -0800 | [diff] [blame] | 252 | fieldView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 253 | |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 254 | // Set either a minimum line requirement or a minimum height (because {@link TextView} |
| 255 | // only takes one or the other at a single time). |
| 256 | if (field.minLines > 1) { |
| 257 | fieldView.setMinLines(field.minLines); |
| 258 | } else { |
| 259 | // This needs to be called after setInputType. Otherwise, calling setInputType |
| 260 | // will unset this value. |
| 261 | fieldView.setMinHeight(mMinFieldHeight); |
| 262 | } |
| 263 | |
Katherine Kuan | 0af0258 | 2011-12-05 17:11:57 -0800 | [diff] [blame] | 264 | // Show the "next" button in IME to navigate between text fields |
| 265 | // TODO: Still need to properly navigate to/from sections without text fields, |
| 266 | // See Bug: 5713510 |
Gary Mai | 6eb8e0d | 2016-07-20 15:24:00 -0700 | [diff] [blame] | 267 | fieldView.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_FULLSCREEN); |
Katherine Kuan | 0af0258 | 2011-12-05 17:11:57 -0800 | [diff] [blame] | 268 | |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 269 | // Read current value from state |
| 270 | final String column = field.column; |
| 271 | final String value = entry.getAsString(column); |
Tingting Wang | b6949dc | 2015-11-03 13:17:12 -0800 | [diff] [blame] | 272 | if (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(kind.mimeType)) { |
Wenyi Wang | fcc7dc9 | 2015-11-19 09:54:22 -0800 | [diff] [blame] | 273 | fieldView.setText(PhoneNumberUtilsCompat.createTtsSpannable(value)); |
Tingting Wang | b6949dc | 2015-11-03 13:17:12 -0800 | [diff] [blame] | 274 | } else { |
| 275 | fieldView.setText(value); |
| 276 | } |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 277 | |
Wenyi Wang | 83e7e63 | 2015-11-12 19:39:29 -0800 | [diff] [blame] | 278 | // Show the delete button if we have a non-empty value |
| 279 | setDeleteButtonVisible(!TextUtils.isEmpty(value)); |
Katherine Kuan | 5e330ed | 2011-07-15 15:06:06 -0700 | [diff] [blame] | 280 | |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 281 | // Prepare listener for writing changes |
| 282 | fieldView.addTextChangedListener(new TextWatcher() { |
| 283 | @Override |
| 284 | public void afterTextChanged(Editable s) { |
| 285 | // Trigger event for newly changed value |
| 286 | onFieldChanged(column, s.toString()); |
| 287 | } |
| 288 | |
| 289 | @Override |
| 290 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { |
| 291 | } |
| 292 | |
| 293 | @Override |
| 294 | public void onTextChanged(CharSequence s, int start, int before, int count) { |
Wenyi Wang | 1d89622 | 2016-03-24 16:50:48 -0700 | [diff] [blame] | 295 | if (!ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals( |
| 296 | getKind().mimeType) || !(s instanceof Spannable)) { |
| 297 | return; |
| 298 | } |
| 299 | final Spannable spannable = (Spannable) s; |
| 300 | final TtsSpan[] spans = spannable.getSpans(0, s.length(), TtsSpan.class); |
| 301 | for (int i = 0; i < spans.length; i++) { |
| 302 | spannable.removeSpan(spans[i]); |
| 303 | } |
| 304 | PhoneNumberUtilsCompat.addTtsSpan(spannable, 0, s.length()); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 305 | } |
| 306 | }); |
| 307 | |
Dmitri Plotnikov | 02bb125 | 2010-12-06 09:39:05 -0800 | [diff] [blame] | 308 | fieldView.setEnabled(isEnabled() && !readOnly); |
Brian Attwell | d690dff | 2014-12-02 15:04:56 -0800 | [diff] [blame] | 309 | fieldView.setOnFocusChangeListener(mTextFocusChangeListener); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 310 | |
| 311 | if (field.shortForm) { |
| 312 | hidePossible = true; |
| 313 | mHasShortAndLongForms = true; |
| 314 | fieldView.setVisibility(mHideOptional ? View.VISIBLE : View.GONE); |
| 315 | } else if (field.longForm) { |
| 316 | hidePossible = true; |
| 317 | mHasShortAndLongForms = true; |
| 318 | fieldView.setVisibility(mHideOptional ? View.GONE : View.VISIBLE); |
| 319 | } else { |
| 320 | // Hide field when empty and optional value |
| 321 | final boolean couldHide = (!ContactsUtils.isGraphic(value) && field.optional); |
| 322 | final boolean willHide = (mHideOptional && couldHide); |
| 323 | fieldView.setVisibility(willHide ? View.GONE : View.VISIBLE); |
| 324 | hidePossible = hidePossible || couldHide; |
| 325 | } |
| 326 | |
Katherine Kuan | 63ffb90 | 2011-04-26 19:53:40 -0700 | [diff] [blame] | 327 | mFields.addView(fieldView); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 328 | } |
| 329 | |
Brian Attwell | 043fba6 | 2014-10-30 11:11:56 -0700 | [diff] [blame] | 330 | if (mExpansionView != null) { |
| 331 | // When hiding fields, place expandable |
| 332 | setupExpansionView(hidePossible, mHideOptional); |
| 333 | mExpansionView.setEnabled(!readOnly && isEnabled()); |
| 334 | } |
Brian Attwell | 8f9d84f | 2014-11-03 23:17:04 -0800 | [diff] [blame] | 335 | updateEmptiness(); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 336 | } |
| 337 | |
Katherine Kuan | 2591436 | 2011-04-29 19:42:01 -0700 | [diff] [blame] | 338 | @Override |
| 339 | public boolean isEmpty() { |
Katherine Kuan | 1b22073 | 2011-04-28 18:45:39 -0700 | [diff] [blame] | 340 | for (int i = 0; i < mFields.getChildCount(); i++) { |
| 341 | EditText editText = (EditText) mFields.getChildAt(i); |
Katherine Kuan | 2591436 | 2011-04-29 19:42:01 -0700 | [diff] [blame] | 342 | if (!TextUtils.isEmpty(editText.getText())) { |
| 343 | return false; |
Katherine Kuan | 1b22073 | 2011-04-28 18:45:39 -0700 | [diff] [blame] | 344 | } |
| 345 | } |
Katherine Kuan | 2591436 | 2011-04-29 19:42:01 -0700 | [diff] [blame] | 346 | return true; |
Katherine Kuan | 1b22073 | 2011-04-28 18:45:39 -0700 | [diff] [blame] | 347 | } |
| 348 | |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 349 | /** |
| 350 | * Returns true if the editor is currently configured to show optional fields. |
| 351 | */ |
| 352 | public boolean areOptionalFieldsVisible() { |
| 353 | return !mHideOptional; |
| 354 | } |
| 355 | |
| 356 | public boolean hasShortAndLongForms() { |
| 357 | return mHasShortAndLongForms; |
| 358 | } |
| 359 | |
| 360 | /** |
| 361 | * Populates the bound rectangle with the bounds of the last editor field inside this view. |
| 362 | */ |
| 363 | public void acquireEditorBounds(Rect bounds) { |
| 364 | if (mFieldEditTexts != null) { |
| 365 | for (int i = mFieldEditTexts.length; --i >= 0;) { |
| 366 | EditText editText = mFieldEditTexts[i]; |
| 367 | if (editText.getVisibility() == View.VISIBLE) { |
| 368 | bounds.set(editText.getLeft(), editText.getTop(), editText.getRight(), |
| 369 | editText.getBottom()); |
| 370 | return; |
| 371 | } |
| 372 | } |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | /** |
| 377 | * Saves the visibility of the child EditTexts, and mHideOptional. |
| 378 | */ |
| 379 | @Override |
| 380 | protected Parcelable onSaveInstanceState() { |
| 381 | Parcelable superState = super.onSaveInstanceState(); |
| 382 | SavedState ss = new SavedState(superState); |
| 383 | |
| 384 | ss.mHideOptional = mHideOptional; |
| 385 | |
Dmitri Plotnikov | 5ec40b0 | 2011-03-01 18:36:16 -0800 | [diff] [blame] | 386 | final int numChildren = mFieldEditTexts == null ? 0 : mFieldEditTexts.length; |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 387 | ss.mVisibilities = new int[numChildren]; |
| 388 | for (int i = 0; i < numChildren; i++) { |
| 389 | ss.mVisibilities[i] = mFieldEditTexts[i].getVisibility(); |
| 390 | } |
| 391 | |
| 392 | return ss; |
| 393 | } |
| 394 | |
| 395 | /** |
| 396 | * Restores the visibility of the child EditTexts, and mHideOptional. |
| 397 | */ |
| 398 | @Override |
| 399 | protected void onRestoreInstanceState(Parcelable state) { |
| 400 | SavedState ss = (SavedState) state; |
| 401 | super.onRestoreInstanceState(ss.getSuperState()); |
| 402 | |
| 403 | mHideOptional = ss.mHideOptional; |
| 404 | |
Jay Shrauner | 882128a | 2015-05-13 12:21:48 -0700 | [diff] [blame] | 405 | int numChildren = Math.min(mFieldEditTexts == null ? 0 : mFieldEditTexts.length, |
| 406 | ss.mVisibilities == null ? 0 : ss.mVisibilities.length); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 407 | for (int i = 0; i < numChildren; i++) { |
| 408 | mFieldEditTexts[i].setVisibility(ss.mVisibilities[i]); |
| 409 | } |
Gary Mai | 1c6298b | 2016-09-09 14:34:52 -0700 | [diff] [blame] | 410 | rebuildValues(); |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 411 | } |
| 412 | |
| 413 | private static class SavedState extends BaseSavedState { |
| 414 | public boolean mHideOptional; |
| 415 | public int[] mVisibilities; |
| 416 | |
| 417 | SavedState(Parcelable superState) { |
| 418 | super(superState); |
| 419 | } |
| 420 | |
| 421 | private SavedState(Parcel in) { |
| 422 | super(in); |
| 423 | mVisibilities = new int[in.readInt()]; |
| 424 | in.readIntArray(mVisibilities); |
| 425 | } |
| 426 | |
| 427 | @Override |
| 428 | public void writeToParcel(Parcel out, int flags) { |
| 429 | super.writeToParcel(out, flags); |
| 430 | out.writeInt(mVisibilities.length); |
| 431 | out.writeIntArray(mVisibilities); |
| 432 | } |
| 433 | |
Daniel Lehmann | cfb525b | 2010-11-02 19:24:54 -0700 | [diff] [blame] | 434 | @SuppressWarnings({"unused", "hiding" }) |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 435 | public static final Parcelable.Creator<SavedState> CREATOR |
| 436 | = new Parcelable.Creator<SavedState>() { |
| 437 | @Override |
| 438 | public SavedState createFromParcel(Parcel in) { |
| 439 | return new SavedState(in); |
| 440 | } |
| 441 | |
| 442 | @Override |
| 443 | public SavedState[] newArray(int size) { |
| 444 | return new SavedState[size]; |
| 445 | } |
| 446 | }; |
| 447 | } |
Dave Santoro | da5bf1c | 2011-05-03 10:30:34 -0700 | [diff] [blame] | 448 | |
Katherine Kuan | 2293e55 | 2011-07-21 20:25:44 -0700 | [diff] [blame] | 449 | @Override |
| 450 | public void clearAllFields() { |
| 451 | if (mFieldEditTexts != null) { |
| 452 | for (EditText fieldEditText : mFieldEditTexts) { |
| 453 | // Update UI (which will trigger a state change through the {@link TextWatcher}) |
| 454 | fieldEditText.setText(""); |
| 455 | } |
| 456 | } |
| 457 | } |
Daniel Lehmann | 392ccec | 2010-11-01 20:50:03 -0700 | [diff] [blame] | 458 | } |