blob: e71c8147c9330c6a55bd6b1b890d12b2a3c32c3f [file] [log] [blame]
Walter Jangcab3dce2015-02-09 17:48:03 -08001/*
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 com.android.contacts.R;
20import com.android.contacts.common.model.AccountTypeManager;
21import com.android.contacts.common.model.RawContactDelta;
22import com.android.contacts.common.model.RawContactDeltaList;
Walter Jange720fde2015-02-17 10:54:14 -080023import com.android.contacts.common.model.RawContactModifier;
Walter Jangcab3dce2015-02-09 17:48:03 -080024import com.android.contacts.common.model.ValuesDelta;
25import com.android.contacts.common.model.account.AccountType;
Walter Jang2d3f31c2015-06-18 23:15:31 -070026import com.android.contacts.common.model.account.AccountWithDataSet;
Walter Jangcab3dce2015-02-09 17:48:03 -080027import com.android.contacts.common.model.dataitem.DataKind;
Walter Jang708ea9e2015-09-10 15:42:05 -070028import com.android.contacts.common.util.AccountsListAdapter;
Walter Jangf46abd82015-02-20 16:52:04 -080029import com.android.contacts.common.util.MaterialColorMapUtils;
Walter Jang3efae4a2015-02-18 11:12:00 -080030import com.android.contacts.editor.CompactContactEditorFragment.PhotoHandler;
Walter Jang708ea9e2015-09-10 15:42:05 -070031import com.android.contacts.util.UiClosables;
Walter Jangcab3dce2015-02-09 17:48:03 -080032
33import android.content.Context;
Walter Jangf10ca152015-09-22 15:23:55 -070034import android.database.Cursor;
Walter Jang3efae4a2015-02-18 11:12:00 -080035import android.graphics.Bitmap;
Walter Jang41b3ea12015-03-09 17:30:06 -070036import android.net.Uri;
Walter Jang79658e12015-09-24 10:36:26 -070037import android.os.Parcel;
38import android.os.Parcelable;
Walter Jangcab3dce2015-02-09 17:48:03 -080039import android.provider.ContactsContract.CommonDataKinds.Email;
Walter Jangf5dfea42015-09-16 12:30:36 -070040import android.provider.ContactsContract.CommonDataKinds.Event;
Walter Jangcab3dce2015-02-09 17:48:03 -080041import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
Walter Jangf5dfea42015-09-16 12:30:36 -070042import android.provider.ContactsContract.CommonDataKinds.Im;
Walter Jang3efae4a2015-02-18 11:12:00 -080043import android.provider.ContactsContract.CommonDataKinds.Nickname;
Walter Jangf5dfea42015-09-16 12:30:36 -070044import android.provider.ContactsContract.CommonDataKinds.Note;
45import android.provider.ContactsContract.CommonDataKinds.Organization;
Walter Jangcab3dce2015-02-09 17:48:03 -080046import android.provider.ContactsContract.CommonDataKinds.Phone;
47import android.provider.ContactsContract.CommonDataKinds.Photo;
Walter Jangf5dfea42015-09-16 12:30:36 -070048import android.provider.ContactsContract.CommonDataKinds.Relation;
49import android.provider.ContactsContract.CommonDataKinds.SipAddress;
Walter Jangcab3dce2015-02-09 17:48:03 -080050import android.provider.ContactsContract.CommonDataKinds.StructuredName;
Walter Jangf5dfea42015-09-16 12:30:36 -070051import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
52import android.provider.ContactsContract.CommonDataKinds.Website;
Walter Jangcab3dce2015-02-09 17:48:03 -080053import android.text.TextUtils;
54import android.util.AttributeSet;
55import android.util.Log;
Walter Jang2d3f31c2015-06-18 23:15:31 -070056import android.util.Pair;
Walter Jangcab3dce2015-02-09 17:48:03 -080057import android.view.LayoutInflater;
Walter Jangb1c87622015-02-13 17:51:38 -080058import android.view.View;
Walter Jangcab3dce2015-02-09 17:48:03 -080059import android.view.ViewGroup;
Walter Jang708ea9e2015-09-10 15:42:05 -070060import android.widget.AdapterView;
Walter Jangcab3dce2015-02-09 17:48:03 -080061import android.widget.LinearLayout;
Walter Jang708ea9e2015-09-10 15:42:05 -070062import android.widget.ListPopupWindow;
Walter Jang2d3f31c2015-06-18 23:15:31 -070063import android.widget.TextView;
Walter Jangcab3dce2015-02-09 17:48:03 -080064
65import java.util.ArrayList;
Walter Jangf5dfea42015-09-16 12:30:36 -070066import java.util.Arrays;
Walter Jang192a01c2015-09-22 15:23:55 -070067import java.util.Collections;
Walter Jangf5dfea42015-09-16 12:30:36 -070068import java.util.Comparator;
Walter Jang19d985f2015-07-01 13:36:27 -070069import java.util.HashMap;
Walter Jangcab3dce2015-02-09 17:48:03 -080070import java.util.List;
Walter Jang19d985f2015-07-01 13:36:27 -070071import java.util.Map;
Walter Jang708ea9e2015-09-10 15:42:05 -070072import java.util.Objects;
Walter Jangf5dfea42015-09-16 12:30:36 -070073import java.util.TreeSet;
Walter Jangcab3dce2015-02-09 17:48:03 -080074
75/**
Walter Jangf5dfea42015-09-16 12:30:36 -070076 * View to display information from multiple {@link RawContactDelta}s grouped together.
Walter Jangcab3dce2015-02-09 17:48:03 -080077 */
Walter Jangb6ca2722015-02-20 11:10:25 -080078public class CompactRawContactsEditorView extends LinearLayout implements View.OnClickListener {
Walter Jangcab3dce2015-02-09 17:48:03 -080079
80 private static final String TAG = "CompactEditorView";
81
Walter Jang192a01c2015-09-22 15:23:55 -070082 private static final KindSectionDataMapEntryComparator
83 KIND_SECTION_DATA_MAP_ENTRY_COMPARATOR = new KindSectionDataMapEntryComparator();
Walter Jangf5dfea42015-09-16 12:30:36 -070084
Walter Jangb6ca2722015-02-20 11:10:25 -080085 /**
86 * Callbacks for hosts of {@link CompactRawContactsEditorView}s.
87 */
88 public interface Listener {
89
90 /**
Walter Jang151f3e62015-02-26 15:29:40 -080091 * Invoked when the structured name editor field has changed.
92 *
93 * @param rawContactId The raw contact ID from the underlying {@link RawContactDelta}.
94 * @param valuesDelta The values from the underlying {@link RawContactDelta}.
95 */
96 public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta);
Walter Jang708ea9e2015-09-10 15:42:05 -070097
98 /**
99 * Invoked when the compact editor should rebind editors for a new account.
100 *
101 * @param oldState Old data being edited.
102 * @param oldAccount Old account associated with oldState.
103 * @param newAccount New account to be used.
104 */
105 public void onRebindEditorsForNewContact(RawContactDelta oldState,
106 AccountWithDataSet oldAccount, AccountWithDataSet newAccount);
Walter Jang79658e12015-09-24 10:36:26 -0700107
108 /**
109 * Invoked when no editors could be bound for the contact.
110 */
111 public void onBindEditorsFailed();
Walter Jangd6753152015-10-02 09:23:13 -0700112
113 /**
114 * Invoked after editors have been bound for the contact.
115 */
116 public void onEditorsBound();
Walter Jang151f3e62015-02-26 15:29:40 -0800117 }
118
Walter Jang192a01c2015-09-22 15:23:55 -0700119 /** Used to sort entire kind sections. */
120 private static final class KindSectionDataMapEntryComparator implements
Walter Jangf5dfea42015-09-16 12:30:36 -0700121 Comparator<Map.Entry<String,List<KindSectionData>>> {
122
Walter Jang192a01c2015-09-22 15:23:55 -0700123 final MimeTypeComparator mMimeTypeComparator = new MimeTypeComparator();
124
125 @Override
126 public int compare(Map.Entry<String, List<KindSectionData>> entry1,
127 Map.Entry<String, List<KindSectionData>> entry2) {
128 if (entry1 == entry2) return 0;
129 if (entry1 == null) return -1;
130 if (entry2 == null) return 1;
131
132 final String mimeType1 = entry1.getKey();
133 final String mimeType2 = entry2.getKey();
134
135 return mMimeTypeComparator.compare(mimeType1, mimeType2);
136 }
137 }
138
139 /**
140 * Sorts kinds roughly the same as quick contacts; we diverge in the following ways:
141 * <ol>
142 * <li>All names are together at the top.</li>
143 * <li>IM is moved up after addresses</li>
144 * <li>SIP addresses are moved to below phone numbers</li>
Walter Jang79658e12015-09-24 10:36:26 -0700145 * <li>Group membership is placed at the end</li>
Walter Jang192a01c2015-09-22 15:23:55 -0700146 * </ol>
147 */
148 private static final class MimeTypeComparator implements Comparator<String> {
149
Walter Jangf5dfea42015-09-16 12:30:36 -0700150 private static final List<String> MIME_TYPE_ORDER = Arrays.asList(new String[] {
151 StructuredName.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700152 Nickname.CONTENT_ITEM_TYPE,
Walter Jang2ae21752015-09-25 11:25:38 -0700153 Organization.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700154 Phone.CONTENT_ITEM_TYPE,
155 SipAddress.CONTENT_ITEM_TYPE,
156 Email.CONTENT_ITEM_TYPE,
157 StructuredPostal.CONTENT_ITEM_TYPE,
158 Im.CONTENT_ITEM_TYPE,
159 Website.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700160 Event.CONTENT_ITEM_TYPE,
161 Relation.CONTENT_ITEM_TYPE,
Walter Jangf10ca152015-09-22 15:23:55 -0700162 Note.CONTENT_ITEM_TYPE,
163 GroupMembership.CONTENT_ITEM_TYPE
Walter Jangf5dfea42015-09-16 12:30:36 -0700164 });
165
166 @Override
Walter Jang192a01c2015-09-22 15:23:55 -0700167 public int compare(String mimeType1, String mimeType2) {
168 if (mimeType1 == mimeType2) return 0;
169 if (mimeType1 == null) return -1;
170 if (mimeType2 == null) return 1;
Walter Jangf5dfea42015-09-16 12:30:36 -0700171
172 int index1 = MIME_TYPE_ORDER.indexOf(mimeType1);
173 int index2 = MIME_TYPE_ORDER.indexOf(mimeType2);
174
175 // Fallback to alphabetical ordering of the mime type if both are not found
176 if (index1 < 0 && index2 < 0) return mimeType1.compareTo(mimeType2);
177 if (index1 < 0) return 1;
178 if (index2 < 0) return -1;
179
180 return index1 < index2 ? -1 : 1;
181 }
182 }
183
Walter Jang192a01c2015-09-22 15:23:55 -0700184 /**
185 * Sorts primary accounts and google account types before others.
186 */
187 private static final class EditorComparator implements Comparator<KindSectionData> {
188
189 private RawContactDeltaComparator mRawContactDeltaComparator;
190
191 private EditorComparator(Context context) {
192 mRawContactDeltaComparator = new RawContactDeltaComparator(context);
193 }
194
195 @Override
196 public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
197 if (kindSectionData1 == kindSectionData2) return 0;
198 if (kindSectionData1 == null) return -1;
199 if (kindSectionData2 == null) return 1;
200
201 final RawContactDelta rawContactDelta1 = kindSectionData1.getRawContactDelta();
202 final RawContactDelta rawContactDelta2 = kindSectionData2.getRawContactDelta();
203
204 if (rawContactDelta1 == rawContactDelta2) return 0;
205 if (rawContactDelta1 == null) return -1;
206 if (rawContactDelta2 == null) return 1;
207
208 return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
209 }
210 }
211
212 /**
213 * Sorts primary account names first, followed by google account types, and other account
214 * types last. For names from the same account we order structured names before nicknames,
215 * but still keep names from the same account together.
216 */
217 private static final class NameEditorComparator implements Comparator<KindSectionData> {
218
219 private RawContactDeltaComparator mRawContactDeltaComparator;
220 private MimeTypeComparator mMimeTypeComparator;
221 private RawContactDelta mPrimaryRawContactDelta;
222
223 private NameEditorComparator(Context context, RawContactDelta primaryRawContactDelta) {
224 mRawContactDeltaComparator = new RawContactDeltaComparator(context);
225 mMimeTypeComparator = new MimeTypeComparator();
226 mPrimaryRawContactDelta = primaryRawContactDelta;
227 }
228
229 @Override
230 public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
231 if (kindSectionData1 == kindSectionData2) return 0;
232 if (kindSectionData1 == null) return -1;
233 if (kindSectionData2 == null) return 1;
234
235 final RawContactDelta rawContactDelta1 = kindSectionData1.getRawContactDelta();
236 final RawContactDelta rawContactDelta2 = kindSectionData2.getRawContactDelta();
237
238 if (rawContactDelta1 == rawContactDelta2) return 0;
239 if (rawContactDelta1 == null) return -1;
240 if (rawContactDelta2 == null) return 1;
241
242 final boolean isRawContactDelta1Primary =
243 mPrimaryRawContactDelta.equals(rawContactDelta1);
244 final boolean isRawContactDelta2Primary =
245 mPrimaryRawContactDelta.equals(rawContactDelta2);
246
247 // If both names are from the primary account, sort my by mime type
248 if (isRawContactDelta1Primary && isRawContactDelta2Primary) {
249 final String mimeType1 = kindSectionData1.getDataKind().mimeType;
250 final String mimeType2 = kindSectionData2.getDataKind().mimeType;
251 return mMimeTypeComparator.compare(mimeType1, mimeType2);
252 }
253
254 // The primary account name should be before all others
Walter Jang79658e12015-09-24 10:36:26 -0700255 if (isRawContactDelta1Primary) return -1;
256 if (isRawContactDelta2Primary) return 1;
Walter Jang192a01c2015-09-22 15:23:55 -0700257
258 return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
259 }
260 }
261
Walter Jang79658e12015-09-24 10:36:26 -0700262 public static class SavedState extends BaseSavedState {
263
264 public static final Parcelable.Creator<SavedState> CREATOR =
265 new Parcelable.Creator<SavedState>() {
266 public SavedState createFromParcel(Parcel in) {
267 return new SavedState(in);
268 }
269 public SavedState[] newArray(int size) {
270 return new SavedState[size];
271 }
272 };
273
274 private boolean mIsExpanded;
275
276 public SavedState(Parcelable superState) {
277 super(superState);
278 }
279
280 private SavedState(Parcel in) {
281 super(in);
282 mIsExpanded = in.readInt() != 0;
283 }
284
285 @Override
286 public void writeToParcel(Parcel out, int flags) {
287 super.writeToParcel(out, flags);
288 out.writeInt(mIsExpanded ? 1 : 0);
289 }
290 }
291
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700292 private CompactRawContactsEditorView.Listener mListener;
Walter Jangb6ca2722015-02-20 11:10:25 -0800293
Walter Jangcab3dce2015-02-09 17:48:03 -0800294 private AccountTypeManager mAccountTypeManager;
295 private LayoutInflater mLayoutInflater;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800296
Walter Jangcab3dce2015-02-09 17:48:03 -0800297 private ViewIdGenerator mViewIdGenerator;
Walter Jangf46abd82015-02-20 16:52:04 -0800298 private MaterialColorMapUtils.MaterialPalette mMaterialPalette;
Walter Jang708ea9e2015-09-10 15:42:05 -0700299 private long mPhotoId;
Walter Jang708ea9e2015-09-10 15:42:05 -0700300 private boolean mHasNewContact;
301 private boolean mIsUserProfile;
302 private AccountWithDataSet mPrimaryAccount;
303 private RawContactDelta mPrimaryRawContactDelta;
Walter Jang363d3fd2015-09-16 10:29:07 -0700304 private Map<String,List<KindSectionData>> mKindSectionDataMap = new HashMap<>();
Walter Jangcab3dce2015-02-09 17:48:03 -0800305
Walter Jang708ea9e2015-09-10 15:42:05 -0700306 // Account header
307 private View mAccountHeaderContainer;
308 private TextView mAccountHeaderType;
309 private TextView mAccountHeaderName;
310
311 // Account selector
312 private View mAccountSelectorContainer;
313 private View mAccountSelector;
314 private TextView mAccountSelectorType;
315 private TextView mAccountSelectorName;
316
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700317 private CompactPhotoEditorView mPhotoView;
Walter Jangf5dfea42015-09-16 12:30:36 -0700318 private ViewGroup mKindSectionViews;
Walter Jangf10ca152015-09-22 15:23:55 -0700319 private Map<String,List<CompactKindSectionView>> mKindSectionViewsMap = new HashMap<>();
Walter Jangb6ca2722015-02-20 11:10:25 -0800320 private View mMoreFields;
Walter Jangcab3dce2015-02-09 17:48:03 -0800321
Walter Jang79658e12015-09-24 10:36:26 -0700322 private boolean mIsExpanded;
Walter Jang3efae4a2015-02-18 11:12:00 -0800323 private long mPhotoRawContactId;
324
Walter Jangcab3dce2015-02-09 17:48:03 -0800325 public CompactRawContactsEditorView(Context context) {
326 super(context);
327 }
328
329 public CompactRawContactsEditorView(Context context, AttributeSet attrs) {
330 super(context, attrs);
331 }
332
Walter Jangb6ca2722015-02-20 11:10:25 -0800333 /**
334 * Sets the receiver for {@link CompactRawContactsEditorView} callbacks.
335 */
336 public void setListener(Listener listener) {
337 mListener = listener;
338 }
339
Walter Jangcab3dce2015-02-09 17:48:03 -0800340 @Override
341 protected void onFinishInflate() {
342 super.onFinishInflate();
343
344 mAccountTypeManager = AccountTypeManager.getInstance(getContext());
345 mLayoutInflater = (LayoutInflater)
346 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
347
Walter Jang708ea9e2015-09-10 15:42:05 -0700348 // Account header
349 mAccountHeaderContainer = findViewById(R.id.account_container);
350 mAccountHeaderType = (TextView) findViewById(R.id.account_type);
351 mAccountHeaderName = (TextView) findViewById(R.id.account_name);
352
353 // Account selector
354 mAccountSelectorContainer = findViewById(R.id.account_selector_container);
355 mAccountSelector = findViewById(R.id.account);
356 mAccountSelectorType = (TextView) findViewById(R.id.account_type_selector);
357 mAccountSelectorName = (TextView) findViewById(R.id.account_name_selector);
358
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700359 mPhotoView = (CompactPhotoEditorView) findViewById(R.id.photo_editor);
Walter Jangf5dfea42015-09-16 12:30:36 -0700360 mKindSectionViews = (LinearLayout) findViewById(R.id.kind_section_views);
Walter Jangb6ca2722015-02-20 11:10:25 -0800361 mMoreFields = findViewById(R.id.more_fields);
362 mMoreFields.setOnClickListener(this);
363 }
364
Walter Jangb6ca2722015-02-20 11:10:25 -0800365 @Override
366 public void onClick(View view) {
Walter Jangf5dfea42015-09-16 12:30:36 -0700367 if (view.getId() == R.id.more_fields) {
Walter Jangd6753152015-10-02 09:23:13 -0700368 showAllFields();
Walter Jangb6ca2722015-02-20 11:10:25 -0800369 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800370 }
371
372 @Override
373 public void setEnabled(boolean enabled) {
374 super.setEnabled(enabled);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700375 final int childCount = mKindSectionViews.getChildCount();
376 for (int i = 0; i < childCount; i++) {
377 mKindSectionViews.getChildAt(i).setEnabled(enabled);
Walter Jangcab3dce2015-02-09 17:48:03 -0800378 }
379 }
380
Walter Jang79658e12015-09-24 10:36:26 -0700381 @Override
382 public Parcelable onSaveInstanceState() {
383 final Parcelable superState = super.onSaveInstanceState();
384 final SavedState savedState = new SavedState(superState);
385 savedState.mIsExpanded = mIsExpanded;
386 return savedState;
387 }
388
389 @Override
390 public void onRestoreInstanceState(Parcelable state) {
391 if(!(state instanceof SavedState)) {
392 super.onRestoreInstanceState(state);
393 return;
394 }
395 final SavedState savedState = (SavedState) state;
396 super.onRestoreInstanceState(savedState.getSuperState());
397 mIsExpanded = savedState.mIsExpanded;
Walter Jangd6753152015-10-02 09:23:13 -0700398 if (mIsExpanded) {
399 showAllFields();
Walter Jang79658e12015-09-24 10:36:26 -0700400 }
401 }
402
Walter Jang3efae4a2015-02-18 11:12:00 -0800403 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800404 * Pass through to {@link CompactPhotoEditorView#setPhotoHandler}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800405 */
406 public void setPhotoHandler(PhotoHandler photoHandler) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700407 mPhotoView.setPhotoHandler(photoHandler);
Walter Jang3efae4a2015-02-18 11:12:00 -0800408 }
409
410 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800411 * Pass through to {@link CompactPhotoEditorView#setPhoto}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800412 */
413 public void setPhoto(Bitmap bitmap) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700414 mPhotoView.setPhoto(bitmap);
Walter Jang3efae4a2015-02-18 11:12:00 -0800415 }
416
417 /**
Walter Jang41b3ea12015-03-09 17:30:06 -0700418 * Pass through to {@link CompactPhotoEditorView#setFullSizedPhoto(Uri)}.
419 */
420 public void setFullSizePhoto(Uri photoUri) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700421 mPhotoView.setFullSizedPhoto(photoUri);
Walter Jang41b3ea12015-03-09 17:30:06 -0700422 }
423
424 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800425 * Pass through to {@link CompactPhotoEditorView#isWritablePhotoSet}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800426 */
427 public boolean isWritablePhotoSet() {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700428 return mPhotoView.isWritablePhotoSet();
Walter Jang3efae4a2015-02-18 11:12:00 -0800429 }
430
431 /**
Walter Jang3efae4a2015-02-18 11:12:00 -0800432 * Get the raw contact ID for the CompactHeaderView photo.
433 */
Walter Jang3efae4a2015-02-18 11:12:00 -0800434 public long getPhotoRawContactId() {
435 return mPhotoRawContactId;
436 }
437
Walter Jangd35e5ef2015-02-24 09:18:16 -0800438 public View getAggregationAnchorView() {
Walter Jangf10ca152015-09-22 15:23:55 -0700439 final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
Walter Jang192a01c2015-09-22 15:23:55 -0700440 StructuredName.CONTENT_ITEM_TYPE);
Walter Jangf10ca152015-09-22 15:23:55 -0700441 if (!kindSectionViews.isEmpty()) {
Walter Jang192a01c2015-09-22 15:23:55 -0700442 return mKindSectionViews.getChildAt(0).findViewById(R.id.anchor_view);
Walter Jangd35e5ef2015-02-24 09:18:16 -0800443 }
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700444 return null;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800445 }
446
Walter Jangf10ca152015-09-22 15:23:55 -0700447 public void setGroupMetaData(Cursor groupMetaData) {
448 final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
449 GroupMembership.CONTENT_ITEM_TYPE);
450 for (CompactKindSectionView kindSectionView : kindSectionViews) {
451 kindSectionView.setGroupMetaData(groupMetaData);
Walter Jangd6753152015-10-02 09:23:13 -0700452 if (mIsExpanded) {
453 kindSectionView.setHideWhenEmpty(false);
454 kindSectionView.updateEmptyEditors(/* shouldAnimate =*/ true);
455 }
Walter Jangf10ca152015-09-22 15:23:55 -0700456 }
457 }
458
Walter Jangf46abd82015-02-20 16:52:04 -0800459 public void setState(RawContactDeltaList rawContactDeltas,
Walter Jang06f73a12015-06-17 11:15:48 -0700460 MaterialColorMapUtils.MaterialPalette materialPalette, ViewIdGenerator viewIdGenerator,
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700461 long photoId, boolean hasNewContact, boolean isUserProfile,
462 AccountWithDataSet primaryAccount) {
Walter Jang363d3fd2015-09-16 10:29:07 -0700463 mKindSectionDataMap.clear();
Walter Jangf5dfea42015-09-16 12:30:36 -0700464 mKindSectionViews.removeAllViews();
Walter Jang363d3fd2015-09-16 10:29:07 -0700465 mMoreFields.setVisibility(View.VISIBLE);
Walter Jangcab3dce2015-02-09 17:48:03 -0800466
Walter Jangf46abd82015-02-20 16:52:04 -0800467 mMaterialPalette = materialPalette;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700468 mViewIdGenerator = viewIdGenerator;
Walter Jang708ea9e2015-09-10 15:42:05 -0700469 mPhotoId = photoId;
Walter Jang708ea9e2015-09-10 15:42:05 -0700470 mHasNewContact = hasNewContact;
471 mIsUserProfile = isUserProfile;
472 mPrimaryAccount = primaryAccount;
473 if (mPrimaryAccount == null) {
474 mPrimaryAccount = ContactEditorUtils.getInstance(getContext()).getDefaultAccount();
475 }
476 vlog("state: primary " + mPrimaryAccount);
Walter Jangcab3dce2015-02-09 17:48:03 -0800477
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700478 // Parse the given raw contact deltas
479 if (rawContactDeltas == null || rawContactDeltas.isEmpty()) {
480 elog("No raw contact deltas");
Walter Jang79658e12015-09-24 10:36:26 -0700481 if (mListener != null) mListener.onBindEditorsFailed();
Walter Jangf5dfea42015-09-16 12:30:36 -0700482 return;
483 }
Walter Jang192a01c2015-09-22 15:23:55 -0700484 parseRawContactDeltas(rawContactDeltas, mPrimaryAccount);
Walter Jang79658e12015-09-24 10:36:26 -0700485 if (mKindSectionDataMap.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700486 elog("No kind section data parsed from RawContactDelta(s)");
Walter Jang79658e12015-09-24 10:36:26 -0700487 if (mListener != null) mListener.onBindEditorsFailed();
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700488 return;
489 }
490
491 // Setup the view
Walter Jang708ea9e2015-09-10 15:42:05 -0700492 addAccountInfo();
Walter Jang363d3fd2015-09-16 10:29:07 -0700493 addPhotoView();
Walter Jangf5dfea42015-09-16 12:30:36 -0700494 addKindSectionViews();
Walter Jang79658e12015-09-24 10:36:26 -0700495
Walter Jangd6753152015-10-02 09:23:13 -0700496 if (mIsExpanded) {
497 showAllFields();
498 }
499
500 if (mListener != null) mListener.onEditorsBound();
Walter Jangcab3dce2015-02-09 17:48:03 -0800501 }
502
Walter Jang192a01c2015-09-22 15:23:55 -0700503 private void parseRawContactDeltas(RawContactDeltaList rawContactDeltas,
504 AccountWithDataSet primaryAccount) {
505 if (primaryAccount != null) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700506 // Use the first writable contact that matches the primary account
507 for (RawContactDelta rawContactDelta : rawContactDeltas) {
508 if (!rawContactDelta.isVisible()) continue;
509 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700510 if (accountType == null || !accountType.areContactsWritable()) continue;
Walter Jang192a01c2015-09-22 15:23:55 -0700511 if (matchesAccount(primaryAccount, rawContactDelta)) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700512 vlog("parse: matched primary account raw contact");
Walter Jang708ea9e2015-09-10 15:42:05 -0700513 mPrimaryRawContactDelta = rawContactDelta;
514 break;
515 }
Walter Jang2d3f31c2015-06-18 23:15:31 -0700516 }
517 }
Walter Jang708ea9e2015-09-10 15:42:05 -0700518 if (mPrimaryRawContactDelta == null) {
519 // Fall back to the first writable raw contact
520 for (RawContactDelta rawContactDelta : rawContactDeltas) {
521 if (!rawContactDelta.isVisible()) continue;
522 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
523 if (accountType != null && accountType.areContactsWritable()) {
524 vlog("parse: falling back to the first writable raw contact as primary");
525 mPrimaryRawContactDelta = rawContactDelta;
526 break;
527 }
528 }
Walter Jang2d3f31c2015-06-18 23:15:31 -0700529 }
Walter Jang192a01c2015-09-22 15:23:55 -0700530
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700531 if (mPrimaryRawContactDelta != null) {
532 RawContactModifier.ensureKindExists(mPrimaryRawContactDelta,
533 mPrimaryRawContactDelta.getAccountType(mAccountTypeManager),
534 StructuredName.CONTENT_ITEM_TYPE);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700535 RawContactModifier.ensureKindExists(mPrimaryRawContactDelta,
536 mPrimaryRawContactDelta.getAccountType(mAccountTypeManager),
537 Photo.CONTENT_ITEM_TYPE);
538 }
Walter Jangfa127a12015-06-18 09:48:18 -0700539
Walter Jang363d3fd2015-09-16 10:29:07 -0700540 // Build the kind section data list map
Walter Jang192a01c2015-09-22 15:23:55 -0700541 vlog("parse: " + rawContactDeltas.size() + " rawContactDelta(s)");
542 for (int j = 0; j < rawContactDeltas.size(); j++) {
543 final RawContactDelta rawContactDelta = rawContactDeltas.get(j);
544 vlog("parse: " + j + " rawContactDelta" + rawContactDelta);
Walter Jang363d3fd2015-09-16 10:29:07 -0700545 if (rawContactDelta == null || !rawContactDelta.isVisible()) continue;
Walter Jangcab3dce2015-02-09 17:48:03 -0800546 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
Walter Jang363d3fd2015-09-16 10:29:07 -0700547 if (accountType == null) continue;
548 final List<DataKind> dataKinds = accountType.getSortedDataKinds();
549 final int dataKindSize = dataKinds == null ? 0 : dataKinds.size();
550 vlog("parse: " + dataKindSize + " dataKinds(s)");
551 for (int i = 0; i < dataKindSize; i++) {
552 final DataKind dataKind = dataKinds.get(i);
Walter Jang192a01c2015-09-22 15:23:55 -0700553 if (dataKind == null || !dataKind.editable) {
554 vlog("parse: " + i + " " + dataKind.mimeType + " dropped read-only");
555 continue;
556 }
557 final String mimeType = dataKind.mimeType;
558
559 // Skip psuedo mime types
560 if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
561 || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
562 vlog("parse: " + i + " " + dataKind.mimeType + " dropped pseudo type");
563 continue;
564 }
565
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700566 final List<KindSectionData> kindSectionDataList =
Walter Jang192a01c2015-09-22 15:23:55 -0700567 getKindSectionDataList(mimeType);
Walter Jang363d3fd2015-09-16 10:29:07 -0700568 final KindSectionData kindSectionData =
569 new KindSectionData(accountType, dataKind, rawContactDelta);
570 kindSectionDataList.add(kindSectionData);
Walter Jang192a01c2015-09-22 15:23:55 -0700571
Walter Jang79658e12015-09-24 10:36:26 -0700572 // Note we must create nickname entries
Walter Jang192a01c2015-09-22 15:23:55 -0700573 if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)
Walter Jang79658e12015-09-24 10:36:26 -0700574 && kindSectionData.getValuesDeltas().isEmpty()) {
Walter Jang192a01c2015-09-22 15:23:55 -0700575 RawContactModifier.insertChild(rawContactDelta, dataKind);
576 }
577
Walter Jang363d3fd2015-09-16 10:29:07 -0700578 vlog("parse: " + i + " " + dataKind.mimeType + " " +
Walter Jang192a01c2015-09-22 15:23:55 -0700579 kindSectionData.getValuesDeltas().size() + " value(s)");
Walter Jangac679af2015-06-01 12:17:06 -0700580 }
581 }
Walter Jang3efae4a2015-02-18 11:12:00 -0800582 }
583
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700584 private List<KindSectionData> getKindSectionDataList(String mimeType) {
Walter Jang192a01c2015-09-22 15:23:55 -0700585 // Put structured names and nicknames together
586 mimeType = Nickname.CONTENT_ITEM_TYPE.equals(mimeType)
587 ? StructuredName.CONTENT_ITEM_TYPE : mimeType;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700588 List<KindSectionData> kindSectionDataList = mKindSectionDataMap.get(mimeType);
589 if (kindSectionDataList == null) {
590 kindSectionDataList = new ArrayList<>();
591 mKindSectionDataMap.put(mimeType, kindSectionDataList);
592 }
593 return kindSectionDataList;
594 }
595
Walter Jang192a01c2015-09-22 15:23:55 -0700596 /** Whether the given RawContactDelta belong to the given account. */
597 private boolean matchesAccount(AccountWithDataSet accountWithDataSet,
598 RawContactDelta rawContactDelta) {
599 if (accountWithDataSet == null) return false;
600 return Objects.equals(accountWithDataSet.name, rawContactDelta.getAccountName())
601 && Objects.equals(accountWithDataSet.type, rawContactDelta.getAccountType())
602 && Objects.equals(accountWithDataSet.dataSet, rawContactDelta.getDataSet());
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700603 }
604
Walter Jang708ea9e2015-09-10 15:42:05 -0700605 private void addAccountInfo() {
606 if (mPrimaryRawContactDelta == null) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700607 mAccountHeaderContainer.setVisibility(View.GONE);
608 mAccountSelectorContainer.setVisibility(View.GONE);
609 return;
610 }
611
612 // Get the account information for the primary raw contact delta
613 final Pair<String,String> accountInfo = EditorUiUtils.getAccountInfo(getContext(),
614 mIsUserProfile, mPrimaryRawContactDelta.getAccountName(),
615 mPrimaryRawContactDelta.getAccountType(mAccountTypeManager));
616
617 // The account header and selector show the same information so both shouldn't be visible
618 // at the same time
619 final List<AccountWithDataSet> accounts =
620 AccountTypeManager.getInstance(getContext()).getAccounts(true);
621 if (mHasNewContact && !mIsUserProfile && accounts.size() > 1) {
622 mAccountHeaderContainer.setVisibility(View.GONE);
623 addAccountSelector(accountInfo);
624 } else {
625 addAccountHeader(accountInfo);
626 mAccountSelectorContainer.setVisibility(View.GONE);
627 }
628 }
629
630 private void addAccountHeader(Pair<String,String> accountInfo) {
Walter Jang03cea2e2015-09-18 17:04:21 -0700631 if (TextUtils.isEmpty(accountInfo.first)) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700632 // Hide this view so the other text view will be centered vertically
633 mAccountHeaderName.setVisibility(View.GONE);
634 } else {
635 mAccountHeaderName.setVisibility(View.VISIBLE);
636 mAccountHeaderName.setText(accountInfo.first);
637 }
638 mAccountHeaderType.setText(accountInfo.second);
639
640 mAccountHeaderContainer.setContentDescription(
641 EditorUiUtils.getAccountInfoContentDescription(
642 accountInfo.first, accountInfo.second));
643 }
644
645 private void addAccountSelector(Pair<String,String> accountInfo) {
646 mAccountSelectorContainer.setVisibility(View.VISIBLE);
647
Walter Jang03cea2e2015-09-18 17:04:21 -0700648 if (TextUtils.isEmpty(accountInfo.first)) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700649 // Hide this view so the other text view will be centered vertically
650 mAccountSelectorName.setVisibility(View.GONE);
651 } else {
652 mAccountSelectorName.setVisibility(View.VISIBLE);
653 mAccountSelectorName.setText(accountInfo.first);
654 }
655 mAccountSelectorType.setText(accountInfo.second);
656
657 mAccountSelectorContainer.setContentDescription(
658 EditorUiUtils.getAccountInfoContentDescription(
659 accountInfo.first, accountInfo.second));
660
661 mAccountSelector.setOnClickListener(new View.OnClickListener() {
662 @Override
663 public void onClick(View v) {
664 final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
665 final AccountsListAdapter adapter =
666 new AccountsListAdapter(getContext(),
667 AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE,
668 mPrimaryAccount);
669 popup.setWidth(mAccountSelectorContainer.getWidth());
670 popup.setAnchorView(mAccountSelectorContainer);
671 popup.setAdapter(adapter);
672 popup.setModal(true);
673 popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
674 popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
675 @Override
676 public void onItemClick(AdapterView<?> parent, View view, int position,
677 long id) {
678 UiClosables.closeQuietly(popup);
679 final AccountWithDataSet newAccount = adapter.getItem(position);
680 if (mListener != null && !mPrimaryAccount.equals(newAccount)) {
681 mListener.onRebindEditorsForNewContact(
682 mPrimaryRawContactDelta,
683 mPrimaryAccount,
684 newAccount);
685 }
686 }
687 });
688 popup.show();
689 }
690 });
691 }
692
Walter Jang363d3fd2015-09-16 10:29:07 -0700693 private void addPhotoView() {
694 // Get the kind section data and values delta that will back the photo view
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700695 Pair<KindSectionData,ValuesDelta> pair = getPrimaryKindSectionData(mPhotoId);
Walter Jang363d3fd2015-09-16 10:29:07 -0700696 if (pair == null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700697 wlog("photo: no kind section data parsed");
Walter Jang363d3fd2015-09-16 10:29:07 -0700698 return;
699 }
700 final KindSectionData kindSectionData = pair.first;
701 final ValuesDelta valuesDelta = pair.second;
Walter Jang06f73a12015-06-17 11:15:48 -0700702
Walter Jang363d3fd2015-09-16 10:29:07 -0700703 // If we're editing a read-only contact we want to display the photo from the
704 // read-only contact in a photo editor backed by the new raw contact
Walter Jang192a01c2015-09-22 15:23:55 -0700705 // that was created.
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700706 if (mHasNewContact) {
707 mPhotoRawContactId = mPrimaryRawContactDelta == null
708 ? null : mPrimaryRawContactDelta.getRawContactId();
Walter Jang363d3fd2015-09-16 10:29:07 -0700709 }
Walter Jang06f73a12015-06-17 11:15:48 -0700710
Walter Jang363d3fd2015-09-16 10:29:07 -0700711 mPhotoRawContactId = kindSectionData.getRawContactDelta().getRawContactId();
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700712 mPhotoView.setValues(kindSectionData.getDataKind(), valuesDelta,
Walter Jang363d3fd2015-09-16 10:29:07 -0700713 kindSectionData.getRawContactDelta(),
714 !kindSectionData.getAccountType().areContactsWritable(), mMaterialPalette,
715 mViewIdGenerator);
716 }
717
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700718 private Pair<KindSectionData,ValuesDelta> getPrimaryKindSectionData(long id) {
719 final String mimeType = Photo.CONTENT_ITEM_TYPE;
Walter Jang363d3fd2015-09-16 10:29:07 -0700720 final List<KindSectionData> kindSectionDataList = mKindSectionDataMap.get(mimeType);
Walter Jang151f3e62015-02-26 15:29:40 -0800721
Walter Jang363d3fd2015-09-16 10:29:07 -0700722 KindSectionData resultKindSectionData = null;
723 ValuesDelta resultValuesDelta = null;
724 if (id > 0) {
725 // Look for a match for the ID that was passed in
726 for (KindSectionData kindSectionData : kindSectionDataList) {
727 resultValuesDelta = kindSectionData.getValuesDeltaById(id);
728 if (resultValuesDelta != null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700729 vlog("photo: matched kind section data by ID");
Walter Jang363d3fd2015-09-16 10:29:07 -0700730 resultKindSectionData = kindSectionData;
731 break;
Walter Jang398cd4b2015-06-16 11:17:53 -0700732 }
733 }
734 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700735 if (resultKindSectionData == null) {
736 // Look for a super primary photo
737 for (KindSectionData kindSectionData : kindSectionDataList) {
738 resultValuesDelta = kindSectionData.getSuperPrimaryValuesDelta();
739 if (resultValuesDelta != null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700740 wlog("photo: matched super primary kind section data");
Walter Jang363d3fd2015-09-16 10:29:07 -0700741 resultKindSectionData = kindSectionData;
742 break;
743 }
Walter Jang151f3e62015-02-26 15:29:40 -0800744 }
745 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700746 if (resultKindSectionData == null) {
747 // Fall back to the first non-empty value
748 for (KindSectionData kindSectionData : kindSectionDataList) {
749 resultValuesDelta = kindSectionData.getFirstNonEmptyValuesDelta();
750 if (resultValuesDelta != null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700751 vlog("photo: using first non empty value");
Walter Jang363d3fd2015-09-16 10:29:07 -0700752 resultKindSectionData = kindSectionData;
753 break;
754 }
Walter Jang151f3e62015-02-26 15:29:40 -0800755 }
756 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700757 if (resultKindSectionData == null || resultValuesDelta == null) {
758 final List<ValuesDelta> valuesDeltaList = kindSectionDataList.get(0).getValuesDeltas();
759 if (valuesDeltaList != null && !valuesDeltaList.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700760 vlog("photo: falling back to first empty entry");
Walter Jang363d3fd2015-09-16 10:29:07 -0700761 resultValuesDelta = valuesDeltaList.get(0);
762 resultKindSectionData = kindSectionDataList.get(0);
Walter Jang10446452015-02-20 13:51:16 -0800763 }
764 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700765 return resultKindSectionData != null && resultValuesDelta != null
766 ? new Pair<>(resultKindSectionData, resultValuesDelta) : null;
Walter Jang10446452015-02-20 13:51:16 -0800767 }
768
Walter Jangf5dfea42015-09-16 12:30:36 -0700769 private void addKindSectionViews() {
770 // Sort the kinds
771 final TreeSet<Map.Entry<String,List<KindSectionData>>> entries =
Walter Jang192a01c2015-09-22 15:23:55 -0700772 new TreeSet<>(KIND_SECTION_DATA_MAP_ENTRY_COMPARATOR);
Walter Jangf5dfea42015-09-16 12:30:36 -0700773 entries.addAll(mKindSectionDataMap.entrySet());
Walter Jang3efae4a2015-02-18 11:12:00 -0800774
Walter Jangf5dfea42015-09-16 12:30:36 -0700775 vlog("kind: " + entries.size() + " kindSection(s)");
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700776 int i = -1;
Walter Jangf5dfea42015-09-16 12:30:36 -0700777 for (Map.Entry<String, List<KindSectionData>> entry : entries) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700778 i++;
779
Walter Jangf5dfea42015-09-16 12:30:36 -0700780 final String mimeType = entry.getKey();
781 final List<KindSectionData> kindSectionDataList = entry.getValue();
Walter Jangab50e6f2015-06-15 08:57:22 -0700782
Walter Jangf5dfea42015-09-16 12:30:36 -0700783 // Ignore mime types that we've already handled
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700784 if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
785 vlog("kind: " + i + " " + mimeType + " dropped");
786 continue;
787 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700788
Walter Jang192a01c2015-09-22 15:23:55 -0700789 if (kindSectionDataList != null && !kindSectionDataList.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700790 vlog("kind: " + i + " " + mimeType + ": " + kindSectionDataList.size() +
791 " kindSectionData(s)");
792
Walter Jangf5dfea42015-09-16 12:30:36 -0700793 final CompactKindSectionView kindSectionView = inflateKindSectionView(
794 mKindSectionViews, kindSectionDataList, mimeType);
Walter Jangf5dfea42015-09-16 12:30:36 -0700795 mKindSectionViews.addView(kindSectionView);
Walter Jangf10ca152015-09-22 15:23:55 -0700796
797 // Keep a pointer to all the KindSectionsViews for each mimeType
798 getKindSectionViews(mimeType).add(kindSectionView);
Walter Jangcab3dce2015-02-09 17:48:03 -0800799 }
800 }
801 }
802
Walter Jangf10ca152015-09-22 15:23:55 -0700803 private List<CompactKindSectionView> getKindSectionViews(String mimeType) {
804 List<CompactKindSectionView> kindSectionViews = mKindSectionViewsMap.get(mimeType);
805 if (kindSectionViews == null) {
806 kindSectionViews = new ArrayList<>();
807 mKindSectionViewsMap.put(mimeType, kindSectionViews);
808 }
809 return kindSectionViews;
810 }
811
Walter Jangf5dfea42015-09-16 12:30:36 -0700812 private CompactKindSectionView inflateKindSectionView(ViewGroup viewGroup,
813 List<KindSectionData> kindSectionDataList, String mimeType) {
814 final CompactKindSectionView kindSectionView = (CompactKindSectionView)
815 mLayoutInflater.inflate(R.layout.compact_item_kind_section, viewGroup,
816 /* attachToRoot =*/ false);
817
Walter Jang192a01c2015-09-22 15:23:55 -0700818 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
Walter Jangf5dfea42015-09-16 12:30:36 -0700819 || Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang192a01c2015-09-22 15:23:55 -0700820 // Phone numbers and email addresses are always displayed,
821 // even if they are empty
Walter Jangf5dfea42015-09-16 12:30:36 -0700822 kindSectionView.setHideWhenEmpty(false);
823 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700824
Walter Jang192a01c2015-09-22 15:23:55 -0700825 // Since phone numbers and email addresses displayed even if they are empty,
826 // they will be the only types you add new values to initially for new contacts
827 kindSectionView.setShowOneEmptyEditor(true);
828
829 // Sort so the editors wind up in the order we want
830 if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
831 Collections.sort(kindSectionDataList, new NameEditorComparator(getContext(),
832 mPrimaryRawContactDelta));
833 } else {
834 Collections.sort(kindSectionDataList, new EditorComparator(getContext()));
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700835 }
836
Walter Jang79658e12015-09-24 10:36:26 -0700837 kindSectionView.setState(kindSectionDataList, mViewIdGenerator, mListener);
Walter Jangf5dfea42015-09-16 12:30:36 -0700838
839 return kindSectionView;
Walter Jangcab3dce2015-02-09 17:48:03 -0800840 }
841
Walter Jangd6753152015-10-02 09:23:13 -0700842 private void showAllFields() {
Walter Jang79658e12015-09-24 10:36:26 -0700843 // Stop hiding empty editors and allow the user to enter values for all kinds now
844 for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
845 final CompactKindSectionView kindSectionView =
846 (CompactKindSectionView) mKindSectionViews.getChildAt(i);
847 kindSectionView.setHideWhenEmpty(false);
848 kindSectionView.updateEmptyEditors(/* shouldAnimate =*/ true);
849 }
850 mIsExpanded = true;
Walter Jang79658e12015-09-24 10:36:26 -0700851
Walter Jangf5dfea42015-09-16 12:30:36 -0700852 // Hide the more fields button
853 mMoreFields.setVisibility(View.GONE);
Walter Jangcab3dce2015-02-09 17:48:03 -0800854 }
855
Walter Jangbf63a6d2015-05-05 09:14:35 -0700856 private static void vlog(String message) {
857 if (Log.isLoggable(TAG, Log.VERBOSE)) {
858 Log.v(TAG, message);
Walter Jangcab3dce2015-02-09 17:48:03 -0800859 }
860 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700861
862 private static void wlog(String message) {
863 if (Log.isLoggable(TAG, Log.WARN)) {
864 Log.w(TAG, message);
865 }
866 }
867
868 private static void elog(String message) {
869 Log.e(TAG, message);
870 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800871}