blob: 8e177e42aec6ab5f604f1b15fb4175e74e143f73 [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
Walter Jangcab3dce2015-02-09 17:48:03 -080019import android.content.Context;
Gary Mai65971d02016-09-15 15:00:16 -070020import android.content.res.Resources;
Walter Jangf10ca152015-09-22 15:23:55 -070021import android.database.Cursor;
Gary Mai65971d02016-09-15 15:00:16 -070022import android.graphics.drawable.Drawable;
Walter Jang41b3ea12015-03-09 17:30:06 -070023import android.net.Uri;
Gary Mai5336e6e2016-10-23 14:17:03 -070024import android.os.Bundle;
Walter Jang79658e12015-09-24 10:36:26 -070025import android.os.Parcel;
26import android.os.Parcelable;
Walter Jangcab3dce2015-02-09 17:48:03 -080027import android.provider.ContactsContract.CommonDataKinds.Email;
Walter Jangf5dfea42015-09-16 12:30:36 -070028import android.provider.ContactsContract.CommonDataKinds.Event;
Walter Jangcab3dce2015-02-09 17:48:03 -080029import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
Walter Jangf5dfea42015-09-16 12:30:36 -070030import android.provider.ContactsContract.CommonDataKinds.Im;
Walter Jang3efae4a2015-02-18 11:12:00 -080031import android.provider.ContactsContract.CommonDataKinds.Nickname;
Walter Jangf5dfea42015-09-16 12:30:36 -070032import android.provider.ContactsContract.CommonDataKinds.Note;
33import android.provider.ContactsContract.CommonDataKinds.Organization;
Walter Jangcab3dce2015-02-09 17:48:03 -080034import android.provider.ContactsContract.CommonDataKinds.Phone;
35import android.provider.ContactsContract.CommonDataKinds.Photo;
Walter Jangf5dfea42015-09-16 12:30:36 -070036import android.provider.ContactsContract.CommonDataKinds.Relation;
37import android.provider.ContactsContract.CommonDataKinds.SipAddress;
Walter Jangcab3dce2015-02-09 17:48:03 -080038import android.provider.ContactsContract.CommonDataKinds.StructuredName;
Walter Jangf5dfea42015-09-16 12:30:36 -070039import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
40import android.provider.ContactsContract.CommonDataKinds.Website;
Walter Jangcab3dce2015-02-09 17:48:03 -080041import android.text.TextUtils;
42import android.util.AttributeSet;
43import android.util.Log;
44import android.view.LayoutInflater;
Walter Jangb1c87622015-02-13 17:51:38 -080045import android.view.View;
Walter Jangcab3dce2015-02-09 17:48:03 -080046import android.view.ViewGroup;
Walter Jang708ea9e2015-09-10 15:42:05 -070047import android.widget.AdapterView;
Tingting Wang655ad1a2015-10-05 17:51:14 -070048import android.widget.ImageView;
Walter Jangcab3dce2015-02-09 17:48:03 -080049import android.widget.LinearLayout;
Walter Jang708ea9e2015-09-10 15:42:05 -070050import android.widget.ListPopupWindow;
Walter Jang2d3f31c2015-06-18 23:15:31 -070051import android.widget.TextView;
Walter Jangcab3dce2015-02-09 17:48:03 -080052
Gary Maib6e28d22016-09-12 14:04:53 -070053import com.android.contacts.R;
Gary Mai65971d02016-09-15 15:00:16 -070054import com.android.contacts.common.GeoUtil;
55import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
Gary Maib6e28d22016-09-12 14:04:53 -070056import com.android.contacts.common.model.AccountTypeManager;
57import com.android.contacts.common.model.RawContactDelta;
58import com.android.contacts.common.model.RawContactDeltaList;
59import com.android.contacts.common.model.RawContactModifier;
60import com.android.contacts.common.model.ValuesDelta;
61import com.android.contacts.common.model.account.AccountDisplayInfo;
62import com.android.contacts.common.model.account.AccountDisplayInfoFactory;
63import com.android.contacts.common.model.account.AccountType;
64import com.android.contacts.common.model.account.AccountWithDataSet;
Gary Mai98868d32016-09-14 11:55:04 -070065import com.android.contacts.common.model.dataitem.CustomDataItem;
Gary Maib6e28d22016-09-12 14:04:53 -070066import com.android.contacts.common.model.dataitem.DataKind;
67import com.android.contacts.common.util.AccountsListAdapter;
68import com.android.contacts.common.util.MaterialColorMapUtils;
69import com.android.contacts.util.UiClosables;
70
Walter Jang708774a2015-10-16 09:32:06 -070071import java.io.FileNotFoundException;
Walter Jangcab3dce2015-02-09 17:48:03 -080072import java.util.ArrayList;
Walter Jangf5dfea42015-09-16 12:30:36 -070073import java.util.Arrays;
74import java.util.Comparator;
Walter Jang19d985f2015-07-01 13:36:27 -070075import java.util.HashMap;
Walter Jangcab3dce2015-02-09 17:48:03 -080076import java.util.List;
Walter Jang19d985f2015-07-01 13:36:27 -070077import java.util.Map;
Gary Mai98868d32016-09-14 11:55:04 -070078import java.util.Set;
Walter Jangf5dfea42015-09-16 12:30:36 -070079import java.util.TreeSet;
Walter Jangcab3dce2015-02-09 17:48:03 -080080
81/**
Walter Jangf5dfea42015-09-16 12:30:36 -070082 * View to display information from multiple {@link RawContactDelta}s grouped together.
Walter Jangcab3dce2015-02-09 17:48:03 -080083 */
Gary Mai363af602016-09-28 10:01:23 -070084public class RawContactEditorView extends LinearLayout implements View.OnClickListener {
Walter Jangcab3dce2015-02-09 17:48:03 -080085
Gary Mai363af602016-09-28 10:01:23 -070086 static final String TAG = "RawContactEditorView";
Walter Jangcab3dce2015-02-09 17:48:03 -080087
Walter Jangb6ca2722015-02-20 11:10:25 -080088 /**
Gary Mai363af602016-09-28 10:01:23 -070089 * Callbacks for hosts of {@link RawContactEditorView}s.
Walter Jangb6ca2722015-02-20 11:10:25 -080090 */
91 public interface Listener {
92
93 /**
Walter Jang151f3e62015-02-26 15:29:40 -080094 * Invoked when the structured name editor field has changed.
95 *
96 * @param rawContactId The raw contact ID from the underlying {@link RawContactDelta}.
97 * @param valuesDelta The values from the underlying {@link RawContactDelta}.
98 */
99 public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta);
Walter Jang708ea9e2015-09-10 15:42:05 -0700100
101 /**
Gary Mai363af602016-09-28 10:01:23 -0700102 * Invoked when the editor should rebind editors for a new account.
Walter Jang708ea9e2015-09-10 15:42:05 -0700103 *
104 * @param oldState Old data being edited.
105 * @param oldAccount Old account associated with oldState.
106 * @param newAccount New account to be used.
107 */
108 public void onRebindEditorsForNewContact(RawContactDelta oldState,
109 AccountWithDataSet oldAccount, AccountWithDataSet newAccount);
Walter Jang79658e12015-09-24 10:36:26 -0700110
111 /**
112 * Invoked when no editors could be bound for the contact.
113 */
114 public void onBindEditorsFailed();
Walter Jangd6753152015-10-02 09:23:13 -0700115
116 /**
117 * Invoked after editors have been bound for the contact.
118 */
119 public void onEditorsBound();
Tingting Wang655ad1a2015-10-05 17:51:14 -0700120 }
Walter Jang192a01c2015-09-22 15:23:55 -0700121 /**
122 * Sorts kinds roughly the same as quick contacts; we diverge in the following ways:
123 * <ol>
124 * <li>All names are together at the top.</li>
125 * <li>IM is moved up after addresses</li>
126 * <li>SIP addresses are moved to below phone numbers</li>
Walter Jang79658e12015-09-24 10:36:26 -0700127 * <li>Group membership is placed at the end</li>
Walter Jang192a01c2015-09-22 15:23:55 -0700128 * </ol>
129 */
130 private static final class MimeTypeComparator implements Comparator<String> {
131
Walter Jangf5dfea42015-09-16 12:30:36 -0700132 private static final List<String> MIME_TYPE_ORDER = Arrays.asList(new String[] {
133 StructuredName.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700134 Nickname.CONTENT_ITEM_TYPE,
Walter Jang2ae21752015-09-25 11:25:38 -0700135 Organization.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700136 Phone.CONTENT_ITEM_TYPE,
137 SipAddress.CONTENT_ITEM_TYPE,
138 Email.CONTENT_ITEM_TYPE,
139 StructuredPostal.CONTENT_ITEM_TYPE,
140 Im.CONTENT_ITEM_TYPE,
141 Website.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700142 Event.CONTENT_ITEM_TYPE,
143 Relation.CONTENT_ITEM_TYPE,
Walter Jangf10ca152015-09-22 15:23:55 -0700144 Note.CONTENT_ITEM_TYPE,
145 GroupMembership.CONTENT_ITEM_TYPE
Walter Jangf5dfea42015-09-16 12:30:36 -0700146 });
147
148 @Override
Walter Jang192a01c2015-09-22 15:23:55 -0700149 public int compare(String mimeType1, String mimeType2) {
150 if (mimeType1 == mimeType2) return 0;
151 if (mimeType1 == null) return -1;
152 if (mimeType2 == null) return 1;
Walter Jangf5dfea42015-09-16 12:30:36 -0700153
154 int index1 = MIME_TYPE_ORDER.indexOf(mimeType1);
155 int index2 = MIME_TYPE_ORDER.indexOf(mimeType2);
156
157 // Fallback to alphabetical ordering of the mime type if both are not found
158 if (index1 < 0 && index2 < 0) return mimeType1.compareTo(mimeType2);
159 if (index1 < 0) return 1;
160 if (index2 < 0) return -1;
161
162 return index1 < index2 ? -1 : 1;
163 }
164 }
165
Walter Jang79658e12015-09-24 10:36:26 -0700166 public static class SavedState extends BaseSavedState {
167
168 public static final Parcelable.Creator<SavedState> CREATOR =
169 new Parcelable.Creator<SavedState>() {
170 public SavedState createFromParcel(Parcel in) {
171 return new SavedState(in);
172 }
173 public SavedState[] newArray(int size) {
174 return new SavedState[size];
175 }
176 };
177
178 private boolean mIsExpanded;
179
180 public SavedState(Parcelable superState) {
181 super(superState);
182 }
183
184 private SavedState(Parcel in) {
185 super(in);
186 mIsExpanded = in.readInt() != 0;
187 }
188
189 @Override
190 public void writeToParcel(Parcel out, int flags) {
191 super.writeToParcel(out, flags);
192 out.writeInt(mIsExpanded ? 1 : 0);
193 }
194 }
195
Gary Mai363af602016-09-28 10:01:23 -0700196 private RawContactEditorView.Listener mListener;
Walter Jangb6ca2722015-02-20 11:10:25 -0800197
Walter Jangcab3dce2015-02-09 17:48:03 -0800198 private AccountTypeManager mAccountTypeManager;
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700199 private AccountDisplayInfoFactory mAccountDisplayInfoFactory;
Walter Jangcab3dce2015-02-09 17:48:03 -0800200 private LayoutInflater mLayoutInflater;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800201
Walter Jangcab3dce2015-02-09 17:48:03 -0800202 private ViewIdGenerator mViewIdGenerator;
Walter Jangf46abd82015-02-20 16:52:04 -0800203 private MaterialColorMapUtils.MaterialPalette mMaterialPalette;
Walter Jang708ea9e2015-09-10 15:42:05 -0700204 private boolean mHasNewContact;
205 private boolean mIsUserProfile;
206 private AccountWithDataSet mPrimaryAccount;
Walter Jang9a552372016-08-24 11:51:05 -0700207 private RawContactDeltaList mRawContactDeltas;
Gary Mai4ceabed2016-09-16 12:14:13 -0700208 private RawContactDelta mCurrentRawContactDelta;
Walter Jang9a552372016-08-24 11:51:05 -0700209 private long mRawContactIdToDisplayAlone = -1;
Gary Mai98868d32016-09-14 11:55:04 -0700210 private Map<String, KindSectionData> mKindSectionDataMap = new HashMap<>();
211 private Set<String> mSortedMimetypes = new TreeSet<>(new MimeTypeComparator());
Walter Jangcab3dce2015-02-09 17:48:03 -0800212
Walter Jang708ea9e2015-09-10 15:42:05 -0700213 // Account header
214 private View mAccountHeaderContainer;
Gary Mai079598f2016-11-03 15:02:45 -0700215 private TextView mAccountHeaderPrimaryText;
216 private TextView mAccountHeaderSecondaryText;
Tingting Wang91cee282015-10-07 13:48:17 -0700217 private ImageView mAccountHeaderIcon;
Gary Mai46cb3102016-08-10 18:14:09 -0700218 private ImageView mAccountHeaderExpanderIcon;
Walter Jang708ea9e2015-09-10 15:42:05 -0700219
Gary Mai363af602016-09-28 10:01:23 -0700220 private PhotoEditorView mPhotoView;
Walter Jangf5dfea42015-09-16 12:30:36 -0700221 private ViewGroup mKindSectionViews;
Gary Mai363af602016-09-28 10:01:23 -0700222 private Map<String, KindSectionView> mKindSectionViewMap = new HashMap<>();
Walter Jangb6ca2722015-02-20 11:10:25 -0800223 private View mMoreFields;
Walter Jangcab3dce2015-02-09 17:48:03 -0800224
Walter Jang79658e12015-09-24 10:36:26 -0700225 private boolean mIsExpanded;
Walter Jangcbd431d2015-10-06 13:07:30 -0700226
Gary Mai5336e6e2016-10-23 14:17:03 -0700227 private Bundle mIntentExtras;
228
Walter Jang31a74ad2015-10-02 19:17:39 -0700229 private ValuesDelta mPhotoValuesDelta;
Walter Jang82acd422015-10-17 14:01:27 -0700230
Gary Mai363af602016-09-28 10:01:23 -0700231 public RawContactEditorView(Context context) {
Walter Jangcab3dce2015-02-09 17:48:03 -0800232 super(context);
233 }
234
Gary Mai363af602016-09-28 10:01:23 -0700235 public RawContactEditorView(Context context, AttributeSet attrs) {
Walter Jangcab3dce2015-02-09 17:48:03 -0800236 super(context, attrs);
237 }
238
Walter Jangb6ca2722015-02-20 11:10:25 -0800239 /**
Gary Mai363af602016-09-28 10:01:23 -0700240 * Sets the receiver for {@link RawContactEditorView} callbacks.
Walter Jangb6ca2722015-02-20 11:10:25 -0800241 */
242 public void setListener(Listener listener) {
243 mListener = listener;
244 }
245
Walter Jangcab3dce2015-02-09 17:48:03 -0800246 @Override
247 protected void onFinishInflate() {
248 super.onFinishInflate();
249
250 mAccountTypeManager = AccountTypeManager.getInstance(getContext());
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700251 mAccountDisplayInfoFactory = AccountDisplayInfoFactory.forWritableAccounts(getContext());
Walter Jangcab3dce2015-02-09 17:48:03 -0800252 mLayoutInflater = (LayoutInflater)
253 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
254
Walter Jang708ea9e2015-09-10 15:42:05 -0700255 // Account header
Gary Mai46cb3102016-08-10 18:14:09 -0700256 mAccountHeaderContainer = findViewById(R.id.account_header_container);
Gary Mai079598f2016-11-03 15:02:45 -0700257 mAccountHeaderPrimaryText = (TextView) findViewById(R.id.account_type);
258 mAccountHeaderSecondaryText = (TextView) findViewById(R.id.account_name);
Tingting Wang91cee282015-10-07 13:48:17 -0700259 mAccountHeaderIcon = (ImageView) findViewById(R.id.account_type_icon);
Gary Mai46cb3102016-08-10 18:14:09 -0700260 mAccountHeaderExpanderIcon = (ImageView) findViewById(R.id.account_expander_icon);
Walter Jang708ea9e2015-09-10 15:42:05 -0700261
Gary Mai363af602016-09-28 10:01:23 -0700262 mPhotoView = (PhotoEditorView) findViewById(R.id.photo_editor);
Walter Jangf5dfea42015-09-16 12:30:36 -0700263 mKindSectionViews = (LinearLayout) findViewById(R.id.kind_section_views);
Walter Jangb6ca2722015-02-20 11:10:25 -0800264 mMoreFields = findViewById(R.id.more_fields);
265 mMoreFields.setOnClickListener(this);
266 }
267
Walter Jangb6ca2722015-02-20 11:10:25 -0800268 @Override
269 public void onClick(View view) {
Walter Jangf5dfea42015-09-16 12:30:36 -0700270 if (view.getId() == R.id.more_fields) {
Walter Jangd6753152015-10-02 09:23:13 -0700271 showAllFields();
Walter Jangb6ca2722015-02-20 11:10:25 -0800272 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800273 }
274
275 @Override
276 public void setEnabled(boolean enabled) {
277 super.setEnabled(enabled);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700278 final int childCount = mKindSectionViews.getChildCount();
279 for (int i = 0; i < childCount; i++) {
280 mKindSectionViews.getChildAt(i).setEnabled(enabled);
Walter Jangcab3dce2015-02-09 17:48:03 -0800281 }
282 }
283
Walter Jang79658e12015-09-24 10:36:26 -0700284 @Override
285 public Parcelable onSaveInstanceState() {
286 final Parcelable superState = super.onSaveInstanceState();
287 final SavedState savedState = new SavedState(superState);
288 savedState.mIsExpanded = mIsExpanded;
289 return savedState;
290 }
291
292 @Override
293 public void onRestoreInstanceState(Parcelable state) {
294 if(!(state instanceof SavedState)) {
295 super.onRestoreInstanceState(state);
296 return;
297 }
298 final SavedState savedState = (SavedState) state;
299 super.onRestoreInstanceState(savedState.getSuperState());
300 mIsExpanded = savedState.mIsExpanded;
Walter Jangd6753152015-10-02 09:23:13 -0700301 if (mIsExpanded) {
302 showAllFields();
Walter Jang79658e12015-09-24 10:36:26 -0700303 }
304 }
305
Walter Jang3efae4a2015-02-18 11:12:00 -0800306 /**
Gary Mai363af602016-09-28 10:01:23 -0700307 * Pass through to {@link PhotoEditorView#setListener}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800308 */
Gary Mai363af602016-09-28 10:01:23 -0700309 public void setPhotoListener(PhotoEditorView.Listener listener) {
Walter Jang31a74ad2015-10-02 19:17:39 -0700310 mPhotoView.setListener(listener);
Walter Jang3efae4a2015-02-18 11:12:00 -0800311 }
312
Walter Jang31a74ad2015-10-02 19:17:39 -0700313 public void removePhoto() {
Walter Jang45b86d52015-10-15 15:23:16 -0700314 mPhotoValuesDelta.setFromTemplate(true);
Walter Jang31a74ad2015-10-02 19:17:39 -0700315 mPhotoValuesDelta.put(Photo.PHOTO, (byte[]) null);
Gary Mai18724182016-09-20 17:33:30 -0700316 mPhotoValuesDelta.put(Photo.PHOTO_FILE_ID, (String) null);
Walter Jang31a74ad2015-10-02 19:17:39 -0700317
318 mPhotoView.removePhoto();
Walter Jang3efae4a2015-02-18 11:12:00 -0800319 }
320
321 /**
Gary Mai363af602016-09-28 10:01:23 -0700322 * Pass through to {@link PhotoEditorView#setFullSizedPhoto(Uri)}.
Walter Jang41b3ea12015-03-09 17:30:06 -0700323 */
324 public void setFullSizePhoto(Uri photoUri) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700325 mPhotoView.setFullSizedPhoto(photoUri);
Walter Jang41b3ea12015-03-09 17:30:06 -0700326 }
327
Walter Jang31a74ad2015-10-02 19:17:39 -0700328 public void updatePhoto(Uri photoUri) {
Walter Jang45b86d52015-10-15 15:23:16 -0700329 mPhotoValuesDelta.setFromTemplate(false);
Wenyi Wangb8ab8612015-10-27 11:18:49 -0700330 // Unset primary for all photos
Wenyi Wang9086fb92015-11-16 09:58:20 -0800331 unsetSuperPrimaryFromAllPhotos();
Wenyi Wangb8ab8612015-10-27 11:18:49 -0700332 // Mark the currently displayed photo as primary
333 mPhotoValuesDelta.setSuperPrimary(true);
Walter Jang31a74ad2015-10-02 19:17:39 -0700334
Wenyi Wang4c9cf3a2015-10-15 17:58:23 -0700335 // Even though high-res photos cannot be saved by passing them via
336 // an EntityDeltaList (since they cause the Bundle size limit to be
337 // exceeded), we still pass a low-res thumbnail. This simplifies
338 // code all over the place, because we don't have to test whether
339 // there is a change in EITHER the delta-list OR a changed photo...
340 // this way, there is always a change in the delta-list.
341 try {
342 final byte[] bytes = EditorUiUtils.getCompressedThumbnailBitmapBytes(
343 getContext(), photoUri);
344 if (bytes != null) {
345 mPhotoValuesDelta.setPhoto(bytes);
346 }
347 } catch (FileNotFoundException e) {
348 elog("Failed to get bitmap from photo Uri");
349 }
350
Walter Jang31a74ad2015-10-02 19:17:39 -0700351 mPhotoView.setFullSizedPhoto(photoUri);
352 }
353
Wenyi Wang9086fb92015-11-16 09:58:20 -0800354 private void unsetSuperPrimaryFromAllPhotos() {
Gary Mai4ceabed2016-09-16 12:14:13 -0700355 for (int i = 0; i < mRawContactDeltas.size(); i++) {
356 final RawContactDelta rawContactDelta = mRawContactDeltas.get(i);
357 if (!rawContactDelta.hasMimeEntries(Photo.CONTENT_ITEM_TYPE)) {
358 continue;
359 }
360 final List<ValuesDelta> photosDeltas =
361 mRawContactDeltas.get(i).getMimeEntries(Photo.CONTENT_ITEM_TYPE);
362 if (photosDeltas == null) {
363 continue;
364 }
365 for (int j = 0; j < photosDeltas.size(); j++) {
366 photosDeltas.get(j).setSuperPrimary(false);
Walter Jang3f18d612015-10-07 16:01:05 -0700367 }
368 }
369 }
370
Walter Jang41b3ea12015-03-09 17:30:06 -0700371 /**
Gary Mai363af602016-09-28 10:01:23 -0700372 * Pass through to {@link PhotoEditorView#isWritablePhotoSet}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800373 */
374 public boolean isWritablePhotoSet() {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700375 return mPhotoView.isWritablePhotoSet();
Walter Jang3efae4a2015-02-18 11:12:00 -0800376 }
377
378 /**
Gary Mai363af602016-09-28 10:01:23 -0700379 * Get the raw contact ID for the current photo.
Walter Jang3efae4a2015-02-18 11:12:00 -0800380 */
Walter Jang3efae4a2015-02-18 11:12:00 -0800381 public long getPhotoRawContactId() {
Gary Maida20b472016-09-20 14:46:40 -0700382 return mCurrentRawContactDelta.getRawContactId();
Walter Jang3efae4a2015-02-18 11:12:00 -0800383 }
384
Gary Mai698cee72016-09-19 16:09:54 -0700385 public StructuredNameEditorView getNameEditorView() {
Gary Mai363af602016-09-28 10:01:23 -0700386 final KindSectionView nameKindSectionView = mKindSectionViewMap
Gary Mai698cee72016-09-19 16:09:54 -0700387 .get(StructuredName.CONTENT_ITEM_TYPE);
388 return nameKindSectionView == null
389 ? null : nameKindSectionView.getNameEditorView();
Walter Jang4f5594a2015-10-06 18:40:31 -0700390 }
391
Gary Mai220d10c2016-09-23 13:56:39 -0700392 public RawContactDelta getCurrentRawContactDelta() {
393 return mCurrentRawContactDelta;
394 }
Walter Jang31a74ad2015-10-02 19:17:39 -0700395
396 /**
Gary Maida20b472016-09-20 14:46:40 -0700397 * Marks the raw contact photo given as primary for the aggregate contact.
Walter Jang31a74ad2015-10-02 19:17:39 -0700398 */
Gary Maida20b472016-09-20 14:46:40 -0700399 public void setPrimaryPhoto() {
Walter Jangda258ff2015-11-17 11:06:02 -0800400
401 // Update values delta
Gary Mai4ceabed2016-09-16 12:14:13 -0700402 final ValuesDelta valuesDelta = mCurrentRawContactDelta
403 .getSuperPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
Gary Maida20b472016-09-20 14:46:40 -0700404 if (valuesDelta == null) {
405 Log.wtf(TAG, "setPrimaryPhoto: had no ValuesDelta for the current RawContactDelta");
406 return;
407 }
Walter Jang31a74ad2015-10-02 19:17:39 -0700408 valuesDelta.setFromTemplate(false);
Wenyi Wang9086fb92015-11-16 09:58:20 -0800409 unsetSuperPrimaryFromAllPhotos();
Wenyi Wangb8ab8612015-10-27 11:18:49 -0700410 valuesDelta.setSuperPrimary(true);
Walter Jang31a74ad2015-10-02 19:17:39 -0700411 }
412
Walter Jangd35e5ef2015-02-24 09:18:16 -0800413 public View getAggregationAnchorView() {
Gary Mai698cee72016-09-19 16:09:54 -0700414 final StructuredNameEditorView nameEditorView = getNameEditorView();
Gary Mai710802c2016-09-19 15:05:44 -0700415 return nameEditorView != null ? nameEditorView.findViewById(R.id.anchor_view) : null;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800416 }
417
Walter Jangf10ca152015-09-22 15:23:55 -0700418 public void setGroupMetaData(Cursor groupMetaData) {
Gary Mai363af602016-09-28 10:01:23 -0700419 final KindSectionView groupKindSectionView =
Gary Mai98868d32016-09-14 11:55:04 -0700420 mKindSectionViewMap.get(GroupMembership.CONTENT_ITEM_TYPE);
421 if (groupKindSectionView == null) {
422 return;
423 }
424 groupKindSectionView.setGroupMetaData(groupMetaData);
425 if (mIsExpanded) {
426 groupKindSectionView.setHideWhenEmpty(false);
427 groupKindSectionView.updateEmptyEditors(/* shouldAnimate =*/ true);
Walter Jangf10ca152015-09-22 15:23:55 -0700428 }
429 }
430
Gary Mai5336e6e2016-10-23 14:17:03 -0700431 public void setIntentExtras(Bundle extras) {
432 mIntentExtras = extras;
433 }
434
Walter Jangf46abd82015-02-20 16:52:04 -0800435 public void setState(RawContactDeltaList rawContactDeltas,
Walter Jang06f73a12015-06-17 11:15:48 -0700436 MaterialColorMapUtils.MaterialPalette materialPalette, ViewIdGenerator viewIdGenerator,
Gary Maida20b472016-09-20 14:46:40 -0700437 boolean hasNewContact, boolean isUserProfile, AccountWithDataSet primaryAccount,
Gary Mai5a00de32016-10-19 18:20:41 -0700438 long rawContactIdToDisplayAlone) {
Marcus Hagerottf04c9752016-09-08 15:22:57 -0700439
Walter Jang9a552372016-08-24 11:51:05 -0700440 mRawContactDeltas = rawContactDeltas;
441 mRawContactIdToDisplayAlone = rawContactIdToDisplayAlone;
Walter Jang9a552372016-08-24 11:51:05 -0700442
Gary Mai98868d32016-09-14 11:55:04 -0700443 mKindSectionViewMap.clear();
Walter Jangf5dfea42015-09-16 12:30:36 -0700444 mKindSectionViews.removeAllViews();
Walter Jang363d3fd2015-09-16 10:29:07 -0700445 mMoreFields.setVisibility(View.VISIBLE);
Walter Jangcab3dce2015-02-09 17:48:03 -0800446
Walter Jangf46abd82015-02-20 16:52:04 -0800447 mMaterialPalette = materialPalette;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700448 mViewIdGenerator = viewIdGenerator;
Tingting Wangf695eb32015-10-15 18:45:15 -0700449
Walter Jang708ea9e2015-09-10 15:42:05 -0700450 mHasNewContact = hasNewContact;
451 mIsUserProfile = isUserProfile;
452 mPrimaryAccount = primaryAccount;
453 if (mPrimaryAccount == null) {
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700454 mPrimaryAccount = ContactEditorUtils.create(getContext()).getOnlyOrDefaultAccount();
Walter Jang708ea9e2015-09-10 15:42:05 -0700455 }
456 vlog("state: primary " + mPrimaryAccount);
Walter Jangcab3dce2015-02-09 17:48:03 -0800457
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700458 // Parse the given raw contact deltas
459 if (rawContactDeltas == null || rawContactDeltas.isEmpty()) {
460 elog("No raw contact deltas");
Walter Jang79658e12015-09-24 10:36:26 -0700461 if (mListener != null) mListener.onBindEditorsFailed();
Walter Jangf5dfea42015-09-16 12:30:36 -0700462 return;
463 }
Gary Mai4ceabed2016-09-16 12:14:13 -0700464 pickRawContactDelta();
Gary Mai5336e6e2016-10-23 14:17:03 -0700465 // Apply any intent extras now that we have selected a raw contact delta.
466 applyIntentExtras();
Gary Mai4ceabed2016-09-16 12:14:13 -0700467 parseRawContactDelta();
Walter Jang79658e12015-09-24 10:36:26 -0700468 if (mKindSectionDataMap.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700469 elog("No kind section data parsed from RawContactDelta(s)");
Walter Jang79658e12015-09-24 10:36:26 -0700470 if (mListener != null) mListener.onBindEditorsFailed();
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700471 return;
472 }
Walter Jang82acd422015-10-17 14:01:27 -0700473
Gary Mai98868d32016-09-14 11:55:04 -0700474 final KindSectionData nameSectionData =
475 mKindSectionDataMap.get(StructuredName.CONTENT_ITEM_TYPE);
476 // Ensure that a structured name and photo exists
477 if (nameSectionData != null) {
Walter Jang82acd422015-10-17 14:01:27 -0700478 final RawContactDelta rawContactDelta =
Gary Mai98868d32016-09-14 11:55:04 -0700479 nameSectionData.getRawContactDelta();
Walter Jang82acd422015-10-17 14:01:27 -0700480 RawContactModifier.ensureKindExists(
481 rawContactDelta,
482 rawContactDelta.getAccountType(mAccountTypeManager),
Walter Jangcbd431d2015-10-06 13:07:30 -0700483 StructuredName.CONTENT_ITEM_TYPE);
Walter Jang82acd422015-10-17 14:01:27 -0700484 RawContactModifier.ensureKindExists(
485 rawContactDelta,
486 rawContactDelta.getAccountType(mAccountTypeManager),
Walter Jangcbd431d2015-10-06 13:07:30 -0700487 Photo.CONTENT_ITEM_TYPE);
488 }
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700489
490 // Setup the view
Walter Jang363d3fd2015-09-16 10:29:07 -0700491 addPhotoView();
Gary Mai079598f2016-11-03 15:02:45 -0700492 setAccountInfo();
Gary Mai4ceabed2016-09-16 12:14:13 -0700493 if (isReadOnlyRawContact()) {
Walter Jang9a552372016-08-24 11:51:05 -0700494 // We're want to display the inputs fields for a single read only raw contact
495 addReadOnlyRawContactEditorViews();
Walter Jang9a552372016-08-24 11:51:05 -0700496 } else {
Gary Mai363af602016-09-28 10:01:23 -0700497 setupEditorNormally();
Walter Jang9a552372016-08-24 11:51:05 -0700498 }
Walter Jangd6753152015-10-02 09:23:13 -0700499 if (mListener != null) mListener.onEditorsBound();
Walter Jangcab3dce2015-02-09 17:48:03 -0800500 }
501
Gary Mai363af602016-09-28 10:01:23 -0700502 private void setupEditorNormally() {
Walter Jang9a552372016-08-24 11:51:05 -0700503 addKindSectionViews();
Walter Jangcab3dce2015-02-09 17:48:03 -0800504
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700505 mMoreFields.setVisibility(hasMoreFields() ? View.VISIBLE : View.GONE);
506
Walter Jang9a552372016-08-24 11:51:05 -0700507 if (mIsExpanded) showAllFields();
508 }
509
Gary Mai4ceabed2016-09-16 12:14:13 -0700510 private boolean isReadOnlyRawContact() {
511 return !mCurrentRawContactDelta.getAccountType(mAccountTypeManager).areContactsWritable();
Walter Jang9a552372016-08-24 11:51:05 -0700512 }
513
Gary Mai4ceabed2016-09-16 12:14:13 -0700514 private void pickRawContactDelta() {
Gary Mai4ceabed2016-09-16 12:14:13 -0700515 vlog("parse: " + mRawContactDeltas.size() + " rawContactDelta(s)");
516 for (int j = 0; j < mRawContactDeltas.size(); j++) {
517 final RawContactDelta rawContactDelta = mRawContactDeltas.get(j);
Walter Jang192a01c2015-09-22 15:23:55 -0700518 vlog("parse: " + j + " rawContactDelta" + rawContactDelta);
Walter Jang363d3fd2015-09-16 10:29:07 -0700519 if (rawContactDelta == null || !rawContactDelta.isVisible()) continue;
Walter Jangcab3dce2015-02-09 17:48:03 -0800520 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
Walter Jang363d3fd2015-09-16 10:29:07 -0700521 if (accountType == null) continue;
Gary Mai4ceabed2016-09-16 12:14:13 -0700522
523 if (mRawContactIdToDisplayAlone > 0) {
524 // Look for the raw contact if specified.
525 if (rawContactDelta.getRawContactId().equals(mRawContactIdToDisplayAlone)) {
526 mCurrentRawContactDelta = rawContactDelta;
527 return;
Walter Jang192a01c2015-09-22 15:23:55 -0700528 }
Gary Mai4ceabed2016-09-16 12:14:13 -0700529 } else if (mPrimaryAccount != null
530 && mPrimaryAccount.equals(rawContactDelta.getAccountWithDataSet())) {
531 // Otherwise try to find the one that matches the default.
532 mCurrentRawContactDelta = rawContactDelta;
533 return;
534 } else if (accountType.areContactsWritable()){
535 // TODO: Find better raw contact delta
536 // Just select an arbitrary writable contact.
537 mCurrentRawContactDelta = rawContactDelta;
Walter Jangac679af2015-06-01 12:17:06 -0700538 }
539 }
Gary Mai4ceabed2016-09-16 12:14:13 -0700540
541 }
542
Gary Mai5336e6e2016-10-23 14:17:03 -0700543 private void applyIntentExtras() {
544 if (mIntentExtras == null || mIntentExtras.size() == 0) {
545 return;
546 }
547 final AccountTypeManager accountTypes = AccountTypeManager.getInstance(getContext());
548 final AccountType type = mCurrentRawContactDelta.getAccountType(accountTypes);
549
550 RawContactModifier.parseExtras(getContext(), type, mCurrentRawContactDelta, mIntentExtras);
551 mIntentExtras = null;
552 }
553
Gary Mai4ceabed2016-09-16 12:14:13 -0700554 private void parseRawContactDelta() {
555 mKindSectionDataMap.clear();
556 mSortedMimetypes.clear();
557
558 final AccountType accountType = mCurrentRawContactDelta.getAccountType(mAccountTypeManager);
559 final List<DataKind> dataKinds = accountType.getSortedDataKinds();
560 final int dataKindSize = dataKinds == null ? 0 : dataKinds.size();
561 vlog("parse: " + dataKindSize + " dataKinds(s)");
562
563 for (int i = 0; i < dataKindSize; i++) {
564 final DataKind dataKind = dataKinds.get(i);
Gary Maid7faa652016-10-03 11:53:39 -0700565 // Skip null and un-editable fields.
566 if (dataKind == null || !dataKind.editable) {
567 vlog("parse: " + i +
568 (dataKind == null ? " dropped null data kind"
569 : " dropped uneditable mimetype: " + dataKind.mimeType));
Gary Mai4ceabed2016-09-16 12:14:13 -0700570 continue;
571 }
572 final String mimeType = dataKind.mimeType;
573
574 // Skip psuedo mime types
Gary Maiac5bd642016-10-12 10:31:36 -0700575 if (DataKind.PSEUDO_MIME_TYPE_NAME.equals(mimeType) ||
576 DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
Gary Mai4ceabed2016-09-16 12:14:13 -0700577 vlog("parse: " + i + " " + dataKind.mimeType + " dropped pseudo type");
578 continue;
579 }
580
581 // Skip custom fields
582 // TODO: Handle them when we implement editing custom fields.
583 if (CustomDataItem.MIMETYPE_CUSTOM_FIELD.equals(mimeType)) {
584 vlog("parse: " + i + " " + dataKind.mimeType + " dropped custom field");
585 continue;
586 }
587
588 final KindSectionData kindSectionData =
589 new KindSectionData(accountType, dataKind, mCurrentRawContactDelta);
590 mKindSectionDataMap.put(mimeType, kindSectionData);
591 mSortedMimetypes.add(mimeType);
592
593 vlog("parse: " + i + " " + dataKind.mimeType + " " +
594 kindSectionData.getValuesDeltas().size() + " value(s) " +
595 kindSectionData.getNonEmptyValuesDeltas().size() + " non-empty value(s) " +
596 kindSectionData.getVisibleValuesDeltas().size() +
597 " visible value(s)");
598 }
Walter Jang3efae4a2015-02-18 11:12:00 -0800599 }
600
Walter Jang9a552372016-08-24 11:51:05 -0700601 private void addReadOnlyRawContactEditorViews() {
Gary Mai65971d02016-09-15 15:00:16 -0700602 mKindSectionViews.removeAllViews();
Walter Jang9a552372016-08-24 11:51:05 -0700603 final AccountTypeManager accountTypes = AccountTypeManager.getInstance(
604 getContext());
Gary Mai4ceabed2016-09-16 12:14:13 -0700605 final AccountType type = mCurrentRawContactDelta.getAccountType(accountTypes);
Walter Jang9a552372016-08-24 11:51:05 -0700606
Gary Mai65971d02016-09-15 15:00:16 -0700607 // Bail if invalid state or source
Gary Mai4ceabed2016-09-16 12:14:13 -0700608 if (type == null) return;
Walter Jang9a552372016-08-24 11:51:05 -0700609
Gary Mai65971d02016-09-15 15:00:16 -0700610 // Make sure we have StructuredName
Gary Mai4ceabed2016-09-16 12:14:13 -0700611 RawContactModifier.ensureKindExists(
612 mCurrentRawContactDelta, type, StructuredName.CONTENT_ITEM_TYPE);
Gary Mai65971d02016-09-15 15:00:16 -0700613
614 ValuesDelta primary;
615
616 // Name
617 final Context context = getContext();
618 final Resources res = context.getResources();
Gary Mai4ceabed2016-09-16 12:14:13 -0700619 primary = mCurrentRawContactDelta.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
Gary Mai65971d02016-09-15 15:00:16 -0700620 final String name = primary != null ? primary.getAsString(StructuredName.DISPLAY_NAME) :
621 getContext().getString(R.string.missing_name);
622 final Drawable nameDrawable = context.getDrawable(R.drawable.ic_person_24dp);
623 final String nameContentDescription = res.getString(R.string.header_name_entry);
624 bindData(nameDrawable, nameContentDescription, name, /* type */ null,
625 /* isFirstEntry */ true);
626
627 // Phones
Gary Mai4ceabed2016-09-16 12:14:13 -0700628 final ArrayList<ValuesDelta> phones = mCurrentRawContactDelta
629 .getMimeEntries(Phone.CONTENT_ITEM_TYPE);
Gary Mai65971d02016-09-15 15:00:16 -0700630 final Drawable phoneDrawable = context.getDrawable(R.drawable.ic_phone_24dp);
631 final String phoneContentDescription = res.getString(R.string.header_phone_entry);
632 if (phones != null) {
633 boolean isFirstPhoneBound = true;
634 for (ValuesDelta phone : phones) {
635 final String phoneNumber = phone.getPhoneNumber();
636 if (TextUtils.isEmpty(phoneNumber)) {
637 continue;
638 }
639 final String formattedNumber = PhoneNumberUtilsCompat.formatNumber(
640 phoneNumber, phone.getPhoneNormalizedNumber(),
641 GeoUtil.getCurrentCountryIso(getContext()));
642 CharSequence phoneType = null;
643 if (phone.hasPhoneType()) {
644 phoneType = Phone.getTypeLabel(
645 res, phone.getPhoneType(), phone.getPhoneLabel());
646 }
647 bindData(phoneDrawable, phoneContentDescription, formattedNumber, phoneType,
648 isFirstPhoneBound, true);
649 isFirstPhoneBound = false;
650 }
651 }
652
653 // Emails
Gary Mai4ceabed2016-09-16 12:14:13 -0700654 final ArrayList<ValuesDelta> emails = mCurrentRawContactDelta
655 .getMimeEntries(Email.CONTENT_ITEM_TYPE);
Gary Mai65971d02016-09-15 15:00:16 -0700656 final Drawable emailDrawable = context.getDrawable(R.drawable.ic_email_24dp);
657 final String emailContentDescription = res.getString(R.string.header_email_entry);
658 if (emails != null) {
659 boolean isFirstEmailBound = true;
660 for (ValuesDelta email : emails) {
661 final String emailAddress = email.getEmailData();
662 if (TextUtils.isEmpty(emailAddress)) {
663 continue;
664 }
665 CharSequence emailType = null;
666 if (email.hasEmailType()) {
667 emailType = Email.getTypeLabel(
668 res, email.getEmailType(), email.getEmailLabel());
669 }
670 bindData(emailDrawable, emailContentDescription, emailAddress, emailType,
671 isFirstEmailBound);
672 isFirstEmailBound = false;
673 }
674 }
675
676 mKindSectionViews.setVisibility(mKindSectionViews.getChildCount() > 0 ? VISIBLE : GONE);
677 // Hide the "More fields" link
678 mMoreFields.setVisibility(GONE);
679 }
680
Gary Mai65971d02016-09-15 15:00:16 -0700681 private void bindData(Drawable icon, String iconContentDescription, CharSequence data,
682 CharSequence type, boolean isFirstEntry) {
683 bindData(icon, iconContentDescription, data, type, isFirstEntry, false);
684 }
685
686 private void bindData(Drawable icon, String iconContentDescription, CharSequence data,
687 CharSequence type, boolean isFirstEntry, boolean forceLTR) {
Gary Mai34047d22016-11-17 10:36:59 -0800688 final View field = mLayoutInflater.inflate(R.layout.item_read_only_field, mKindSectionViews,
689 /* attachToRoot */ false);
Gary Mai65971d02016-09-15 15:00:16 -0700690 if (isFirstEntry) {
691 final ImageView imageView = (ImageView) field.findViewById(R.id.kind_icon);
692 imageView.setImageDrawable(icon);
693 imageView.setContentDescription(iconContentDescription);
694 } else {
695 final ImageView imageView = (ImageView) field.findViewById(R.id.kind_icon);
696 imageView.setVisibility(View.INVISIBLE);
697 imageView.setContentDescription(null);
698 }
699 final TextView dataView = (TextView) field.findViewById(R.id.data);
700 dataView.setText(data);
701 if (forceLTR) {
702 dataView.setTextDirection(View.TEXT_DIRECTION_LTR);
703 }
704 final TextView typeView = (TextView) field.findViewById(R.id.type);
705 if (!TextUtils.isEmpty(type)) {
706 typeView.setText(type);
707 } else {
708 typeView.setVisibility(View.GONE);
709 }
710 mKindSectionViews.addView(field);
Walter Jang9a552372016-08-24 11:51:05 -0700711 }
712
Gary Mai079598f2016-11-03 15:02:45 -0700713 private void setAccountInfo() {
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700714 final AccountDisplayInfo account =
Gary Mai4ceabed2016-09-16 12:14:13 -0700715 mAccountDisplayInfoFactory.getAccountDisplayInfoFor(mCurrentRawContactDelta);
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700716
Walter Jang708ea9e2015-09-10 15:42:05 -0700717 // Get the account information for the primary raw contact delta
Gary Mai079598f2016-11-03 15:02:45 -0700718 if (isReadOnlyRawContact()) {
719 final String accountType = account.getTypeLabel().toString();
720 setAccountHeader(accountType,
721 getResources().getString(
722 R.string.editor_account_selector_read_only_title, accountType));
723 } else {
724 final String accountLabel = mIsUserProfile
725 ? EditorUiUtils.getAccountHeaderLabelForMyProfile(getContext(), account)
726 : account.getNameLabel().toString();
727 setAccountHeader(getResources().getString(R.string.editor_account_selector_title),
728 accountLabel);
729 }
Gary Maid7faa652016-10-03 11:53:39 -0700730
731 // If we're saving a new contact and there are multiple accounts, add the account selector.
Walter Jang708ea9e2015-09-10 15:42:05 -0700732 final List<AccountWithDataSet> accounts =
733 AccountTypeManager.getInstance(getContext()).getAccounts(true);
Gary Maid7faa652016-10-03 11:53:39 -0700734 if (mHasNewContact && !mIsUserProfile && accounts.size() > 1) {
735 addAccountSelector(mCurrentRawContactDelta);
Walter Jang23709542015-10-22 12:50:58 -0700736 }
Walter Jang708ea9e2015-09-10 15:42:05 -0700737 }
738
Gary Mai079598f2016-11-03 15:02:45 -0700739 private void setAccountHeader(String primaryText, String secondaryText) {
740 mAccountHeaderPrimaryText.setText(primaryText);
741 mAccountHeaderSecondaryText.setText(secondaryText);
Walter Jangbe5e1b12015-10-17 11:38:29 -0700742
743 // Set the icon
Gary Mai4ceabed2016-09-16 12:14:13 -0700744 final AccountType accountType =
745 mCurrentRawContactDelta.getRawContactAccountType(getContext());
746 mAccountHeaderIcon.setImageDrawable(accountType.getDisplayIcon(getContext()));
Walter Jangbe5e1b12015-10-17 11:38:29 -0700747
748 // Set the content description
749 mAccountHeaderContainer.setContentDescription(
Gary Mai34047d22016-11-17 10:36:59 -0800750 EditorUiUtils.getAccountInfoContentDescription(secondaryText, primaryText));
Walter Jangbe5e1b12015-10-17 11:38:29 -0700751 }
752
Gary Maid7faa652016-10-03 11:53:39 -0700753 private void addAccountSelector(final RawContactDelta rawContactDelta) {
754 // Add handlers for choosing another account to save to.
755 mAccountHeaderExpanderIcon.setVisibility(View.VISIBLE);
756 mAccountHeaderContainer.setOnClickListener(new View.OnClickListener() {
Walter Jang708ea9e2015-09-10 15:42:05 -0700757 @Override
758 public void onClick(View v) {
759 final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
760 final AccountsListAdapter adapter =
761 new AccountsListAdapter(getContext(),
762 AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE,
763 mPrimaryAccount);
Gary Mai46cb3102016-08-10 18:14:09 -0700764 popup.setWidth(mAccountHeaderContainer.getWidth());
765 popup.setAnchorView(mAccountHeaderContainer);
Walter Jang708ea9e2015-09-10 15:42:05 -0700766 popup.setAdapter(adapter);
767 popup.setModal(true);
768 popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
769 popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
770 @Override
771 public void onItemClick(AdapterView<?> parent, View view, int position,
772 long id) {
773 UiClosables.closeQuietly(popup);
774 final AccountWithDataSet newAccount = adapter.getItem(position);
775 if (mListener != null && !mPrimaryAccount.equals(newAccount)) {
Gary Mai4ceabed2016-09-16 12:14:13 -0700776 mIsExpanded = false;
Walter Jang708ea9e2015-09-10 15:42:05 -0700777 mListener.onRebindEditorsForNewContact(
Walter Jang82acd422015-10-17 14:01:27 -0700778 rawContactDelta,
Walter Jang708ea9e2015-09-10 15:42:05 -0700779 mPrimaryAccount,
780 newAccount);
781 }
782 }
783 });
784 popup.show();
785 }
Gary Maid7faa652016-10-03 11:53:39 -0700786 });
Tingting Wang655ad1a2015-10-05 17:51:14 -0700787 }
788
Walter Jang363d3fd2015-09-16 10:29:07 -0700789 private void addPhotoView() {
Gary Mai4ceabed2016-09-16 12:14:13 -0700790 if (!mCurrentRawContactDelta.hasMimeEntries(Photo.CONTENT_ITEM_TYPE)) {
791 wlog("No photo mimetype for this raw contact.");
Gary Maida20b472016-09-20 14:46:40 -0700792 mPhotoView.setVisibility(GONE);
Walter Jang363d3fd2015-09-16 10:29:07 -0700793 return;
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700794 } else {
Gary Maida20b472016-09-20 14:46:40 -0700795 mPhotoView.setVisibility(VISIBLE);
Walter Jang363d3fd2015-09-16 10:29:07 -0700796 }
Walter Jang06f73a12015-06-17 11:15:48 -0700797
Gary Mai4ceabed2016-09-16 12:14:13 -0700798 final ValuesDelta superPrimaryDelta = mCurrentRawContactDelta
799 .getSuperPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
Gary Maida20b472016-09-20 14:46:40 -0700800 if (superPrimaryDelta == null) {
801 Log.wtf(TAG, "addPhotoView: no ValueDelta found for current RawContactDelta"
802 + "that supports a photo.");
803 mPhotoView.setVisibility(GONE);
804 return;
805 }
Walter Jang31a74ad2015-10-02 19:17:39 -0700806 // Set the photo view
Gary Mai18724182016-09-20 17:33:30 -0700807 mPhotoView.setPalette(mMaterialPalette);
808 mPhotoView.setPhoto(superPrimaryDelta);
Walter Jang31a74ad2015-10-02 19:17:39 -0700809
Gary Mai4ceabed2016-09-16 12:14:13 -0700810 if (isReadOnlyRawContact()) {
Walter Jang31a74ad2015-10-02 19:17:39 -0700811 mPhotoView.setReadOnly(true);
812 return;
813 }
Walter Jang31a74ad2015-10-02 19:17:39 -0700814 mPhotoView.setReadOnly(false);
Gary Mai4ceabed2016-09-16 12:14:13 -0700815 mPhotoValuesDelta = superPrimaryDelta;
Walter Jang31a74ad2015-10-02 19:17:39 -0700816 }
817
Walter Jangf5dfea42015-09-16 12:30:36 -0700818 private void addKindSectionViews() {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700819 int i = -1;
Gary Mai98868d32016-09-14 11:55:04 -0700820
821 for (String mimeType : mSortedMimetypes) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700822 i++;
Gary Mai4ceabed2016-09-16 12:14:13 -0700823 // Ignore mime types that we've already handled
824 if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
825 vlog("kind: " + i + " " + mimeType + " dropped");
826 continue;
Walter Jangcab3dce2015-02-09 17:48:03 -0800827 }
Gary Mai363af602016-09-28 10:01:23 -0700828 final KindSectionView kindSectionView;
Gary Mai4ceabed2016-09-16 12:14:13 -0700829 final KindSectionData kindSectionData = mKindSectionDataMap.get(mimeType);
Gary Mai698cee72016-09-19 16:09:54 -0700830 kindSectionView = inflateKindSectionView(mKindSectionViews, kindSectionData, mimeType);
Gary Mai98868d32016-09-14 11:55:04 -0700831 mKindSectionViews.addView(kindSectionView);
Walter Jangcab3dce2015-02-09 17:48:03 -0800832
Gary Mai98868d32016-09-14 11:55:04 -0700833 // Keep a pointer to the KindSectionView for each mimeType
834 mKindSectionViewMap.put(mimeType, kindSectionView);
Walter Jangf10ca152015-09-22 15:23:55 -0700835 }
Walter Jangf10ca152015-09-22 15:23:55 -0700836 }
837
Gary Mai363af602016-09-28 10:01:23 -0700838 private KindSectionView inflateKindSectionView(ViewGroup viewGroup,
Gary Mai698cee72016-09-19 16:09:54 -0700839 KindSectionData kindSectionData, String mimeType) {
Gary Mai363af602016-09-28 10:01:23 -0700840 final KindSectionView kindSectionView = (KindSectionView)
841 mLayoutInflater.inflate(R.layout.item_kind_section, viewGroup,
Walter Jangf5dfea42015-09-16 12:30:36 -0700842 /* attachToRoot =*/ false);
Walter Jang45b86d52015-10-15 15:23:16 -0700843 kindSectionView.setIsUserProfile(mIsUserProfile);
Walter Jangf5dfea42015-09-16 12:30:36 -0700844
Walter Jang192a01c2015-09-22 15:23:55 -0700845 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
Walter Jangf5dfea42015-09-16 12:30:36 -0700846 || Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang192a01c2015-09-22 15:23:55 -0700847 // Phone numbers and email addresses are always displayed,
848 // even if they are empty
Walter Jangf5dfea42015-09-16 12:30:36 -0700849 kindSectionView.setHideWhenEmpty(false);
850 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700851
Walter Jang192a01c2015-09-22 15:23:55 -0700852 // Since phone numbers and email addresses displayed even if they are empty,
853 // they will be the only types you add new values to initially for new contacts
854 kindSectionView.setShowOneEmptyEditor(true);
855
Gary Mai698cee72016-09-19 16:09:54 -0700856 kindSectionView.setState(kindSectionData, mViewIdGenerator, mListener);
Walter Jangf5dfea42015-09-16 12:30:36 -0700857
858 return kindSectionView;
Walter Jangcab3dce2015-02-09 17:48:03 -0800859 }
860
Walter Jangd6753152015-10-02 09:23:13 -0700861 private void showAllFields() {
Walter Jang79658e12015-09-24 10:36:26 -0700862 // Stop hiding empty editors and allow the user to enter values for all kinds now
863 for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
Gary Mai363af602016-09-28 10:01:23 -0700864 final KindSectionView kindSectionView =
865 (KindSectionView) mKindSectionViews.getChildAt(i);
Walter Jang79658e12015-09-24 10:36:26 -0700866 kindSectionView.setHideWhenEmpty(false);
867 kindSectionView.updateEmptyEditors(/* shouldAnimate =*/ true);
868 }
869 mIsExpanded = true;
Walter Jang79658e12015-09-24 10:36:26 -0700870
Walter Jangf5dfea42015-09-16 12:30:36 -0700871 // Hide the more fields button
872 mMoreFields.setVisibility(View.GONE);
Walter Jangcab3dce2015-02-09 17:48:03 -0800873 }
874
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700875 private boolean hasMoreFields() {
Gary Mai363af602016-09-28 10:01:23 -0700876 for (KindSectionView section : mKindSectionViewMap.values()) {
Gary Mai98868d32016-09-14 11:55:04 -0700877 if (section.getVisibility() != View.VISIBLE) {
878 return true;
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700879 }
880 }
881 return false;
882 }
883
Walter Jangbf63a6d2015-05-05 09:14:35 -0700884 private static void vlog(String message) {
885 if (Log.isLoggable(TAG, Log.VERBOSE)) {
886 Log.v(TAG, message);
Walter Jangcab3dce2015-02-09 17:48:03 -0800887 }
888 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700889
890 private static void wlog(String message) {
891 if (Log.isLoggable(TAG, Log.WARN)) {
892 Log.w(TAG, message);
893 }
894 }
895
896 private static void elog(String message) {
897 Log.e(TAG, message);
898 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800899}