blob: 02eae11f146fe1425c87f32f608aaccd9365a7db [file] [log] [blame]
Walter Jangf5dfea42015-09-16 12:30:36 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.contacts.editor;
18
19import android.content.Context;
Walter Jangf10ca152015-09-22 15:23:55 -070020import android.database.Cursor;
Walter Jang4f5594a2015-10-06 18:40:31 -070021import android.provider.ContactsContract.CommonDataKinds.Event;
Walter Jangf10ca152015-09-22 15:23:55 -070022import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
Walter Jang4f5594a2015-10-06 18:40:31 -070023import android.provider.ContactsContract.CommonDataKinds.Nickname;
Walter Jang3e5ae0d2015-09-20 12:43:37 -070024import android.provider.ContactsContract.CommonDataKinds.StructuredName;
Walter Jangf5dfea42015-09-16 12:30:36 -070025import android.util.AttributeSet;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.widget.ImageView;
30import android.widget.LinearLayout;
Walter Jang1ee24ed2015-09-25 17:49:14 -070031import android.widget.TextView;
Walter Jangf5dfea42015-09-16 12:30:36 -070032
Gary Mai98868d32016-09-14 11:55:04 -070033import com.android.contacts.R;
Gary Mai69c182a2016-12-05 13:07:03 -080034import com.android.contacts.model.RawContactDelta;
35import com.android.contacts.model.RawContactModifier;
36import com.android.contacts.model.ValuesDelta;
37import com.android.contacts.model.account.AccountType;
38import com.android.contacts.model.dataitem.DataKind;
Gary Mai98868d32016-09-14 11:55:04 -070039
Walter Jangf5dfea42015-09-16 12:30:36 -070040import java.util.ArrayList;
41import java.util.List;
42
43/**
Gary Mai65971d02016-09-15 15:00:16 -070044 * Custom view for an entire section of data as segmented by
45 * {@link DataKind} around a {@link Data#MIMETYPE}. This view shows a
46 * section header and a trigger for adding new {@link Data} rows.
Walter Jangf5dfea42015-09-16 12:30:36 -070047 */
Gary Mai363af602016-09-28 10:01:23 -070048public class KindSectionView extends LinearLayout {
Walter Jangf5dfea42015-09-16 12:30:36 -070049
Walter Jang3e5ae0d2015-09-20 12:43:37 -070050 /**
51 * Marks a name as super primary when it is changed.
52 *
53 * This is for the case when two or more raw contacts with names are joined where neither is
Walter Jang79658e12015-09-24 10:36:26 -070054 * marked as super primary.
Walter Jang3e5ae0d2015-09-20 12:43:37 -070055 */
Walter Jang79658e12015-09-24 10:36:26 -070056 private static final class StructuredNameEditorListener implements Editor.EditorListener {
Walter Jang3e5ae0d2015-09-20 12:43:37 -070057
58 private final ValuesDelta mValuesDelta;
59 private final long mRawContactId;
Gary Mai363af602016-09-28 10:01:23 -070060 private final RawContactEditorView.Listener mListener;
Walter Jang3e5ae0d2015-09-20 12:43:37 -070061
Walter Jang79658e12015-09-24 10:36:26 -070062 public StructuredNameEditorListener(ValuesDelta valuesDelta, long rawContactId,
Gary Mai363af602016-09-28 10:01:23 -070063 RawContactEditorView.Listener listener) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -070064 mValuesDelta = valuesDelta;
65 mRawContactId = rawContactId;
66 mListener = listener;
67 }
68
69 @Override
70 public void onRequest(int request) {
71 if (request == Editor.EditorListener.FIELD_CHANGED) {
72 mValuesDelta.setSuperPrimary(true);
73 if (mListener != null) {
74 mListener.onNameFieldChanged(mRawContactId, mValuesDelta);
75 }
76 } else if (request == Editor.EditorListener.FIELD_TURNED_EMPTY) {
77 mValuesDelta.setSuperPrimary(false);
78 }
79 }
80
81 @Override
82 public void onDeleteRequested(Editor editor) {
Walter Jang192a01c2015-09-22 15:23:55 -070083 editor.clearAllFields();
Walter Jang3e5ae0d2015-09-20 12:43:37 -070084 }
85 }
86
Walter Jang79658e12015-09-24 10:36:26 -070087 /**
88 * Clears fields when deletes are requested (on phonetic and nickename fields);
89 * does not change the number of editors.
90 */
91 private static final class OtherNameKindEditorListener implements Editor.EditorListener {
Walter Jangf5dfea42015-09-16 12:30:36 -070092
Walter Jang192a01c2015-09-22 15:23:55 -070093 @Override
94 public void onRequest(int request) {
95 }
96
97 @Override
98 public void onDeleteRequested(Editor editor) {
99 editor.clearAllFields();
100 }
101 }
102
Walter Jang79658e12015-09-24 10:36:26 -0700103 /**
104 * Updates empty fields when fields are deleted or turns empty.
105 * Whether a new empty editor is added is controlled by {@link #setShowOneEmptyEditor} and
106 * {@link #setHideWhenEmpty}.
107 */
Wenyi Wang2da5d2f2015-09-29 22:15:38 -0700108 private class NonNameEditorListener implements Editor.EditorListener {
Walter Jang79658e12015-09-24 10:36:26 -0700109
110 @Override
111 public void onRequest(int request) {
112 // If a field has become empty or non-empty, then check if another row
113 // can be added dynamically.
114 if (request == FIELD_TURNED_EMPTY || request == FIELD_TURNED_NON_EMPTY) {
115 updateEmptyEditors(/* shouldAnimate = */ true);
116 }
117 }
118
119 @Override
120 public void onDeleteRequested(Editor editor) {
121 if (mShowOneEmptyEditor && mEditors.getChildCount() == 1) {
122 // If there is only 1 editor in the section, then don't allow the user to
123 // delete it. Just clear the fields in the editor.
124 editor.clearAllFields();
125 } else {
126 editor.deleteEditor();
127 }
128 }
129 }
130
Wenyi Wang2da5d2f2015-09-29 22:15:38 -0700131 private class EventEditorListener extends NonNameEditorListener {
132
133 @Override
134 public void onRequest(int request) {
135 super.onRequest(request);
136 }
137
138 @Override
139 public void onDeleteRequested(Editor editor) {
140 if (editor instanceof EventFieldEditorView){
141 final EventFieldEditorView delView = (EventFieldEditorView) editor;
142 if (delView.isBirthdayType() && mEditors.getChildCount() > 1) {
143 final EventFieldEditorView bottomView = (EventFieldEditorView) mEditors
144 .getChildAt(mEditors.getChildCount() - 1);
145 bottomView.restoreBirthday();
146 }
147 }
148 super.onDeleteRequested(editor);
149 }
150 }
151
Gary Mai98868d32016-09-14 11:55:04 -0700152 private KindSectionData mKindSectionData;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700153 private ViewIdGenerator mViewIdGenerator;
Gary Mai363af602016-09-28 10:01:23 -0700154 private RawContactEditorView.Listener mListener;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700155
Walter Jang45b86d52015-10-15 15:23:16 -0700156 private boolean mIsUserProfile;
Walter Jangf5dfea42015-09-16 12:30:36 -0700157 private boolean mShowOneEmptyEditor = false;
158 private boolean mHideIfEmpty = true;
159
Walter Jang79658e12015-09-24 10:36:26 -0700160 private LayoutInflater mLayoutInflater;
Walter Jang192a01c2015-09-22 15:23:55 -0700161 private ViewGroup mEditors;
162 private ImageView mIcon;
Walter Jangf5dfea42015-09-16 12:30:36 -0700163
Gary Mai363af602016-09-28 10:01:23 -0700164 public KindSectionView(Context context) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700165 this(context, /* attrs =*/ null);
Walter Jangf5dfea42015-09-16 12:30:36 -0700166 }
167
Gary Mai363af602016-09-28 10:01:23 -0700168 public KindSectionView(Context context, AttributeSet attrs) {
Walter Jangf5dfea42015-09-16 12:30:36 -0700169 super(context, attrs);
170 }
171
172 @Override
173 public void setEnabled(boolean enabled) {
174 super.setEnabled(enabled);
175 if (mEditors != null) {
176 int childCount = mEditors.getChildCount();
177 for (int i = 0; i < childCount; i++) {
178 mEditors.getChildAt(i).setEnabled(enabled);
179 }
180 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700181 }
182
Walter Jangf5dfea42015-09-16 12:30:36 -0700183 @Override
184 protected void onFinishInflate() {
Gary Mai65971d02016-09-15 15:00:16 -0700185 super.onFinishInflate();
Walter Jangf5dfea42015-09-16 12:30:36 -0700186 setDrawingCacheEnabled(true);
187 setAlwaysDrawnWithCacheEnabled(true);
188
Walter Jang79658e12015-09-24 10:36:26 -0700189 mLayoutInflater = (LayoutInflater) getContext().getSystemService(
190 Context.LAYOUT_INFLATER_SERVICE);
Walter Jangf5dfea42015-09-16 12:30:36 -0700191
192 mEditors = (ViewGroup) findViewById(R.id.kind_editors);
193 mIcon = (ImageView) findViewById(R.id.kind_icon);
194 }
195
Walter Jang45b86d52015-10-15 15:23:16 -0700196 public void setIsUserProfile(boolean isUserProfile) {
197 mIsUserProfile = isUserProfile;
198 }
199
Walter Jangf5dfea42015-09-16 12:30:36 -0700200 /**
Walter Jang192a01c2015-09-22 15:23:55 -0700201 * @param showOneEmptyEditor If true, we will always show one empty editor, otherwise an empty
Walter Jang79658e12015-09-24 10:36:26 -0700202 * editor will not be shown until the user enters a value. Note, this does not apply
203 * to name editors since those are always displayed.
Walter Jangf5dfea42015-09-16 12:30:36 -0700204 */
205 public void setShowOneEmptyEditor(boolean showOneEmptyEditor) {
206 mShowOneEmptyEditor = showOneEmptyEditor;
207 }
208
209 /**
210 * @param hideWhenEmpty If true, the entire section will be hidden if all inputs are empty,
Walter Jang79658e12015-09-24 10:36:26 -0700211 * otherwise one empty input will always be displayed. Note, this does not apply
212 * to name editors since those are always displayed.
Walter Jangf5dfea42015-09-16 12:30:36 -0700213 */
214 public void setHideWhenEmpty(boolean hideWhenEmpty) {
215 mHideIfEmpty = hideWhenEmpty;
216 }
217
Walter Jang79658e12015-09-24 10:36:26 -0700218 /** Binds the given group data to every {@link GroupMembershipView}. */
Walter Jangf10ca152015-09-22 15:23:55 -0700219 public void setGroupMetaData(Cursor cursor) {
220 for (int i = 0; i < mEditors.getChildCount(); i++) {
221 final View view = mEditors.getChildAt(i);
222 if (view instanceof GroupMembershipView) {
223 ((GroupMembershipView) view).setGroupMetaData(cursor);
224 }
225 }
226 }
227
Walter Jang79658e12015-09-24 10:36:26 -0700228 /**
Walter Jang4f5594a2015-10-06 18:40:31 -0700229 * Whether this is a name kind section view and all name fields (structured, phonetic,
230 * and nicknames) are empty.
231 */
232 public boolean isEmptyName() {
Gary Mai98868d32016-09-14 11:55:04 -0700233 if (!StructuredName.CONTENT_ITEM_TYPE.equals(mKindSectionData.getMimeType())) {
Walter Jang4f5594a2015-10-06 18:40:31 -0700234 return false;
235 }
236 for (int i = 0; i < mEditors.getChildCount(); i++) {
237 final View view = mEditors.getChildAt(i);
238 if (view instanceof Editor) {
239 final Editor editor = (Editor) view;
240 if (!editor.isEmpty()) {
241 return false;
242 }
243 }
244 }
245 return true;
246 }
247
Gary Mai698cee72016-09-19 16:09:54 -0700248 public StructuredNameEditorView getNameEditorView() {
Gary Mai98868d32016-09-14 11:55:04 -0700249 if (!StructuredName.CONTENT_ITEM_TYPE.equals(mKindSectionData.getMimeType())
Walter Jang4f5594a2015-10-06 18:40:31 -0700250 || mEditors.getChildCount() == 0) {
251 return null;
252 }
253 return (StructuredNameEditorView) mEditors.getChildAt(0);
254 }
255
256 /**
Gary Mai98868d32016-09-14 11:55:04 -0700257 * Binds views for the given {@link KindSectionData}.
Walter Jang79658e12015-09-24 10:36:26 -0700258 *
259 * We create a structured name and phonetic name editor for each {@link DataKind} with a
Walter Jang4f5594a2015-10-06 18:40:31 -0700260 * {@link StructuredName#CONTENT_ITEM_TYPE} mime type. The number and order of editors are
Walter Jang79658e12015-09-24 10:36:26 -0700261 * rendered as they are given to {@link #setState}.
262 *
263 * Empty name editors are never added and at least one structured name editor is always
264 * displayed, even if it is empty.
265 */
Gary Mai98868d32016-09-14 11:55:04 -0700266 public void setState(KindSectionData kindSectionData,
Gary Mai363af602016-09-28 10:01:23 -0700267 ViewIdGenerator viewIdGenerator, RawContactEditorView.Listener listener) {
Gary Mai98868d32016-09-14 11:55:04 -0700268 mKindSectionData = kindSectionData;
Walter Jangf5dfea42015-09-16 12:30:36 -0700269 mViewIdGenerator = viewIdGenerator;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700270 mListener = listener;
Walter Jangf5dfea42015-09-16 12:30:36 -0700271
Gary Mai98868d32016-09-14 11:55:04 -0700272 // Set the icon using the DataKind
273 final DataKind dataKind = mKindSectionData.getDataKind();
Walter Jangf5dfea42015-09-16 12:30:36 -0700274 if (dataKind != null) {
Walter Jangf5dfea42015-09-16 12:30:36 -0700275 mIcon.setImageDrawable(EditorUiUtils.getMimeTypeDrawable(getContext(),
276 dataKind.mimeType));
Walter Jang79658e12015-09-24 10:36:26 -0700277 if (mIcon.getDrawable() != null) {
278 mIcon.setContentDescription(dataKind.titleRes == -1 || dataKind.titleRes == 0
279 ? "" : getResources().getString(dataKind.titleRes));
280 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700281 }
282
Gary Mai698cee72016-09-19 16:09:54 -0700283 rebuildFromState();
Walter Jang79658e12015-09-24 10:36:26 -0700284
Walter Jangf5dfea42015-09-16 12:30:36 -0700285 updateEmptyEditors(/* shouldAnimate = */ false);
286 }
287
Gary Mai698cee72016-09-19 16:09:54 -0700288 private void rebuildFromState() {
Walter Jangf5dfea42015-09-16 12:30:36 -0700289 mEditors.removeAllViews();
290
Gary Mai98868d32016-09-14 11:55:04 -0700291 final String mimeType = mKindSectionData.getMimeType();
292 if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
293 addNameEditorViews(mKindSectionData.getAccountType(),
Gary Mai698cee72016-09-19 16:09:54 -0700294 mKindSectionData.getRawContactDelta());
Gary Mai98868d32016-09-14 11:55:04 -0700295 } else if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
296 addGroupEditorView(mKindSectionData.getRawContactDelta(),
297 mKindSectionData.getDataKind());
298 } else {
299 final Editor.EditorListener editorListener;
300 if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
301 editorListener = new OtherNameKindEditorListener();
302 } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType)) {
303 editorListener = new EventEditorListener();
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700304 } else {
Gary Mai98868d32016-09-14 11:55:04 -0700305 editorListener = new NonNameEditorListener();
306 }
307 final List<ValuesDelta> valuesDeltas = mKindSectionData.getVisibleValuesDeltas();
308 for (int i = 0; i < valuesDeltas.size(); i++ ) {
309 addNonNameEditorView(mKindSectionData.getRawContactDelta(),
310 mKindSectionData.getDataKind(), valuesDeltas.get(i), editorListener);
Walter Jangf5dfea42015-09-16 12:30:36 -0700311 }
312 }
313 }
314
Gary Mai698cee72016-09-19 16:09:54 -0700315 private void addNameEditorViews(AccountType accountType, RawContactDelta rawContactDelta) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700316 final boolean readOnly = !accountType.areContactsWritable();
Gary Mai698cee72016-09-19 16:09:54 -0700317 final ValuesDelta nameValuesDelta = rawContactDelta
318 .getSuperPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
Walter Jang192a01c2015-09-22 15:23:55 -0700319
Walter Jang1ee24ed2015-09-25 17:49:14 -0700320 if (readOnly) {
Walter Jang82acd422015-10-17 14:01:27 -0700321 final View nameView = mLayoutInflater.inflate(
322 R.layout.structured_name_readonly_editor_view, mEditors,
323 /* attachToRoot =*/ false);
324
325 // Display name
326 ((TextView) nameView.findViewById(R.id.display_name))
Gary Mai698cee72016-09-19 16:09:54 -0700327 .setText(nameValuesDelta.getDisplayName());
Walter Jang82acd422015-10-17 14:01:27 -0700328
329 // Account type info
330 final LinearLayout accountTypeLayout = (LinearLayout)
331 nameView.findViewById(R.id.account_type);
332 accountTypeLayout.setVisibility(View.VISIBLE);
333 ((ImageView) accountTypeLayout.findViewById(R.id.account_type_icon))
334 .setImageDrawable(accountType.getDisplayIcon(getContext()));
335 ((TextView) accountTypeLayout.findViewById(R.id.account_type_name))
336 .setText(accountType.getDisplayLabel(getContext()));
337
338 mEditors.addView(nameView);
Walter Jang1ee24ed2015-09-25 17:49:14 -0700339 return;
340 }
341
Walter Jang192a01c2015-09-22 15:23:55 -0700342 // Structured name
Walter Jang79658e12015-09-24 10:36:26 -0700343 final StructuredNameEditorView nameView = (StructuredNameEditorView) mLayoutInflater
344 .inflate(R.layout.structured_name_editor_view, mEditors, /* attachToRoot =*/ false);
Walter Jang45b86d52015-10-15 15:23:16 -0700345 if (!mIsUserProfile) {
346 // Don't set super primary for the me contact
347 nameView.setEditorListener(new StructuredNameEditorListener(
Gary Mai698cee72016-09-19 16:09:54 -0700348 nameValuesDelta, rawContactDelta.getRawContactId(), mListener));
Walter Jang45b86d52015-10-15 15:23:16 -0700349 }
Walter Jang192a01c2015-09-22 15:23:55 -0700350 nameView.setDeletable(false);
351 nameView.setValues(
Gary Mai7a6daea2016-10-10 15:41:48 -0700352 accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_NAME),
Gary Mai698cee72016-09-19 16:09:54 -0700353 nameValuesDelta, rawContactDelta, /* readOnly =*/ false, mViewIdGenerator);
Walter Jang192a01c2015-09-22 15:23:55 -0700354
Walter Jang79658e12015-09-24 10:36:26 -0700355 // Correct start margin since there is a second icon in the structured name layout
Walter Jang192a01c2015-09-22 15:23:55 -0700356 nameView.findViewById(R.id.kind_icon).setVisibility(View.GONE);
357 mEditors.addView(nameView);
358
359 // Phonetic name
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700360 final DataKind phoneticNameKind = accountType
361 .getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME);
362 // The account type doesn't support phonetic name.
363 if (phoneticNameKind == null) return;
364
Walter Jang79658e12015-09-24 10:36:26 -0700365 final PhoneticNameEditorView phoneticNameView = (PhoneticNameEditorView) mLayoutInflater
366 .inflate(R.layout.phonetic_name_editor_view, mEditors, /* attachToRoot =*/ false);
367 phoneticNameView.setEditorListener(new OtherNameKindEditorListener());
Walter Jang192a01c2015-09-22 15:23:55 -0700368 phoneticNameView.setDeletable(false);
369 phoneticNameView.setValues(
370 accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME),
Gary Mai698cee72016-09-19 16:09:54 -0700371 nameValuesDelta, rawContactDelta, /* readOnly =*/ false, mViewIdGenerator);
Walter Jang192a01c2015-09-22 15:23:55 -0700372
373 // Fix the start margin for phonetic name views
374 final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
375 LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
376 layoutParams.setMargins(0, 0, 0, 0);
377 phoneticNameView.setLayoutParams(layoutParams);
378 mEditors.addView(phoneticNameView);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700379 }
380
Walter Jang79658e12015-09-24 10:36:26 -0700381 private void addGroupEditorView(RawContactDelta rawContactDelta, DataKind dataKind) {
382 final GroupMembershipView view = (GroupMembershipView) mLayoutInflater.inflate(
Walter Jangf10ca152015-09-22 15:23:55 -0700383 R.layout.item_group_membership, mEditors, /* attachToRoot =*/ false);
384 view.setKind(dataKind);
385 view.setEnabled(isEnabled());
386 view.setState(rawContactDelta);
387
Walter Jang79658e12015-09-24 10:36:26 -0700388 // Correct start margin since there is a second icon in the group layout
Walter Jangf10ca152015-09-22 15:23:55 -0700389 view.findViewById(R.id.kind_icon).setVisibility(View.GONE);
390
391 mEditors.addView(view);
392 }
393
Walter Jang79658e12015-09-24 10:36:26 -0700394 private View addNonNameEditorView(RawContactDelta rawContactDelta, DataKind dataKind,
395 ValuesDelta valuesDelta, Editor.EditorListener editorListener) {
Walter Jangf5dfea42015-09-16 12:30:36 -0700396 // Inflate the layout
Walter Jang79658e12015-09-24 10:36:26 -0700397 final View view = mLayoutInflater.inflate(
398 EditorUiUtils.getLayoutResourceId(dataKind.mimeType), mEditors, false);
399 view.setEnabled(isEnabled());
Walter Jangf5dfea42015-09-16 12:30:36 -0700400 if (view instanceof Editor) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700401 final Editor editor = (Editor) view;
Walter Jangf5dfea42015-09-16 12:30:36 -0700402 editor.setDeletable(true);
Walter Jang79658e12015-09-24 10:36:26 -0700403 editor.setEditorListener(editorListener);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700404 editor.setValues(dataKind, valuesDelta, rawContactDelta, !dataKind.editable,
405 mViewIdGenerator);
Walter Jangf5dfea42015-09-16 12:30:36 -0700406 }
407 mEditors.addView(view);
Walter Jang79658e12015-09-24 10:36:26 -0700408
Walter Jangf5dfea42015-09-16 12:30:36 -0700409 return view;
410 }
411
412 /**
Walter Jangf5dfea42015-09-16 12:30:36 -0700413 * Updates the editors being displayed to the user removing extra empty
414 * {@link Editor}s, so there is only max 1 empty {@link Editor} view at a time.
415 * If there is only 1 empty editor and {@link #setHideWhenEmpty} was set to true,
416 * then the entire section is hidden.
417 */
418 public void updateEmptyEditors(boolean shouldAnimate) {
Walter Jangcbd431d2015-10-06 13:07:30 -0700419 final boolean isNameKindSection = StructuredName.CONTENT_ITEM_TYPE.equals(
Gary Mai98868d32016-09-14 11:55:04 -0700420 mKindSectionData.getMimeType());
Walter Jang79658e12015-09-24 10:36:26 -0700421 final boolean isGroupKindSection = GroupMembership.CONTENT_ITEM_TYPE.equals(
Gary Mai98868d32016-09-14 11:55:04 -0700422 mKindSectionData.getMimeType());
Walter Jang79658e12015-09-24 10:36:26 -0700423
424 if (isNameKindSection) {
425 // The name kind section is always visible
426 setVisibility(VISIBLE);
Walter Jang192a01c2015-09-22 15:23:55 -0700427 updateEmptyNameEditors(shouldAnimate);
Walter Jang79658e12015-09-24 10:36:26 -0700428 } else if (isGroupKindSection) {
429 // Check whether metadata has been bound for all group views
430 for (int i = 0; i < mEditors.getChildCount(); i++) {
431 final View view = mEditors.getChildAt(i);
Tingting Wang6dc36b02015-11-15 21:36:22 -0800432 if (view instanceof GroupMembershipView) {
433 final GroupMembershipView groupView = (GroupMembershipView) view;
434 if (!groupView.wasGroupMetaDataBound() || !groupView.accountHasGroups()) {
435 setVisibility(GONE);
436 return;
437 }
Walter Jang79658e12015-09-24 10:36:26 -0700438 }
439 }
440 // Check that the user has selected to display all fields
441 if (mHideIfEmpty) {
442 setVisibility(GONE);
443 return;
444 }
445 setVisibility(VISIBLE);
446
447 // We don't check the emptiness of the group views
Walter Jang192a01c2015-09-22 15:23:55 -0700448 } else {
Walter Jang79658e12015-09-24 10:36:26 -0700449 // Determine if the entire kind section should be visible
450 final int editorCount = mEditors.getChildCount();
451 final List<View> emptyEditors = getEmptyEditors();
452 if (editorCount == emptyEditors.size() && mHideIfEmpty) {
453 setVisibility(GONE);
454 return;
455 }
456 setVisibility(VISIBLE);
457
Walter Jang192a01c2015-09-22 15:23:55 -0700458 updateEmptyNonNameEditors(shouldAnimate);
459 }
460 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700461
Walter Jang192a01c2015-09-22 15:23:55 -0700462 private void updateEmptyNameEditors(boolean shouldAnimate) {
463 boolean isEmptyNameEditorVisible = false;
464
465 for (int i = 0; i < mEditors.getChildCount(); i++) {
466 final View view = mEditors.getChildAt(i);
Walter Jang4f5594a2015-10-06 18:40:31 -0700467 if (view instanceof Editor) {
468 final Editor editor = (Editor) view;
469 if (view instanceof StructuredNameEditorView) {
470 // We always show one empty structured name view
471 if (editor.isEmpty()) {
472 if (isEmptyNameEditorVisible) {
473 // If we're already showing an empty editor then hide any other empties
474 if (mHideIfEmpty) {
475 view.setVisibility(View.GONE);
476 }
477 } else {
478 isEmptyNameEditorVisible = true;
Walter Jang192a01c2015-09-22 15:23:55 -0700479 }
480 } else {
Walter Jang4f5594a2015-10-06 18:40:31 -0700481 showView(view, shouldAnimate);
Walter Jang192a01c2015-09-22 15:23:55 -0700482 isEmptyNameEditorVisible = true;
483 }
484 } else {
Walter Jang4f5594a2015-10-06 18:40:31 -0700485 // Since we can't add phonetic names and nicknames, just show or hide them
486 if (mHideIfEmpty && editor.isEmpty()) {
487 hideView(view);
488 } else {
489 showView(view, /* shouldAnimate =*/ false); // Animation here causes jank
490 }
Walter Jang192a01c2015-09-22 15:23:55 -0700491 }
492 } else {
Walter Jang4f5594a2015-10-06 18:40:31 -0700493 // For read only names, only show them if we're not hiding empty views
494 if (mHideIfEmpty) {
Walter Jang79658e12015-09-24 10:36:26 -0700495 hideView(view);
Walter Jang192a01c2015-09-22 15:23:55 -0700496 } else {
Walter Jang4f5594a2015-10-06 18:40:31 -0700497 showView(view, shouldAnimate);
Walter Jang192a01c2015-09-22 15:23:55 -0700498 }
499 }
500 }
501 }
502
503 private void updateEmptyNonNameEditors(boolean shouldAnimate) {
Walter Jang192a01c2015-09-22 15:23:55 -0700504 // Prune excess empty editors
Walter Jang79658e12015-09-24 10:36:26 -0700505 final List<View> emptyEditors = getEmptyEditors();
Walter Jangf5dfea42015-09-16 12:30:36 -0700506 if (emptyEditors.size() > 1) {
507 // If there is more than 1 empty editor, then remove it from the list of editors.
508 int deleted = 0;
Gary Mai98868d32016-09-14 11:55:04 -0700509 for (int i = 0; i < emptyEditors.size(); i++) {
510 final View view = emptyEditors.get(i);
Walter Jangf5dfea42015-09-16 12:30:36 -0700511 // If no child {@link View}s are being focused on within this {@link View}, then
Walter Jang192a01c2015-09-22 15:23:55 -0700512 // remove this empty editor. We can assume that at least one empty editor has
513 // focus. One way to get two empty editors is by deleting characters from a
514 // non-empty editor, in which case this editor has focus. Another way is if
515 // there is more values delta so we must also count number of editors deleted.
516 if (view.findFocus() == null) {
517 deleteView(view, shouldAnimate);
Walter Jangf5dfea42015-09-16 12:30:36 -0700518 deleted++;
Walter Jang192a01c2015-09-22 15:23:55 -0700519 if (deleted == emptyEditors.size() - 1) break;
Walter Jangf5dfea42015-09-16 12:30:36 -0700520 }
521 }
522 return;
523 }
Walter Jang192a01c2015-09-22 15:23:55 -0700524 // Determine if we should add a new empty editor
Gary Mai98868d32016-09-14 11:55:04 -0700525 final DataKind dataKind = mKindSectionData.getDataKind();
526 final RawContactDelta rawContactDelta = mKindSectionData.getRawContactDelta();
Walter Jang79658e12015-09-24 10:36:26 -0700527 if (dataKind == null // There is nothing we can do.
Walter Jangf5dfea42015-09-16 12:30:36 -0700528 // We have already reached the maximum number of editors, don't add any more.
Tingting Wang6d8c6292015-12-11 12:31:29 -0800529 || !RawContactModifier.canInsert(rawContactDelta, dataKind)
Walter Jangf5dfea42015-09-16 12:30:36 -0700530 // We have already reached the maximum number of empty editors, don't add any more.
531 || emptyEditors.size() == 1) {
532 return;
533 }
534 // Add a new empty editor
535 if (mShowOneEmptyEditor) {
Gary Mai98868d32016-09-14 11:55:04 -0700536 final String mimeType = mKindSectionData.getMimeType();
Tingting Wangf695eb32015-10-15 18:45:15 -0700537 if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType) && mEditors.getChildCount() > 0) {
538 return;
539 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700540 final ValuesDelta values = RawContactModifier.insertChild(rawContactDelta, dataKind);
Walter Jang4f5594a2015-10-06 18:40:31 -0700541 final Editor.EditorListener editorListener = Event.CONTENT_ITEM_TYPE.equals(mimeType)
542 ? new EventEditorListener() : new NonNameEditorListener();
Walter Jang79658e12015-09-24 10:36:26 -0700543 final View view = addNonNameEditorView(rawContactDelta, dataKind, values,
Wenyi Wang2da5d2f2015-09-29 22:15:38 -0700544 editorListener);
Walter Jang192a01c2015-09-22 15:23:55 -0700545 showView(view, shouldAnimate);
546 }
547 }
548
Walter Jang79658e12015-09-24 10:36:26 -0700549 private void hideView(View view) {
550 view.setVisibility(View.GONE);
Walter Jang192a01c2015-09-22 15:23:55 -0700551 }
552
553 private void deleteView(View view, boolean shouldAnimate) {
554 if (shouldAnimate) {
555 final Editor editor = (Editor) view;
556 editor.deleteEditor();
557 } else {
558 mEditors.removeView(view);
559 }
560 }
561
562 private void showView(View view, boolean shouldAnimate) {
563 if (shouldAnimate) {
564 view.setVisibility(View.GONE);
Walter Jang192a01c2015-09-22 15:23:55 -0700565 EditorAnimator.getInstance().showFieldFooter(view);
566 } else {
567 view.setVisibility(View.VISIBLE);
Walter Jangf5dfea42015-09-16 12:30:36 -0700568 }
569 }
570
Walter Jangf5dfea42015-09-16 12:30:36 -0700571 private List<View> getEmptyEditors() {
Walter Jang79658e12015-09-24 10:36:26 -0700572 final List<View> emptyEditors = new ArrayList<>();
Walter Jangf5dfea42015-09-16 12:30:36 -0700573 for (int i = 0; i < mEditors.getChildCount(); i++) {
Walter Jangf10ca152015-09-22 15:23:55 -0700574 final View view = mEditors.getChildAt(i);
575 if (view instanceof Editor && ((Editor) view).isEmpty()) {
Walter Jang79658e12015-09-24 10:36:26 -0700576 emptyEditors.add(view);
Walter Jangf5dfea42015-09-16 12:30:36 -0700577 }
578 }
Walter Jang79658e12015-09-24 10:36:26 -0700579 return emptyEditors;
Walter Jangf5dfea42015-09-16 12:30:36 -0700580 }
581}