blob: 9d812766bfdf61a2f2925ea69b4a960dc75d0a3e [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 Jang151f3e62015-02-26 15:29:40 -0800112 }
113
Walter Jang192a01c2015-09-22 15:23:55 -0700114 /** Used to sort entire kind sections. */
115 private static final class KindSectionDataMapEntryComparator implements
Walter Jangf5dfea42015-09-16 12:30:36 -0700116 Comparator<Map.Entry<String,List<KindSectionData>>> {
117
Walter Jang192a01c2015-09-22 15:23:55 -0700118 final MimeTypeComparator mMimeTypeComparator = new MimeTypeComparator();
119
120 @Override
121 public int compare(Map.Entry<String, List<KindSectionData>> entry1,
122 Map.Entry<String, List<KindSectionData>> entry2) {
123 if (entry1 == entry2) return 0;
124 if (entry1 == null) return -1;
125 if (entry2 == null) return 1;
126
127 final String mimeType1 = entry1.getKey();
128 final String mimeType2 = entry2.getKey();
129
130 return mMimeTypeComparator.compare(mimeType1, mimeType2);
131 }
132 }
133
134 /**
135 * Sorts kinds roughly the same as quick contacts; we diverge in the following ways:
136 * <ol>
137 * <li>All names are together at the top.</li>
138 * <li>IM is moved up after addresses</li>
139 * <li>SIP addresses are moved to below phone numbers</li>
Walter Jang79658e12015-09-24 10:36:26 -0700140 * <li>Group membership is placed at the end</li>
Walter Jang192a01c2015-09-22 15:23:55 -0700141 * </ol>
142 */
143 private static final class MimeTypeComparator implements Comparator<String> {
144
Walter Jangf5dfea42015-09-16 12:30:36 -0700145 private static final List<String> MIME_TYPE_ORDER = Arrays.asList(new String[] {
146 StructuredName.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700147 Nickname.CONTENT_ITEM_TYPE,
Walter Jang2ae21752015-09-25 11:25:38 -0700148 Organization.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700149 Phone.CONTENT_ITEM_TYPE,
150 SipAddress.CONTENT_ITEM_TYPE,
151 Email.CONTENT_ITEM_TYPE,
152 StructuredPostal.CONTENT_ITEM_TYPE,
153 Im.CONTENT_ITEM_TYPE,
154 Website.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700155 Event.CONTENT_ITEM_TYPE,
156 Relation.CONTENT_ITEM_TYPE,
Walter Jangf10ca152015-09-22 15:23:55 -0700157 Note.CONTENT_ITEM_TYPE,
158 GroupMembership.CONTENT_ITEM_TYPE
Walter Jangf5dfea42015-09-16 12:30:36 -0700159 });
160
161 @Override
Walter Jang192a01c2015-09-22 15:23:55 -0700162 public int compare(String mimeType1, String mimeType2) {
163 if (mimeType1 == mimeType2) return 0;
164 if (mimeType1 == null) return -1;
165 if (mimeType2 == null) return 1;
Walter Jangf5dfea42015-09-16 12:30:36 -0700166
167 int index1 = MIME_TYPE_ORDER.indexOf(mimeType1);
168 int index2 = MIME_TYPE_ORDER.indexOf(mimeType2);
169
170 // Fallback to alphabetical ordering of the mime type if both are not found
171 if (index1 < 0 && index2 < 0) return mimeType1.compareTo(mimeType2);
172 if (index1 < 0) return 1;
173 if (index2 < 0) return -1;
174
175 return index1 < index2 ? -1 : 1;
176 }
177 }
178
Walter Jang192a01c2015-09-22 15:23:55 -0700179 /**
180 * Sorts primary accounts and google account types before others.
181 */
182 private static final class EditorComparator implements Comparator<KindSectionData> {
183
184 private RawContactDeltaComparator mRawContactDeltaComparator;
185
186 private EditorComparator(Context context) {
187 mRawContactDeltaComparator = new RawContactDeltaComparator(context);
188 }
189
190 @Override
191 public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
192 if (kindSectionData1 == kindSectionData2) return 0;
193 if (kindSectionData1 == null) return -1;
194 if (kindSectionData2 == null) return 1;
195
196 final RawContactDelta rawContactDelta1 = kindSectionData1.getRawContactDelta();
197 final RawContactDelta rawContactDelta2 = kindSectionData2.getRawContactDelta();
198
199 if (rawContactDelta1 == rawContactDelta2) return 0;
200 if (rawContactDelta1 == null) return -1;
201 if (rawContactDelta2 == null) return 1;
202
203 return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
204 }
205 }
206
207 /**
208 * Sorts primary account names first, followed by google account types, and other account
209 * types last. For names from the same account we order structured names before nicknames,
210 * but still keep names from the same account together.
211 */
212 private static final class NameEditorComparator implements Comparator<KindSectionData> {
213
214 private RawContactDeltaComparator mRawContactDeltaComparator;
215 private MimeTypeComparator mMimeTypeComparator;
216 private RawContactDelta mPrimaryRawContactDelta;
217
218 private NameEditorComparator(Context context, RawContactDelta primaryRawContactDelta) {
219 mRawContactDeltaComparator = new RawContactDeltaComparator(context);
220 mMimeTypeComparator = new MimeTypeComparator();
221 mPrimaryRawContactDelta = primaryRawContactDelta;
222 }
223
224 @Override
225 public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
226 if (kindSectionData1 == kindSectionData2) return 0;
227 if (kindSectionData1 == null) return -1;
228 if (kindSectionData2 == null) return 1;
229
230 final RawContactDelta rawContactDelta1 = kindSectionData1.getRawContactDelta();
231 final RawContactDelta rawContactDelta2 = kindSectionData2.getRawContactDelta();
232
233 if (rawContactDelta1 == rawContactDelta2) return 0;
234 if (rawContactDelta1 == null) return -1;
235 if (rawContactDelta2 == null) return 1;
236
237 final boolean isRawContactDelta1Primary =
238 mPrimaryRawContactDelta.equals(rawContactDelta1);
239 final boolean isRawContactDelta2Primary =
240 mPrimaryRawContactDelta.equals(rawContactDelta2);
241
242 // If both names are from the primary account, sort my by mime type
243 if (isRawContactDelta1Primary && isRawContactDelta2Primary) {
244 final String mimeType1 = kindSectionData1.getDataKind().mimeType;
245 final String mimeType2 = kindSectionData2.getDataKind().mimeType;
246 return mMimeTypeComparator.compare(mimeType1, mimeType2);
247 }
248
249 // The primary account name should be before all others
Walter Jang79658e12015-09-24 10:36:26 -0700250 if (isRawContactDelta1Primary) return -1;
251 if (isRawContactDelta2Primary) return 1;
Walter Jang192a01c2015-09-22 15:23:55 -0700252
253 return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
254 }
255 }
256
Walter Jang79658e12015-09-24 10:36:26 -0700257 public static class SavedState extends BaseSavedState {
258
259 public static final Parcelable.Creator<SavedState> CREATOR =
260 new Parcelable.Creator<SavedState>() {
261 public SavedState createFromParcel(Parcel in) {
262 return new SavedState(in);
263 }
264 public SavedState[] newArray(int size) {
265 return new SavedState[size];
266 }
267 };
268
269 private boolean mIsExpanded;
270
271 public SavedState(Parcelable superState) {
272 super(superState);
273 }
274
275 private SavedState(Parcel in) {
276 super(in);
277 mIsExpanded = in.readInt() != 0;
278 }
279
280 @Override
281 public void writeToParcel(Parcel out, int flags) {
282 super.writeToParcel(out, flags);
283 out.writeInt(mIsExpanded ? 1 : 0);
284 }
285 }
286
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700287 private CompactRawContactsEditorView.Listener mListener;
Walter Jangb6ca2722015-02-20 11:10:25 -0800288
Walter Jangcab3dce2015-02-09 17:48:03 -0800289 private AccountTypeManager mAccountTypeManager;
290 private LayoutInflater mLayoutInflater;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800291
Walter Jangcab3dce2015-02-09 17:48:03 -0800292 private ViewIdGenerator mViewIdGenerator;
Walter Jangf46abd82015-02-20 16:52:04 -0800293 private MaterialColorMapUtils.MaterialPalette mMaterialPalette;
Walter Jang708ea9e2015-09-10 15:42:05 -0700294 private long mPhotoId;
Walter Jang708ea9e2015-09-10 15:42:05 -0700295 private boolean mHasNewContact;
296 private boolean mIsUserProfile;
297 private AccountWithDataSet mPrimaryAccount;
298 private RawContactDelta mPrimaryRawContactDelta;
Walter Jang363d3fd2015-09-16 10:29:07 -0700299 private Map<String,List<KindSectionData>> mKindSectionDataMap = new HashMap<>();
Walter Jangcab3dce2015-02-09 17:48:03 -0800300
Walter Jang708ea9e2015-09-10 15:42:05 -0700301 // Account header
302 private View mAccountHeaderContainer;
303 private TextView mAccountHeaderType;
304 private TextView mAccountHeaderName;
305
306 // Account selector
307 private View mAccountSelectorContainer;
308 private View mAccountSelector;
309 private TextView mAccountSelectorType;
310 private TextView mAccountSelectorName;
311
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700312 private CompactPhotoEditorView mPhotoView;
Walter Jangf5dfea42015-09-16 12:30:36 -0700313 private ViewGroup mKindSectionViews;
Walter Jangf10ca152015-09-22 15:23:55 -0700314 private Map<String,List<CompactKindSectionView>> mKindSectionViewsMap = new HashMap<>();
Walter Jangb6ca2722015-02-20 11:10:25 -0800315 private View mMoreFields;
Walter Jangcab3dce2015-02-09 17:48:03 -0800316
Walter Jang79658e12015-09-24 10:36:26 -0700317 private boolean mIsExpanded;
Walter Jang3efae4a2015-02-18 11:12:00 -0800318 private long mPhotoRawContactId;
319
Walter Jangcab3dce2015-02-09 17:48:03 -0800320 public CompactRawContactsEditorView(Context context) {
321 super(context);
322 }
323
324 public CompactRawContactsEditorView(Context context, AttributeSet attrs) {
325 super(context, attrs);
326 }
327
Walter Jangb6ca2722015-02-20 11:10:25 -0800328 /**
329 * Sets the receiver for {@link CompactRawContactsEditorView} callbacks.
330 */
331 public void setListener(Listener listener) {
332 mListener = listener;
333 }
334
Walter Jangcab3dce2015-02-09 17:48:03 -0800335 @Override
336 protected void onFinishInflate() {
337 super.onFinishInflate();
338
339 mAccountTypeManager = AccountTypeManager.getInstance(getContext());
340 mLayoutInflater = (LayoutInflater)
341 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
342
Walter Jang708ea9e2015-09-10 15:42:05 -0700343 // Account header
344 mAccountHeaderContainer = findViewById(R.id.account_container);
345 mAccountHeaderType = (TextView) findViewById(R.id.account_type);
346 mAccountHeaderName = (TextView) findViewById(R.id.account_name);
347
348 // Account selector
349 mAccountSelectorContainer = findViewById(R.id.account_selector_container);
350 mAccountSelector = findViewById(R.id.account);
351 mAccountSelectorType = (TextView) findViewById(R.id.account_type_selector);
352 mAccountSelectorName = (TextView) findViewById(R.id.account_name_selector);
353
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700354 mPhotoView = (CompactPhotoEditorView) findViewById(R.id.photo_editor);
Walter Jangf5dfea42015-09-16 12:30:36 -0700355 mKindSectionViews = (LinearLayout) findViewById(R.id.kind_section_views);
Walter Jangb6ca2722015-02-20 11:10:25 -0800356 mMoreFields = findViewById(R.id.more_fields);
357 mMoreFields.setOnClickListener(this);
358 }
359
Walter Jangb6ca2722015-02-20 11:10:25 -0800360 @Override
361 public void onClick(View view) {
Walter Jangf5dfea42015-09-16 12:30:36 -0700362 if (view.getId() == R.id.more_fields) {
Walter Jang79658e12015-09-24 10:36:26 -0700363 showMoreFields();
Walter Jangf5dfea42015-09-16 12:30:36 -0700364 updateMoreFieldsButton();
Walter Jangb6ca2722015-02-20 11:10:25 -0800365 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800366 }
367
368 @Override
369 public void setEnabled(boolean enabled) {
370 super.setEnabled(enabled);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700371 final int childCount = mKindSectionViews.getChildCount();
372 for (int i = 0; i < childCount; i++) {
373 mKindSectionViews.getChildAt(i).setEnabled(enabled);
Walter Jangcab3dce2015-02-09 17:48:03 -0800374 }
375 }
376
Walter Jang79658e12015-09-24 10:36:26 -0700377 @Override
378 public Parcelable onSaveInstanceState() {
379 final Parcelable superState = super.onSaveInstanceState();
380 final SavedState savedState = new SavedState(superState);
381 savedState.mIsExpanded = mIsExpanded;
382 return savedState;
383 }
384
385 @Override
386 public void onRestoreInstanceState(Parcelable state) {
387 if(!(state instanceof SavedState)) {
388 super.onRestoreInstanceState(state);
389 return;
390 }
391 final SavedState savedState = (SavedState) state;
392 super.onRestoreInstanceState(savedState.getSuperState());
393 mIsExpanded = savedState.mIsExpanded;
394 if (mIsExpanded && !mKindSectionDataMap.isEmpty()) {
395 showMoreFields();
396 }
397 }
398
Walter Jang3efae4a2015-02-18 11:12:00 -0800399 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800400 * Pass through to {@link CompactPhotoEditorView#setPhotoHandler}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800401 */
402 public void setPhotoHandler(PhotoHandler photoHandler) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700403 mPhotoView.setPhotoHandler(photoHandler);
Walter Jang3efae4a2015-02-18 11:12:00 -0800404 }
405
406 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800407 * Pass through to {@link CompactPhotoEditorView#setPhoto}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800408 */
409 public void setPhoto(Bitmap bitmap) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700410 mPhotoView.setPhoto(bitmap);
Walter Jang3efae4a2015-02-18 11:12:00 -0800411 }
412
413 /**
Walter Jang41b3ea12015-03-09 17:30:06 -0700414 * Pass through to {@link CompactPhotoEditorView#setFullSizedPhoto(Uri)}.
415 */
416 public void setFullSizePhoto(Uri photoUri) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700417 mPhotoView.setFullSizedPhoto(photoUri);
Walter Jang41b3ea12015-03-09 17:30:06 -0700418 }
419
420 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800421 * Pass through to {@link CompactPhotoEditorView#isWritablePhotoSet}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800422 */
423 public boolean isWritablePhotoSet() {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700424 return mPhotoView.isWritablePhotoSet();
Walter Jang3efae4a2015-02-18 11:12:00 -0800425 }
426
427 /**
Walter Jang3efae4a2015-02-18 11:12:00 -0800428 * Get the raw contact ID for the CompactHeaderView photo.
429 */
Walter Jang3efae4a2015-02-18 11:12:00 -0800430 public long getPhotoRawContactId() {
431 return mPhotoRawContactId;
432 }
433
Walter Jangd35e5ef2015-02-24 09:18:16 -0800434 public View getAggregationAnchorView() {
Walter Jangf10ca152015-09-22 15:23:55 -0700435 final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
Walter Jang192a01c2015-09-22 15:23:55 -0700436 StructuredName.CONTENT_ITEM_TYPE);
Walter Jangf10ca152015-09-22 15:23:55 -0700437 if (!kindSectionViews.isEmpty()) {
Walter Jang192a01c2015-09-22 15:23:55 -0700438 return mKindSectionViews.getChildAt(0).findViewById(R.id.anchor_view);
Walter Jangd35e5ef2015-02-24 09:18:16 -0800439 }
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700440 return null;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800441 }
442
Walter Jangf10ca152015-09-22 15:23:55 -0700443 public void setGroupMetaData(Cursor groupMetaData) {
444 final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
445 GroupMembership.CONTENT_ITEM_TYPE);
446 for (CompactKindSectionView kindSectionView : kindSectionViews) {
447 kindSectionView.setGroupMetaData(groupMetaData);
448 }
Walter Jang79658e12015-09-24 10:36:26 -0700449
450 // Groups metadata may be set after we restore expansion state so just do it again
451 if (mIsExpanded) {
452 showMoreFields();
453 }
454 updateMoreFieldsButton();
Walter Jangf10ca152015-09-22 15:23:55 -0700455 }
456
Walter Jangf46abd82015-02-20 16:52:04 -0800457 public void setState(RawContactDeltaList rawContactDeltas,
Walter Jang06f73a12015-06-17 11:15:48 -0700458 MaterialColorMapUtils.MaterialPalette materialPalette, ViewIdGenerator viewIdGenerator,
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700459 long photoId, boolean hasNewContact, boolean isUserProfile,
460 AccountWithDataSet primaryAccount) {
461 // Clear previous state and reset views
Walter Jang363d3fd2015-09-16 10:29:07 -0700462 mKindSectionDataMap.clear();
Walter Jangf5dfea42015-09-16 12:30:36 -0700463 mKindSectionViews.removeAllViews();
Walter Jang363d3fd2015-09-16 10:29:07 -0700464 mMoreFields.setVisibility(View.VISIBLE);
Walter Jangcab3dce2015-02-09 17:48:03 -0800465
Walter Jangf46abd82015-02-20 16:52:04 -0800466 mMaterialPalette = materialPalette;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700467 mViewIdGenerator = viewIdGenerator;
Walter Jang708ea9e2015-09-10 15:42:05 -0700468 mPhotoId = photoId;
Walter Jang708ea9e2015-09-10 15:42:05 -0700469 mHasNewContact = hasNewContact;
470 mIsUserProfile = isUserProfile;
471 mPrimaryAccount = primaryAccount;
472 if (mPrimaryAccount == null) {
473 mPrimaryAccount = ContactEditorUtils.getInstance(getContext()).getDefaultAccount();
474 }
475 vlog("state: primary " + mPrimaryAccount);
Walter Jangcab3dce2015-02-09 17:48:03 -0800476
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700477 // Parse the given raw contact deltas
478 if (rawContactDeltas == null || rawContactDeltas.isEmpty()) {
479 elog("No raw contact deltas");
Walter Jang79658e12015-09-24 10:36:26 -0700480 if (mListener != null) mListener.onBindEditorsFailed();
Walter Jangf5dfea42015-09-16 12:30:36 -0700481 return;
482 }
Walter Jang192a01c2015-09-22 15:23:55 -0700483 parseRawContactDeltas(rawContactDeltas, mPrimaryAccount);
Walter Jang79658e12015-09-24 10:36:26 -0700484 if (mKindSectionDataMap.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700485 elog("No kind section data parsed from RawContactDelta(s)");
Walter Jang79658e12015-09-24 10:36:26 -0700486 if (mListener != null) mListener.onBindEditorsFailed();
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700487 return;
488 }
489
490 // Setup the view
491 setId(mViewIdGenerator.getId(rawContactDeltas.get(0), /* dataKind =*/ null,
492 /* valuesDelta =*/ null, ViewIdGenerator.NO_VIEW_INDEX));
Walter Jang708ea9e2015-09-10 15:42:05 -0700493 addAccountInfo();
Walter Jang363d3fd2015-09-16 10:29:07 -0700494 addPhotoView();
Walter Jangf5dfea42015-09-16 12:30:36 -0700495 addKindSectionViews();
Walter Jang79658e12015-09-24 10:36:26 -0700496
Walter Jangf5dfea42015-09-16 12:30:36 -0700497 updateMoreFieldsButton();
Walter Jangcab3dce2015-02-09 17:48:03 -0800498 }
499
Walter Jang192a01c2015-09-22 15:23:55 -0700500 private void parseRawContactDeltas(RawContactDeltaList rawContactDeltas,
501 AccountWithDataSet primaryAccount) {
502 if (primaryAccount != null) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700503 // Use the first writable contact that matches the primary account
504 for (RawContactDelta rawContactDelta : rawContactDeltas) {
505 if (!rawContactDelta.isVisible()) continue;
506 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700507 if (accountType == null || !accountType.areContactsWritable()) continue;
Walter Jang192a01c2015-09-22 15:23:55 -0700508 if (matchesAccount(primaryAccount, rawContactDelta)) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700509 vlog("parse: matched primary account raw contact");
Walter Jang708ea9e2015-09-10 15:42:05 -0700510 mPrimaryRawContactDelta = rawContactDelta;
511 break;
512 }
Walter Jang2d3f31c2015-06-18 23:15:31 -0700513 }
514 }
Walter Jang708ea9e2015-09-10 15:42:05 -0700515 if (mPrimaryRawContactDelta == null) {
516 // Fall back to the first writable raw contact
517 for (RawContactDelta rawContactDelta : rawContactDeltas) {
518 if (!rawContactDelta.isVisible()) continue;
519 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
520 if (accountType != null && accountType.areContactsWritable()) {
521 vlog("parse: falling back to the first writable raw contact as primary");
522 mPrimaryRawContactDelta = rawContactDelta;
523 break;
524 }
525 }
Walter Jang2d3f31c2015-06-18 23:15:31 -0700526 }
Walter Jang192a01c2015-09-22 15:23:55 -0700527
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700528 if (mPrimaryRawContactDelta != null) {
529 RawContactModifier.ensureKindExists(mPrimaryRawContactDelta,
530 mPrimaryRawContactDelta.getAccountType(mAccountTypeManager),
531 StructuredName.CONTENT_ITEM_TYPE);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700532 RawContactModifier.ensureKindExists(mPrimaryRawContactDelta,
533 mPrimaryRawContactDelta.getAccountType(mAccountTypeManager),
534 Photo.CONTENT_ITEM_TYPE);
535 }
Walter Jangfa127a12015-06-18 09:48:18 -0700536
Walter Jang363d3fd2015-09-16 10:29:07 -0700537 // Build the kind section data list map
Walter Jang192a01c2015-09-22 15:23:55 -0700538 vlog("parse: " + rawContactDeltas.size() + " rawContactDelta(s)");
539 for (int j = 0; j < rawContactDeltas.size(); j++) {
540 final RawContactDelta rawContactDelta = rawContactDeltas.get(j);
541 vlog("parse: " + j + " rawContactDelta" + rawContactDelta);
Walter Jang363d3fd2015-09-16 10:29:07 -0700542 if (rawContactDelta == null || !rawContactDelta.isVisible()) continue;
Walter Jangcab3dce2015-02-09 17:48:03 -0800543 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
Walter Jang363d3fd2015-09-16 10:29:07 -0700544 if (accountType == null) continue;
545 final List<DataKind> dataKinds = accountType.getSortedDataKinds();
546 final int dataKindSize = dataKinds == null ? 0 : dataKinds.size();
547 vlog("parse: " + dataKindSize + " dataKinds(s)");
548 for (int i = 0; i < dataKindSize; i++) {
549 final DataKind dataKind = dataKinds.get(i);
Walter Jang192a01c2015-09-22 15:23:55 -0700550 if (dataKind == null || !dataKind.editable) {
551 vlog("parse: " + i + " " + dataKind.mimeType + " dropped read-only");
552 continue;
553 }
554 final String mimeType = dataKind.mimeType;
555
556 // Skip psuedo mime types
557 if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
558 || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
559 vlog("parse: " + i + " " + dataKind.mimeType + " dropped pseudo type");
560 continue;
561 }
562
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700563 final List<KindSectionData> kindSectionDataList =
Walter Jang192a01c2015-09-22 15:23:55 -0700564 getKindSectionDataList(mimeType);
Walter Jang363d3fd2015-09-16 10:29:07 -0700565 final KindSectionData kindSectionData =
566 new KindSectionData(accountType, dataKind, rawContactDelta);
567 kindSectionDataList.add(kindSectionData);
Walter Jang192a01c2015-09-22 15:23:55 -0700568
Walter Jang79658e12015-09-24 10:36:26 -0700569 // Note we must create nickname entries
Walter Jang192a01c2015-09-22 15:23:55 -0700570 if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)
Walter Jang79658e12015-09-24 10:36:26 -0700571 && kindSectionData.getValuesDeltas().isEmpty()) {
Walter Jang192a01c2015-09-22 15:23:55 -0700572 RawContactModifier.insertChild(rawContactDelta, dataKind);
573 }
574
Walter Jang363d3fd2015-09-16 10:29:07 -0700575 vlog("parse: " + i + " " + dataKind.mimeType + " " +
Walter Jang192a01c2015-09-22 15:23:55 -0700576 kindSectionData.getValuesDeltas().size() + " value(s)");
Walter Jangac679af2015-06-01 12:17:06 -0700577 }
578 }
Walter Jang3efae4a2015-02-18 11:12:00 -0800579 }
580
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700581 private List<KindSectionData> getKindSectionDataList(String mimeType) {
Walter Jang192a01c2015-09-22 15:23:55 -0700582 // Put structured names and nicknames together
583 mimeType = Nickname.CONTENT_ITEM_TYPE.equals(mimeType)
584 ? StructuredName.CONTENT_ITEM_TYPE : mimeType;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700585 List<KindSectionData> kindSectionDataList = mKindSectionDataMap.get(mimeType);
586 if (kindSectionDataList == null) {
587 kindSectionDataList = new ArrayList<>();
588 mKindSectionDataMap.put(mimeType, kindSectionDataList);
589 }
590 return kindSectionDataList;
591 }
592
Walter Jang192a01c2015-09-22 15:23:55 -0700593 /** Whether the given RawContactDelta belong to the given account. */
594 private boolean matchesAccount(AccountWithDataSet accountWithDataSet,
595 RawContactDelta rawContactDelta) {
596 if (accountWithDataSet == null) return false;
597 return Objects.equals(accountWithDataSet.name, rawContactDelta.getAccountName())
598 && Objects.equals(accountWithDataSet.type, rawContactDelta.getAccountType())
599 && Objects.equals(accountWithDataSet.dataSet, rawContactDelta.getDataSet());
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700600 }
601
Walter Jang708ea9e2015-09-10 15:42:05 -0700602 private void addAccountInfo() {
603 if (mPrimaryRawContactDelta == null) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700604 mAccountHeaderContainer.setVisibility(View.GONE);
605 mAccountSelectorContainer.setVisibility(View.GONE);
606 return;
607 }
608
609 // Get the account information for the primary raw contact delta
610 final Pair<String,String> accountInfo = EditorUiUtils.getAccountInfo(getContext(),
611 mIsUserProfile, mPrimaryRawContactDelta.getAccountName(),
612 mPrimaryRawContactDelta.getAccountType(mAccountTypeManager));
613
614 // The account header and selector show the same information so both shouldn't be visible
615 // at the same time
616 final List<AccountWithDataSet> accounts =
617 AccountTypeManager.getInstance(getContext()).getAccounts(true);
618 if (mHasNewContact && !mIsUserProfile && accounts.size() > 1) {
619 mAccountHeaderContainer.setVisibility(View.GONE);
620 addAccountSelector(accountInfo);
621 } else {
622 addAccountHeader(accountInfo);
623 mAccountSelectorContainer.setVisibility(View.GONE);
624 }
625 }
626
627 private void addAccountHeader(Pair<String,String> accountInfo) {
Walter Jang03cea2e2015-09-18 17:04:21 -0700628 if (TextUtils.isEmpty(accountInfo.first)) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700629 // Hide this view so the other text view will be centered vertically
630 mAccountHeaderName.setVisibility(View.GONE);
631 } else {
632 mAccountHeaderName.setVisibility(View.VISIBLE);
633 mAccountHeaderName.setText(accountInfo.first);
634 }
635 mAccountHeaderType.setText(accountInfo.second);
636
637 mAccountHeaderContainer.setContentDescription(
638 EditorUiUtils.getAccountInfoContentDescription(
639 accountInfo.first, accountInfo.second));
640 }
641
642 private void addAccountSelector(Pair<String,String> accountInfo) {
643 mAccountSelectorContainer.setVisibility(View.VISIBLE);
644
Walter Jang03cea2e2015-09-18 17:04:21 -0700645 if (TextUtils.isEmpty(accountInfo.first)) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700646 // Hide this view so the other text view will be centered vertically
647 mAccountSelectorName.setVisibility(View.GONE);
648 } else {
649 mAccountSelectorName.setVisibility(View.VISIBLE);
650 mAccountSelectorName.setText(accountInfo.first);
651 }
652 mAccountSelectorType.setText(accountInfo.second);
653
654 mAccountSelectorContainer.setContentDescription(
655 EditorUiUtils.getAccountInfoContentDescription(
656 accountInfo.first, accountInfo.second));
657
658 mAccountSelector.setOnClickListener(new View.OnClickListener() {
659 @Override
660 public void onClick(View v) {
661 final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
662 final AccountsListAdapter adapter =
663 new AccountsListAdapter(getContext(),
664 AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE,
665 mPrimaryAccount);
666 popup.setWidth(mAccountSelectorContainer.getWidth());
667 popup.setAnchorView(mAccountSelectorContainer);
668 popup.setAdapter(adapter);
669 popup.setModal(true);
670 popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
671 popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
672 @Override
673 public void onItemClick(AdapterView<?> parent, View view, int position,
674 long id) {
675 UiClosables.closeQuietly(popup);
676 final AccountWithDataSet newAccount = adapter.getItem(position);
677 if (mListener != null && !mPrimaryAccount.equals(newAccount)) {
678 mListener.onRebindEditorsForNewContact(
679 mPrimaryRawContactDelta,
680 mPrimaryAccount,
681 newAccount);
682 }
683 }
684 });
685 popup.show();
686 }
687 });
688 }
689
Walter Jang363d3fd2015-09-16 10:29:07 -0700690 private void addPhotoView() {
691 // Get the kind section data and values delta that will back the photo view
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700692 Pair<KindSectionData,ValuesDelta> pair = getPrimaryKindSectionData(mPhotoId);
Walter Jang363d3fd2015-09-16 10:29:07 -0700693 if (pair == null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700694 wlog("photo: no kind section data parsed");
Walter Jang363d3fd2015-09-16 10:29:07 -0700695 return;
696 }
697 final KindSectionData kindSectionData = pair.first;
698 final ValuesDelta valuesDelta = pair.second;
Walter Jang06f73a12015-06-17 11:15:48 -0700699
Walter Jang363d3fd2015-09-16 10:29:07 -0700700 // If we're editing a read-only contact we want to display the photo from the
701 // read-only contact in a photo editor backed by the new raw contact
Walter Jang192a01c2015-09-22 15:23:55 -0700702 // that was created.
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700703 if (mHasNewContact) {
704 mPhotoRawContactId = mPrimaryRawContactDelta == null
705 ? null : mPrimaryRawContactDelta.getRawContactId();
Walter Jang363d3fd2015-09-16 10:29:07 -0700706 }
Walter Jang06f73a12015-06-17 11:15:48 -0700707
Walter Jang363d3fd2015-09-16 10:29:07 -0700708 mPhotoRawContactId = kindSectionData.getRawContactDelta().getRawContactId();
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700709 mPhotoView.setValues(kindSectionData.getDataKind(), valuesDelta,
Walter Jang363d3fd2015-09-16 10:29:07 -0700710 kindSectionData.getRawContactDelta(),
711 !kindSectionData.getAccountType().areContactsWritable(), mMaterialPalette,
712 mViewIdGenerator);
713 }
714
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700715 private Pair<KindSectionData,ValuesDelta> getPrimaryKindSectionData(long id) {
716 final String mimeType = Photo.CONTENT_ITEM_TYPE;
Walter Jang363d3fd2015-09-16 10:29:07 -0700717 final List<KindSectionData> kindSectionDataList = mKindSectionDataMap.get(mimeType);
Walter Jang151f3e62015-02-26 15:29:40 -0800718
Walter Jang363d3fd2015-09-16 10:29:07 -0700719 KindSectionData resultKindSectionData = null;
720 ValuesDelta resultValuesDelta = null;
721 if (id > 0) {
722 // Look for a match for the ID that was passed in
723 for (KindSectionData kindSectionData : kindSectionDataList) {
724 resultValuesDelta = kindSectionData.getValuesDeltaById(id);
725 if (resultValuesDelta != null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700726 vlog("photo: matched kind section data by ID");
Walter Jang363d3fd2015-09-16 10:29:07 -0700727 resultKindSectionData = kindSectionData;
728 break;
Walter Jang398cd4b2015-06-16 11:17:53 -0700729 }
730 }
731 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700732 if (resultKindSectionData == null) {
733 // Look for a super primary photo
734 for (KindSectionData kindSectionData : kindSectionDataList) {
735 resultValuesDelta = kindSectionData.getSuperPrimaryValuesDelta();
736 if (resultValuesDelta != null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700737 wlog("photo: matched super primary kind section data");
Walter Jang363d3fd2015-09-16 10:29:07 -0700738 resultKindSectionData = kindSectionData;
739 break;
740 }
Walter Jang151f3e62015-02-26 15:29:40 -0800741 }
742 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700743 if (resultKindSectionData == null) {
744 // Fall back to the first non-empty value
745 for (KindSectionData kindSectionData : kindSectionDataList) {
746 resultValuesDelta = kindSectionData.getFirstNonEmptyValuesDelta();
747 if (resultValuesDelta != null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700748 vlog("photo: using first non empty value");
Walter Jang363d3fd2015-09-16 10:29:07 -0700749 resultKindSectionData = kindSectionData;
750 break;
751 }
Walter Jang151f3e62015-02-26 15:29:40 -0800752 }
753 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700754 if (resultKindSectionData == null || resultValuesDelta == null) {
755 final List<ValuesDelta> valuesDeltaList = kindSectionDataList.get(0).getValuesDeltas();
756 if (valuesDeltaList != null && !valuesDeltaList.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700757 vlog("photo: falling back to first empty entry");
Walter Jang363d3fd2015-09-16 10:29:07 -0700758 resultValuesDelta = valuesDeltaList.get(0);
759 resultKindSectionData = kindSectionDataList.get(0);
Walter Jang10446452015-02-20 13:51:16 -0800760 }
761 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700762 return resultKindSectionData != null && resultValuesDelta != null
763 ? new Pair<>(resultKindSectionData, resultValuesDelta) : null;
Walter Jang10446452015-02-20 13:51:16 -0800764 }
765
Walter Jangf5dfea42015-09-16 12:30:36 -0700766 private void addKindSectionViews() {
767 // Sort the kinds
768 final TreeSet<Map.Entry<String,List<KindSectionData>>> entries =
Walter Jang192a01c2015-09-22 15:23:55 -0700769 new TreeSet<>(KIND_SECTION_DATA_MAP_ENTRY_COMPARATOR);
Walter Jangf5dfea42015-09-16 12:30:36 -0700770 entries.addAll(mKindSectionDataMap.entrySet());
Walter Jang3efae4a2015-02-18 11:12:00 -0800771
Walter Jangf5dfea42015-09-16 12:30:36 -0700772 vlog("kind: " + entries.size() + " kindSection(s)");
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700773 int i = -1;
Walter Jangf5dfea42015-09-16 12:30:36 -0700774 for (Map.Entry<String, List<KindSectionData>> entry : entries) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700775 i++;
776
Walter Jangf5dfea42015-09-16 12:30:36 -0700777 final String mimeType = entry.getKey();
778 final List<KindSectionData> kindSectionDataList = entry.getValue();
Walter Jangab50e6f2015-06-15 08:57:22 -0700779
Walter Jangf5dfea42015-09-16 12:30:36 -0700780 // Ignore mime types that we've already handled
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700781 if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
782 vlog("kind: " + i + " " + mimeType + " dropped");
783 continue;
784 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700785
Walter Jang192a01c2015-09-22 15:23:55 -0700786 if (kindSectionDataList != null && !kindSectionDataList.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700787 vlog("kind: " + i + " " + mimeType + ": " + kindSectionDataList.size() +
788 " kindSectionData(s)");
789
Walter Jangf5dfea42015-09-16 12:30:36 -0700790 final CompactKindSectionView kindSectionView = inflateKindSectionView(
791 mKindSectionViews, kindSectionDataList, mimeType);
Walter Jangf5dfea42015-09-16 12:30:36 -0700792 mKindSectionViews.addView(kindSectionView);
Walter Jangf10ca152015-09-22 15:23:55 -0700793
794 // Keep a pointer to all the KindSectionsViews for each mimeType
795 getKindSectionViews(mimeType).add(kindSectionView);
Walter Jangcab3dce2015-02-09 17:48:03 -0800796 }
797 }
798 }
799
Walter Jangf10ca152015-09-22 15:23:55 -0700800 private List<CompactKindSectionView> getKindSectionViews(String mimeType) {
801 List<CompactKindSectionView> kindSectionViews = mKindSectionViewsMap.get(mimeType);
802 if (kindSectionViews == null) {
803 kindSectionViews = new ArrayList<>();
804 mKindSectionViewsMap.put(mimeType, kindSectionViews);
805 }
806 return kindSectionViews;
807 }
808
Walter Jangf5dfea42015-09-16 12:30:36 -0700809 private CompactKindSectionView inflateKindSectionView(ViewGroup viewGroup,
810 List<KindSectionData> kindSectionDataList, String mimeType) {
811 final CompactKindSectionView kindSectionView = (CompactKindSectionView)
812 mLayoutInflater.inflate(R.layout.compact_item_kind_section, viewGroup,
813 /* attachToRoot =*/ false);
814
Walter Jang192a01c2015-09-22 15:23:55 -0700815 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
Walter Jangf5dfea42015-09-16 12:30:36 -0700816 || Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang192a01c2015-09-22 15:23:55 -0700817 // Phone numbers and email addresses are always displayed,
818 // even if they are empty
Walter Jangf5dfea42015-09-16 12:30:36 -0700819 kindSectionView.setHideWhenEmpty(false);
820 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700821
Walter Jang192a01c2015-09-22 15:23:55 -0700822 // Since phone numbers and email addresses displayed even if they are empty,
823 // they will be the only types you add new values to initially for new contacts
824 kindSectionView.setShowOneEmptyEditor(true);
825
826 // Sort so the editors wind up in the order we want
827 if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
828 Collections.sort(kindSectionDataList, new NameEditorComparator(getContext(),
829 mPrimaryRawContactDelta));
830 } else {
831 Collections.sort(kindSectionDataList, new EditorComparator(getContext()));
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700832 }
833
Walter Jang79658e12015-09-24 10:36:26 -0700834 kindSectionView.setState(kindSectionDataList, mViewIdGenerator, mListener);
Walter Jangf5dfea42015-09-16 12:30:36 -0700835
836 return kindSectionView;
Walter Jangcab3dce2015-02-09 17:48:03 -0800837 }
838
Walter Jang79658e12015-09-24 10:36:26 -0700839 private void showMoreFields() {
840 // Stop hiding empty editors and allow the user to enter values for all kinds now
841 for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
842 final CompactKindSectionView kindSectionView =
843 (CompactKindSectionView) mKindSectionViews.getChildAt(i);
844 kindSectionView.setHideWhenEmpty(false);
845 kindSectionView.updateEmptyEditors(/* shouldAnimate =*/ true);
846 }
847 mIsExpanded = true;
848 }
849
Walter Jangf5dfea42015-09-16 12:30:36 -0700850 private void updateMoreFieldsButton() {
851 // If any kind section views are hidden then show the link
852 for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
853 final CompactKindSectionView kindSectionView =
854 (CompactKindSectionView) mKindSectionViews.getChildAt(i);
855 if (kindSectionView.getVisibility() == View.GONE) {
856 // Show the more fields button
857 mMoreFields.setVisibility(View.VISIBLE);
858 return;
859 }
860 }
861 // Hide the more fields button
862 mMoreFields.setVisibility(View.GONE);
Walter Jangcab3dce2015-02-09 17:48:03 -0800863 }
864
Walter Jangbf63a6d2015-05-05 09:14:35 -0700865 private static void vlog(String message) {
866 if (Log.isLoggable(TAG, Log.VERBOSE)) {
867 Log.v(TAG, message);
Walter Jangcab3dce2015-02-09 17:48:03 -0800868 }
869 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700870
871 private static void wlog(String message) {
872 if (Log.isLoggable(TAG, Log.WARN)) {
873 Log.w(TAG, message);
874 }
875 }
876
877 private static void elog(String message) {
878 Log.e(TAG, message);
879 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800880}