blob: bdf329debe93f20941b5e7a669481cbba0af5969 [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
Marcus Hagerottfac695a2016-08-24 17:02:40 -070019import com.android.contacts.common.model.account.AccountDisplayInfo;
20import com.android.contacts.common.model.account.AccountDisplayInfoFactory;
Walter Jangcab3dce2015-02-09 17:48:03 -080021import com.android.contacts.R;
22import com.android.contacts.common.model.AccountTypeManager;
23import com.android.contacts.common.model.RawContactDelta;
24import com.android.contacts.common.model.RawContactDeltaList;
Walter Jange720fde2015-02-17 10:54:14 -080025import com.android.contacts.common.model.RawContactModifier;
Walter Jangcab3dce2015-02-09 17:48:03 -080026import com.android.contacts.common.model.ValuesDelta;
27import com.android.contacts.common.model.account.AccountType;
Walter Jang2d3f31c2015-06-18 23:15:31 -070028import com.android.contacts.common.model.account.AccountWithDataSet;
Walter Jangcab3dce2015-02-09 17:48:03 -080029import com.android.contacts.common.model.dataitem.DataKind;
Walter Jang708ea9e2015-09-10 15:42:05 -070030import com.android.contacts.common.util.AccountsListAdapter;
Walter Jangf46abd82015-02-20 16:52:04 -080031import com.android.contacts.common.util.MaterialColorMapUtils;
Walter Jang708ea9e2015-09-10 15:42:05 -070032import com.android.contacts.util.UiClosables;
Walter Jangcab3dce2015-02-09 17:48:03 -080033
Marcus Hagerottcf7f2952016-09-06 13:49:17 -070034import android.animation.LayoutTransition;
Tingting Wang655ad1a2015-10-05 17:51:14 -070035import android.content.ContentUris;
Walter Jangcab3dce2015-02-09 17:48:03 -080036import android.content.Context;
Walter Jangf10ca152015-09-22 15:23:55 -070037import android.database.Cursor;
Walter Jang3efae4a2015-02-18 11:12:00 -080038import android.graphics.Bitmap;
Walter Jang41b3ea12015-03-09 17:30:06 -070039import android.net.Uri;
Walter Jang3f18d612015-10-07 16:01:05 -070040import android.os.Bundle;
Walter Jang79658e12015-09-24 10:36:26 -070041import android.os.Parcel;
42import android.os.Parcelable;
Tingting Wang655ad1a2015-10-05 17:51:14 -070043import android.provider.ContactsContract;
Walter Jangcab3dce2015-02-09 17:48:03 -080044import android.provider.ContactsContract.CommonDataKinds.Email;
Walter Jangf5dfea42015-09-16 12:30:36 -070045import android.provider.ContactsContract.CommonDataKinds.Event;
Walter Jangcab3dce2015-02-09 17:48:03 -080046import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
Walter Jangf5dfea42015-09-16 12:30:36 -070047import android.provider.ContactsContract.CommonDataKinds.Im;
Walter Jang3efae4a2015-02-18 11:12:00 -080048import android.provider.ContactsContract.CommonDataKinds.Nickname;
Walter Jangf5dfea42015-09-16 12:30:36 -070049import android.provider.ContactsContract.CommonDataKinds.Note;
50import android.provider.ContactsContract.CommonDataKinds.Organization;
Walter Jangcab3dce2015-02-09 17:48:03 -080051import android.provider.ContactsContract.CommonDataKinds.Phone;
52import android.provider.ContactsContract.CommonDataKinds.Photo;
Walter Jangf5dfea42015-09-16 12:30:36 -070053import android.provider.ContactsContract.CommonDataKinds.Relation;
54import android.provider.ContactsContract.CommonDataKinds.SipAddress;
Walter Jangcab3dce2015-02-09 17:48:03 -080055import android.provider.ContactsContract.CommonDataKinds.StructuredName;
Walter Jangf5dfea42015-09-16 12:30:36 -070056import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
57import android.provider.ContactsContract.CommonDataKinds.Website;
Walter Jangcab3dce2015-02-09 17:48:03 -080058import android.text.TextUtils;
59import android.util.AttributeSet;
60import android.util.Log;
Walter Jang2d3f31c2015-06-18 23:15:31 -070061import android.util.Pair;
Walter Jangcab3dce2015-02-09 17:48:03 -080062import android.view.LayoutInflater;
Walter Jangb1c87622015-02-13 17:51:38 -080063import android.view.View;
Walter Jangcab3dce2015-02-09 17:48:03 -080064import android.view.ViewGroup;
Walter Jang708ea9e2015-09-10 15:42:05 -070065import android.widget.AdapterView;
Tingting Wang655ad1a2015-10-05 17:51:14 -070066import android.widget.BaseAdapter;
67import android.widget.ImageView;
Walter Jangcab3dce2015-02-09 17:48:03 -080068import android.widget.LinearLayout;
Walter Jang708ea9e2015-09-10 15:42:05 -070069import android.widget.ListPopupWindow;
Walter Jang2d3f31c2015-06-18 23:15:31 -070070import android.widget.TextView;
Walter Jangcab3dce2015-02-09 17:48:03 -080071
Walter Jang708774a2015-10-16 09:32:06 -070072import java.io.FileNotFoundException;
Walter Jangcab3dce2015-02-09 17:48:03 -080073import java.util.ArrayList;
Walter Jangf5dfea42015-09-16 12:30:36 -070074import java.util.Arrays;
Walter Jang192a01c2015-09-22 15:23:55 -070075import java.util.Collections;
Walter Jangf5dfea42015-09-16 12:30:36 -070076import java.util.Comparator;
Walter Jang19d985f2015-07-01 13:36:27 -070077import java.util.HashMap;
Walter Jangcab3dce2015-02-09 17:48:03 -080078import java.util.List;
Walter Jang19d985f2015-07-01 13:36:27 -070079import java.util.Map;
Walter Jangf5dfea42015-09-16 12:30:36 -070080import java.util.TreeSet;
Walter Jangcab3dce2015-02-09 17:48:03 -080081
82/**
Walter Jangf5dfea42015-09-16 12:30:36 -070083 * View to display information from multiple {@link RawContactDelta}s grouped together.
Walter Jangcab3dce2015-02-09 17:48:03 -080084 */
Walter Jangb6ca2722015-02-20 11:10:25 -080085public class CompactRawContactsEditorView extends LinearLayout implements View.OnClickListener {
Walter Jangcab3dce2015-02-09 17:48:03 -080086
Walter Jang4f5594a2015-10-06 18:40:31 -070087 static final String TAG = "CompactEditorView";
Walter Jangcab3dce2015-02-09 17:48:03 -080088
Walter Jang192a01c2015-09-22 15:23:55 -070089 private static final KindSectionDataMapEntryComparator
90 KIND_SECTION_DATA_MAP_ENTRY_COMPARATOR = new KindSectionDataMapEntryComparator();
Walter Jangf5dfea42015-09-16 12:30:36 -070091
Walter Jangb6ca2722015-02-20 11:10:25 -080092 /**
93 * Callbacks for hosts of {@link CompactRawContactsEditorView}s.
94 */
95 public interface Listener {
96
97 /**
Walter Jang151f3e62015-02-26 15:29:40 -080098 * Invoked when the structured name editor field has changed.
99 *
100 * @param rawContactId The raw contact ID from the underlying {@link RawContactDelta}.
101 * @param valuesDelta The values from the underlying {@link RawContactDelta}.
102 */
103 public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta);
Walter Jang708ea9e2015-09-10 15:42:05 -0700104
105 /**
106 * Invoked when the compact editor should rebind editors for a new account.
107 *
108 * @param oldState Old data being edited.
109 * @param oldAccount Old account associated with oldState.
110 * @param newAccount New account to be used.
111 */
112 public void onRebindEditorsForNewContact(RawContactDelta oldState,
113 AccountWithDataSet oldAccount, AccountWithDataSet newAccount);
Walter Jang79658e12015-09-24 10:36:26 -0700114
115 /**
116 * Invoked when no editors could be bound for the contact.
117 */
118 public void onBindEditorsFailed();
Walter Jangd6753152015-10-02 09:23:13 -0700119
120 /**
121 * Invoked after editors have been bound for the contact.
122 */
123 public void onEditorsBound();
Tingting Wang655ad1a2015-10-05 17:51:14 -0700124
125 /**
Tingting Wang5585c6e2015-10-14 11:19:58 -0700126 * Invoked when a rawcontact from linked contacts is selected in editor.
Tingting Wang655ad1a2015-10-05 17:51:14 -0700127 */
Tingting Wang91cee282015-10-07 13:48:17 -0700128 public void onRawContactSelected(Uri uri, long rawContactId, boolean isReadOnly);
Walter Jang3f18d612015-10-07 16:01:05 -0700129
130 /**
131 * Returns the map of raw contact IDs to newly taken or selected photos that have not
132 * yet been saved to CP2.
133 */
134 public Bundle getUpdatedPhotos();
Tingting Wang655ad1a2015-10-05 17:51:14 -0700135 }
136
137 /**
138 * Used to list the account info for the given raw contacts list.
139 */
140 private static final class RawContactAccountListAdapter extends BaseAdapter {
141 private final LayoutInflater mInflater;
142 private final Context mContext;
143 private final RawContactDeltaList mRawContactDeltas;
144
145 public RawContactAccountListAdapter(Context context, RawContactDeltaList rawContactDeltas) {
146 mContext = context;
147 mRawContactDeltas = new RawContactDeltaList();
148 for (RawContactDelta rawContactDelta : rawContactDeltas) {
Walter Jang23709542015-10-22 12:50:58 -0700149 if (rawContactDelta.isVisible() && rawContactDelta.getRawContactId() > 0) {
Tingting Wang655ad1a2015-10-05 17:51:14 -0700150 mRawContactDeltas.add(rawContactDelta);
151 }
152 }
153 mInflater = LayoutInflater.from(context);
154 }
155
156 @Override
157 public View getView(int position, View convertView, ViewGroup parent) {
158 final View resultView = convertView != null ? convertView
159 : mInflater.inflate(R.layout.account_selector_list_item, parent, false);
160
161 final RawContactDelta rawContactDelta = mRawContactDeltas.get(position);
Tingting Wang655ad1a2015-10-05 17:51:14 -0700162
163 final TextView text1 = (TextView) resultView.findViewById(android.R.id.text1);
Walter Jang9488a762015-10-16 13:42:48 -0700164 final AccountType accountType = rawContactDelta.getRawContactAccountType(mContext);
Tingting Wang655ad1a2015-10-05 17:51:14 -0700165 text1.setText(accountType.getDisplayLabel(mContext));
166
Tingting Wang655ad1a2015-10-05 17:51:14 -0700167 final TextView text2 = (TextView) resultView.findViewById(android.R.id.text2);
Walter Jang9488a762015-10-16 13:42:48 -0700168 final String accountName = rawContactDelta.getAccountName();
Tingting Wanga0b69402015-10-13 14:27:58 -0700169 if (TextUtils.isEmpty(accountName)) {
170 text2.setVisibility(View.GONE);
171 } else {
Walter Jang9488a762015-10-16 13:42:48 -0700172 // Truncate email addresses in the middle so we don't lose the domain
Tingting Wanga0b69402015-10-13 14:27:58 -0700173 text2.setText(accountName);
174 text2.setEllipsize(TextUtils.TruncateAt.MIDDLE);
175 }
Tingting Wang655ad1a2015-10-05 17:51:14 -0700176
177 final ImageView icon = (ImageView) resultView.findViewById(android.R.id.icon);
178 icon.setImageDrawable(accountType.getDisplayIcon(mContext));
179
180 return resultView;
181 }
182
183 @Override
184 public int getCount() {
185 return mRawContactDeltas.size();
186 }
187
188 @Override
189 public RawContactDelta getItem(int position) {
190 return mRawContactDeltas.get(position);
191 }
192
193 @Override
194 public long getItemId(int position) {
195 return getItem(position).getRawContactId();
196 }
Walter Jang151f3e62015-02-26 15:29:40 -0800197 }
198
Walter Jang192a01c2015-09-22 15:23:55 -0700199 /** Used to sort entire kind sections. */
200 private static final class KindSectionDataMapEntryComparator implements
Walter Jangcbd431d2015-10-06 13:07:30 -0700201 Comparator<Map.Entry<String,KindSectionDataList>> {
Walter Jangf5dfea42015-09-16 12:30:36 -0700202
Walter Jang192a01c2015-09-22 15:23:55 -0700203 final MimeTypeComparator mMimeTypeComparator = new MimeTypeComparator();
204
205 @Override
Walter Jangcbd431d2015-10-06 13:07:30 -0700206 public int compare(Map.Entry<String, KindSectionDataList> entry1,
207 Map.Entry<String, KindSectionDataList> entry2) {
Walter Jang192a01c2015-09-22 15:23:55 -0700208 if (entry1 == entry2) return 0;
209 if (entry1 == null) return -1;
210 if (entry2 == null) return 1;
211
212 final String mimeType1 = entry1.getKey();
213 final String mimeType2 = entry2.getKey();
214
215 return mMimeTypeComparator.compare(mimeType1, mimeType2);
216 }
217 }
218
219 /**
220 * Sorts kinds roughly the same as quick contacts; we diverge in the following ways:
221 * <ol>
222 * <li>All names are together at the top.</li>
223 * <li>IM is moved up after addresses</li>
224 * <li>SIP addresses are moved to below phone numbers</li>
Walter Jang79658e12015-09-24 10:36:26 -0700225 * <li>Group membership is placed at the end</li>
Walter Jang192a01c2015-09-22 15:23:55 -0700226 * </ol>
227 */
228 private static final class MimeTypeComparator implements Comparator<String> {
229
Walter Jangf5dfea42015-09-16 12:30:36 -0700230 private static final List<String> MIME_TYPE_ORDER = Arrays.asList(new String[] {
231 StructuredName.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700232 Nickname.CONTENT_ITEM_TYPE,
Walter Jang2ae21752015-09-25 11:25:38 -0700233 Organization.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700234 Phone.CONTENT_ITEM_TYPE,
235 SipAddress.CONTENT_ITEM_TYPE,
236 Email.CONTENT_ITEM_TYPE,
237 StructuredPostal.CONTENT_ITEM_TYPE,
238 Im.CONTENT_ITEM_TYPE,
239 Website.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700240 Event.CONTENT_ITEM_TYPE,
241 Relation.CONTENT_ITEM_TYPE,
Walter Jangf10ca152015-09-22 15:23:55 -0700242 Note.CONTENT_ITEM_TYPE,
243 GroupMembership.CONTENT_ITEM_TYPE
Walter Jangf5dfea42015-09-16 12:30:36 -0700244 });
245
246 @Override
Walter Jang192a01c2015-09-22 15:23:55 -0700247 public int compare(String mimeType1, String mimeType2) {
248 if (mimeType1 == mimeType2) return 0;
249 if (mimeType1 == null) return -1;
250 if (mimeType2 == null) return 1;
Walter Jangf5dfea42015-09-16 12:30:36 -0700251
252 int index1 = MIME_TYPE_ORDER.indexOf(mimeType1);
253 int index2 = MIME_TYPE_ORDER.indexOf(mimeType2);
254
255 // Fallback to alphabetical ordering of the mime type if both are not found
256 if (index1 < 0 && index2 < 0) return mimeType1.compareTo(mimeType2);
257 if (index1 < 0) return 1;
258 if (index2 < 0) return -1;
259
260 return index1 < index2 ? -1 : 1;
261 }
262 }
263
Walter Jang192a01c2015-09-22 15:23:55 -0700264 /**
265 * Sorts primary accounts and google account types before others.
266 */
267 private static final class EditorComparator implements Comparator<KindSectionData> {
268
269 private RawContactDeltaComparator mRawContactDeltaComparator;
270
271 private EditorComparator(Context context) {
272 mRawContactDeltaComparator = new RawContactDeltaComparator(context);
273 }
274
275 @Override
276 public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
277 if (kindSectionData1 == kindSectionData2) return 0;
278 if (kindSectionData1 == null) return -1;
279 if (kindSectionData2 == null) return 1;
280
281 final RawContactDelta rawContactDelta1 = kindSectionData1.getRawContactDelta();
282 final RawContactDelta rawContactDelta2 = kindSectionData2.getRawContactDelta();
283
284 if (rawContactDelta1 == rawContactDelta2) return 0;
285 if (rawContactDelta1 == null) return -1;
286 if (rawContactDelta2 == null) return 1;
287
288 return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
289 }
290 }
291
Walter Jang79658e12015-09-24 10:36:26 -0700292 public static class SavedState extends BaseSavedState {
293
294 public static final Parcelable.Creator<SavedState> CREATOR =
295 new Parcelable.Creator<SavedState>() {
296 public SavedState createFromParcel(Parcel in) {
297 return new SavedState(in);
298 }
299 public SavedState[] newArray(int size) {
300 return new SavedState[size];
301 }
302 };
303
304 private boolean mIsExpanded;
305
306 public SavedState(Parcelable superState) {
307 super(superState);
308 }
309
310 private SavedState(Parcel in) {
311 super(in);
312 mIsExpanded = in.readInt() != 0;
313 }
314
315 @Override
316 public void writeToParcel(Parcel out, int flags) {
317 super.writeToParcel(out, flags);
318 out.writeInt(mIsExpanded ? 1 : 0);
319 }
320 }
321
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700322 private CompactRawContactsEditorView.Listener mListener;
Walter Jangb6ca2722015-02-20 11:10:25 -0800323
Walter Jangcab3dce2015-02-09 17:48:03 -0800324 private AccountTypeManager mAccountTypeManager;
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700325 private AccountDisplayInfoFactory mAccountDisplayInfoFactory;
Walter Jangcab3dce2015-02-09 17:48:03 -0800326 private LayoutInflater mLayoutInflater;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800327
Walter Jangcab3dce2015-02-09 17:48:03 -0800328 private ViewIdGenerator mViewIdGenerator;
Walter Jangf46abd82015-02-20 16:52:04 -0800329 private MaterialColorMapUtils.MaterialPalette mMaterialPalette;
Walter Jang82acd422015-10-17 14:01:27 -0700330 private long mPhotoId = -1;
Walter Jang708ea9e2015-09-10 15:42:05 -0700331 private boolean mHasNewContact;
332 private boolean mIsUserProfile;
333 private AccountWithDataSet mPrimaryAccount;
Walter Jang9a552372016-08-24 11:51:05 -0700334 private RawContactDeltaList mRawContactDeltas;
335 private long mRawContactIdToDisplayAlone = -1;
336 private boolean mRawContactDisplayAloneIsReadOnly;
337 private boolean mIsEditingReadOnlyRawContactWithNewContact;
Walter Jangcbd431d2015-10-06 13:07:30 -0700338 private Map<String,KindSectionDataList> mKindSectionDataMap = new HashMap<>();
Walter Jangcab3dce2015-02-09 17:48:03 -0800339
Walter Jang708ea9e2015-09-10 15:42:05 -0700340 // Account header
341 private View mAccountHeaderContainer;
342 private TextView mAccountHeaderType;
343 private TextView mAccountHeaderName;
Tingting Wang91cee282015-10-07 13:48:17 -0700344 private ImageView mAccountHeaderIcon;
Gary Mai46cb3102016-08-10 18:14:09 -0700345 private ImageView mAccountHeaderExpanderIcon;
Walter Jang708ea9e2015-09-10 15:42:05 -0700346
Tingting Wang655ad1a2015-10-05 17:51:14 -0700347 // Raw contacts selector
348 private View mRawContactContainer;
349 private TextView mRawContactSummary;
Tingting Wang655ad1a2015-10-05 17:51:14 -0700350
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700351 private CompactPhotoEditorView mPhotoView;
Walter Jangf5dfea42015-09-16 12:30:36 -0700352 private ViewGroup mKindSectionViews;
Walter Jangf10ca152015-09-22 15:23:55 -0700353 private Map<String,List<CompactKindSectionView>> mKindSectionViewsMap = new HashMap<>();
Walter Jangb6ca2722015-02-20 11:10:25 -0800354 private View mMoreFields;
Walter Jangcab3dce2015-02-09 17:48:03 -0800355
Walter Jang79658e12015-09-24 10:36:26 -0700356 private boolean mIsExpanded;
Walter Jangcbd431d2015-10-06 13:07:30 -0700357
Walter Jang3efae4a2015-02-18 11:12:00 -0800358 private long mPhotoRawContactId;
Walter Jang31a74ad2015-10-02 19:17:39 -0700359 private ValuesDelta mPhotoValuesDelta;
Walter Jang82acd422015-10-17 14:01:27 -0700360
361 private Pair<KindSectionData, ValuesDelta> mPrimaryNameKindSectionData;
Walter Jang3efae4a2015-02-18 11:12:00 -0800362
Walter Jangcab3dce2015-02-09 17:48:03 -0800363 public CompactRawContactsEditorView(Context context) {
364 super(context);
365 }
366
367 public CompactRawContactsEditorView(Context context, AttributeSet attrs) {
368 super(context, attrs);
369 }
370
Walter Jangb6ca2722015-02-20 11:10:25 -0800371 /**
372 * Sets the receiver for {@link CompactRawContactsEditorView} callbacks.
373 */
374 public void setListener(Listener listener) {
375 mListener = listener;
376 }
377
Walter Jangcab3dce2015-02-09 17:48:03 -0800378 @Override
379 protected void onFinishInflate() {
380 super.onFinishInflate();
381
382 mAccountTypeManager = AccountTypeManager.getInstance(getContext());
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700383 mAccountDisplayInfoFactory = AccountDisplayInfoFactory.forWritableAccounts(getContext());
Walter Jangcab3dce2015-02-09 17:48:03 -0800384 mLayoutInflater = (LayoutInflater)
385 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
386
Walter Jang708ea9e2015-09-10 15:42:05 -0700387 // Account header
Gary Mai46cb3102016-08-10 18:14:09 -0700388 mAccountHeaderContainer = findViewById(R.id.account_header_container);
Walter Jang708ea9e2015-09-10 15:42:05 -0700389 mAccountHeaderType = (TextView) findViewById(R.id.account_type);
390 mAccountHeaderName = (TextView) findViewById(R.id.account_name);
Tingting Wang91cee282015-10-07 13:48:17 -0700391 mAccountHeaderIcon = (ImageView) findViewById(R.id.account_type_icon);
Gary Mai46cb3102016-08-10 18:14:09 -0700392 mAccountHeaderExpanderIcon = (ImageView) findViewById(R.id.account_expander_icon);
Walter Jang708ea9e2015-09-10 15:42:05 -0700393
Tingting Wang655ad1a2015-10-05 17:51:14 -0700394 // Raw contacts selector
395 mRawContactContainer = findViewById(R.id.all_rawcontacts_accounts_container);
396 mRawContactSummary = (TextView) findViewById(R.id.rawcontacts_accounts_summary);
Tingting Wang655ad1a2015-10-05 17:51:14 -0700397
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700398 mPhotoView = (CompactPhotoEditorView) findViewById(R.id.photo_editor);
Walter Jangf5dfea42015-09-16 12:30:36 -0700399 mKindSectionViews = (LinearLayout) findViewById(R.id.kind_section_views);
Walter Jangb6ca2722015-02-20 11:10:25 -0800400 mMoreFields = findViewById(R.id.more_fields);
401 mMoreFields.setOnClickListener(this);
402 }
403
Walter Jangb6ca2722015-02-20 11:10:25 -0800404 @Override
405 public void onClick(View view) {
Walter Jangf5dfea42015-09-16 12:30:36 -0700406 if (view.getId() == R.id.more_fields) {
Walter Jangd6753152015-10-02 09:23:13 -0700407 showAllFields();
Walter Jangb6ca2722015-02-20 11:10:25 -0800408 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800409 }
410
411 @Override
412 public void setEnabled(boolean enabled) {
413 super.setEnabled(enabled);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700414 final int childCount = mKindSectionViews.getChildCount();
415 for (int i = 0; i < childCount; i++) {
416 mKindSectionViews.getChildAt(i).setEnabled(enabled);
Walter Jangcab3dce2015-02-09 17:48:03 -0800417 }
418 }
419
Walter Jang79658e12015-09-24 10:36:26 -0700420 @Override
421 public Parcelable onSaveInstanceState() {
422 final Parcelable superState = super.onSaveInstanceState();
423 final SavedState savedState = new SavedState(superState);
424 savedState.mIsExpanded = mIsExpanded;
425 return savedState;
426 }
427
428 @Override
429 public void onRestoreInstanceState(Parcelable state) {
430 if(!(state instanceof SavedState)) {
431 super.onRestoreInstanceState(state);
432 return;
433 }
434 final SavedState savedState = (SavedState) state;
435 super.onRestoreInstanceState(savedState.getSuperState());
436 mIsExpanded = savedState.mIsExpanded;
Walter Jangd6753152015-10-02 09:23:13 -0700437 if (mIsExpanded) {
438 showAllFields();
Walter Jang79658e12015-09-24 10:36:26 -0700439 }
440 }
441
Walter Jang3efae4a2015-02-18 11:12:00 -0800442 /**
Walter Jang31a74ad2015-10-02 19:17:39 -0700443 * Pass through to {@link CompactPhotoEditorView#setListener}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800444 */
Walter Jang31a74ad2015-10-02 19:17:39 -0700445 public void setPhotoListener(CompactPhotoEditorView.Listener listener) {
446 mPhotoView.setListener(listener);
Walter Jang3efae4a2015-02-18 11:12:00 -0800447 }
448
Walter Jang31a74ad2015-10-02 19:17:39 -0700449 public void removePhoto() {
Walter Jang45b86d52015-10-15 15:23:16 -0700450 mPhotoValuesDelta.setFromTemplate(true);
Walter Jang31a74ad2015-10-02 19:17:39 -0700451 mPhotoValuesDelta.put(Photo.PHOTO, (byte[]) null);
452
453 mPhotoView.removePhoto();
Walter Jang3efae4a2015-02-18 11:12:00 -0800454 }
455
456 /**
Walter Jang41b3ea12015-03-09 17:30:06 -0700457 * Pass through to {@link CompactPhotoEditorView#setFullSizedPhoto(Uri)}.
458 */
459 public void setFullSizePhoto(Uri photoUri) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700460 mPhotoView.setFullSizedPhoto(photoUri);
Walter Jang41b3ea12015-03-09 17:30:06 -0700461 }
462
Walter Jang31a74ad2015-10-02 19:17:39 -0700463 public void updatePhoto(Uri photoUri) {
Walter Jang45b86d52015-10-15 15:23:16 -0700464 mPhotoValuesDelta.setFromTemplate(false);
Wenyi Wangb8ab8612015-10-27 11:18:49 -0700465 // Unset primary for all photos
Wenyi Wang9086fb92015-11-16 09:58:20 -0800466 unsetSuperPrimaryFromAllPhotos();
Wenyi Wangb8ab8612015-10-27 11:18:49 -0700467 // Mark the currently displayed photo as primary
468 mPhotoValuesDelta.setSuperPrimary(true);
Walter Jang31a74ad2015-10-02 19:17:39 -0700469
Wenyi Wang4c9cf3a2015-10-15 17:58:23 -0700470 // Even though high-res photos cannot be saved by passing them via
471 // an EntityDeltaList (since they cause the Bundle size limit to be
472 // exceeded), we still pass a low-res thumbnail. This simplifies
473 // code all over the place, because we don't have to test whether
474 // there is a change in EITHER the delta-list OR a changed photo...
475 // this way, there is always a change in the delta-list.
476 try {
477 final byte[] bytes = EditorUiUtils.getCompressedThumbnailBitmapBytes(
478 getContext(), photoUri);
479 if (bytes != null) {
480 mPhotoValuesDelta.setPhoto(bytes);
481 }
482 } catch (FileNotFoundException e) {
483 elog("Failed to get bitmap from photo Uri");
484 }
485
Walter Jang31a74ad2015-10-02 19:17:39 -0700486 mPhotoView.setFullSizedPhoto(photoUri);
487 }
488
Wenyi Wang9086fb92015-11-16 09:58:20 -0800489 private void unsetSuperPrimaryFromAllPhotos() {
Walter Jang3f18d612015-10-07 16:01:05 -0700490 final List<KindSectionData> kindSectionDataList =
491 mKindSectionDataMap.get(Photo.CONTENT_ITEM_TYPE);
492 for (KindSectionData kindSectionData : kindSectionDataList) {
Wenyi Wang9086fb92015-11-16 09:58:20 -0800493 for (ValuesDelta valuesDelta : kindSectionData.getNonEmptyValuesDeltas()) {
494 valuesDelta.setSuperPrimary(false);
Walter Jang3f18d612015-10-07 16:01:05 -0700495 }
496 }
497 }
498
Walter Jang41b3ea12015-03-09 17:30:06 -0700499 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800500 * Pass through to {@link CompactPhotoEditorView#isWritablePhotoSet}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800501 */
502 public boolean isWritablePhotoSet() {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700503 return mPhotoView.isWritablePhotoSet();
Walter Jang3efae4a2015-02-18 11:12:00 -0800504 }
505
506 /**
Walter Jang3efae4a2015-02-18 11:12:00 -0800507 * Get the raw contact ID for the CompactHeaderView photo.
508 */
Walter Jang3efae4a2015-02-18 11:12:00 -0800509 public long getPhotoRawContactId() {
510 return mPhotoRawContactId;
511 }
512
Walter Jang4f5594a2015-10-06 18:40:31 -0700513 public StructuredNameEditorView getPrimaryNameEditorView() {
Walter Jange3945952015-10-27 12:44:54 -0700514 final CompactKindSectionView primaryNameKindSectionView = getPrimaryNameKindSectionView();
515 return primaryNameKindSectionView == null
516 ? null : primaryNameKindSectionView.getPrimaryNameEditorView();
Walter Jang4f5594a2015-10-06 18:40:31 -0700517 }
518
Walter Jang31a74ad2015-10-02 19:17:39 -0700519 /**
520 * Returns a data holder for every non-default/non-empty photo from each raw contact, whether
521 * the raw contact is writable or not.
522 */
523 public ArrayList<CompactPhotoSelectionFragment.Photo> getPhotos() {
524 final ArrayList<CompactPhotoSelectionFragment.Photo> photos = new ArrayList<>();
525
Walter Jang3f18d612015-10-07 16:01:05 -0700526 final Bundle updatedPhotos = mListener == null ? null : mListener.getUpdatedPhotos();
527
Walter Jang31a74ad2015-10-02 19:17:39 -0700528 final List<KindSectionData> kindSectionDataList =
529 mKindSectionDataMap.get(Photo.CONTENT_ITEM_TYPE);
530 for (int i = 0; i < kindSectionDataList.size(); i++) {
531 final KindSectionData kindSectionData = kindSectionDataList.get(i);
532 final AccountType accountType = kindSectionData.getAccountType();
Walter Jang228e02f2015-11-13 09:11:01 -0800533 final List<ValuesDelta> valuesDeltas = kindSectionData.getNonEmptyValuesDeltas();
534 if (valuesDeltas.isEmpty()) continue;
535 for (int j = 0; j < valuesDeltas.size(); j++) {
536 final ValuesDelta valuesDelta = valuesDeltas.get(j);
Walter Jang31a74ad2015-10-02 19:17:39 -0700537 final Bitmap bitmap = EditorUiUtils.getPhotoBitmap(valuesDelta);
538 if (bitmap == null) continue;
539
540 final CompactPhotoSelectionFragment.Photo photo =
541 new CompactPhotoSelectionFragment.Photo();
542 photo.titleRes = accountType.titleRes;
543 photo.iconRes = accountType.iconRes;
544 photo.syncAdapterPackageName = accountType.syncAdapterPackageName;
545 photo.valuesDelta = valuesDelta;
546 photo.primary = valuesDelta.isSuperPrimary();
547 photo.kindSectionDataListIndex = i;
548 photo.valuesDeltaListIndex = j;
Walter Jangda258ff2015-11-17 11:06:02 -0800549 photo.photoId = valuesDelta.getId();
Walter Jang3f18d612015-10-07 16:01:05 -0700550
551 if (updatedPhotos != null) {
552 photo.updatedPhotoUri = (Uri) updatedPhotos.get(String.valueOf(
553 kindSectionData.getRawContactDelta().getRawContactId()));
554 }
555
Wenyi Wangd375c352016-03-28 15:12:45 -0700556 final CharSequence accountTypeLabel = accountType.getDisplayLabel(getContext());
557 photo.accountType = accountTypeLabel == null ? "" : accountTypeLabel.toString();
558 final String accountName = kindSectionData.getRawContactDelta().getAccountName();
559 photo.accountName = accountName == null ? "" : accountName;
Wenyi Wangab360172015-12-15 10:35:58 -0800560
Walter Jang31a74ad2015-10-02 19:17:39 -0700561 photos.add(photo);
562 }
563 }
564
565 return photos;
566 }
567
568 /**
569 * Marks the raw contact photo given as primary for the aggregate contact and updates the
570 * UI.
571 */
572 public void setPrimaryPhoto(CompactPhotoSelectionFragment.Photo photo) {
Walter Jang31a74ad2015-10-02 19:17:39 -0700573 // Find the values delta to mark as primary
Walter Jang3f18d612015-10-07 16:01:05 -0700574 final KindSectionDataList kindSectionDataList =
575 mKindSectionDataMap.get(Photo.CONTENT_ITEM_TYPE);
Walter Jang31a74ad2015-10-02 19:17:39 -0700576 if (photo.kindSectionDataListIndex < 0
577 || photo.kindSectionDataListIndex >= kindSectionDataList.size()) {
578 wlog("Invalid kind section data list index");
579 return;
580 }
581 final KindSectionData kindSectionData =
582 kindSectionDataList.get(photo.kindSectionDataListIndex);
Walter Jang228e02f2015-11-13 09:11:01 -0800583 final List<ValuesDelta> valuesDeltaList = kindSectionData.getNonEmptyValuesDeltas();
Walter Jang31a74ad2015-10-02 19:17:39 -0700584 if (photo.valuesDeltaListIndex >= valuesDeltaList.size()) {
585 wlog("Invalid values delta list index");
586 return;
587 }
Walter Jangda258ff2015-11-17 11:06:02 -0800588
589 // Update values delta
Walter Jang31a74ad2015-10-02 19:17:39 -0700590 final ValuesDelta valuesDelta = valuesDeltaList.get(photo.valuesDeltaListIndex);
591 valuesDelta.setFromTemplate(false);
Wenyi Wang9086fb92015-11-16 09:58:20 -0800592 unsetSuperPrimaryFromAllPhotos();
Wenyi Wangb8ab8612015-10-27 11:18:49 -0700593 valuesDelta.setSuperPrimary(true);
Walter Jangda258ff2015-11-17 11:06:02 -0800594
Walter Jang31a74ad2015-10-02 19:17:39 -0700595 // Update the UI
596 mPhotoView.setPhoto(valuesDelta, mMaterialPalette);
597 }
598
Walter Jangd35e5ef2015-02-24 09:18:16 -0800599 public View getAggregationAnchorView() {
Walter Jangf10ca152015-09-22 15:23:55 -0700600 final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
Walter Jang192a01c2015-09-22 15:23:55 -0700601 StructuredName.CONTENT_ITEM_TYPE);
Walter Jangf10ca152015-09-22 15:23:55 -0700602 if (!kindSectionViews.isEmpty()) {
Walter Jang192a01c2015-09-22 15:23:55 -0700603 return mKindSectionViews.getChildAt(0).findViewById(R.id.anchor_view);
Walter Jangd35e5ef2015-02-24 09:18:16 -0800604 }
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700605 return null;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800606 }
607
Walter Jangf10ca152015-09-22 15:23:55 -0700608 public void setGroupMetaData(Cursor groupMetaData) {
609 final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
610 GroupMembership.CONTENT_ITEM_TYPE);
611 for (CompactKindSectionView kindSectionView : kindSectionViews) {
612 kindSectionView.setGroupMetaData(groupMetaData);
Walter Jangd6753152015-10-02 09:23:13 -0700613 if (mIsExpanded) {
614 kindSectionView.setHideWhenEmpty(false);
615 kindSectionView.updateEmptyEditors(/* shouldAnimate =*/ true);
616 }
Walter Jangf10ca152015-09-22 15:23:55 -0700617 }
618 }
619
Walter Jangf46abd82015-02-20 16:52:04 -0800620 public void setState(RawContactDeltaList rawContactDeltas,
Walter Jang06f73a12015-06-17 11:15:48 -0700621 MaterialColorMapUtils.MaterialPalette materialPalette, ViewIdGenerator viewIdGenerator,
Walter Jange3945952015-10-27 12:44:54 -0700622 long photoId, boolean hasNewContact, boolean isUserProfile,
Walter Jang9a552372016-08-24 11:51:05 -0700623 AccountWithDataSet primaryAccount, long rawContactIdToDisplayAlone,
624 boolean rawContactDisplayAloneIsReadOnly,
625 boolean isEditingReadOnlyRawContactWithNewContact) {
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700626 // Enable layout animations for new contacts. This looks nicer when switching to and from
627 // an account that doesn't support profile photos (e.g. SIM accounts).
628 if (hasNewContact && getLayoutTransition() == null) {
629 setLayoutTransition(new LayoutTransition());
630 }
Marcus Hagerottf04c9752016-09-08 15:22:57 -0700631
Walter Jang9a552372016-08-24 11:51:05 -0700632 mRawContactDeltas = rawContactDeltas;
633 mRawContactIdToDisplayAlone = rawContactIdToDisplayAlone;
634 mRawContactDisplayAloneIsReadOnly = rawContactDisplayAloneIsReadOnly;
635 mIsEditingReadOnlyRawContactWithNewContact = isEditingReadOnlyRawContactWithNewContact;
636
Walter Jang363d3fd2015-09-16 10:29:07 -0700637 mKindSectionDataMap.clear();
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700638 mKindSectionViewsMap.clear();
Walter Jangf5dfea42015-09-16 12:30:36 -0700639 mKindSectionViews.removeAllViews();
Walter Jang363d3fd2015-09-16 10:29:07 -0700640 mMoreFields.setVisibility(View.VISIBLE);
Walter Jangcab3dce2015-02-09 17:48:03 -0800641
Walter Jangf46abd82015-02-20 16:52:04 -0800642 mMaterialPalette = materialPalette;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700643 mViewIdGenerator = viewIdGenerator;
Walter Jang708ea9e2015-09-10 15:42:05 -0700644 mPhotoId = photoId;
Tingting Wangf695eb32015-10-15 18:45:15 -0700645
Walter Jang708ea9e2015-09-10 15:42:05 -0700646 mHasNewContact = hasNewContact;
647 mIsUserProfile = isUserProfile;
648 mPrimaryAccount = primaryAccount;
649 if (mPrimaryAccount == null) {
650 mPrimaryAccount = ContactEditorUtils.getInstance(getContext()).getDefaultAccount();
651 }
652 vlog("state: primary " + mPrimaryAccount);
Walter Jangcab3dce2015-02-09 17:48:03 -0800653
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700654 // Parse the given raw contact deltas
655 if (rawContactDeltas == null || rawContactDeltas.isEmpty()) {
656 elog("No raw contact deltas");
Walter Jang79658e12015-09-24 10:36:26 -0700657 if (mListener != null) mListener.onBindEditorsFailed();
Walter Jangf5dfea42015-09-16 12:30:36 -0700658 return;
659 }
Walter Jangcbd431d2015-10-06 13:07:30 -0700660 parseRawContactDeltas(rawContactDeltas);
Walter Jang79658e12015-09-24 10:36:26 -0700661 if (mKindSectionDataMap.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700662 elog("No kind section data parsed from RawContactDelta(s)");
Walter Jang79658e12015-09-24 10:36:26 -0700663 if (mListener != null) mListener.onBindEditorsFailed();
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700664 return;
665 }
Walter Jang82acd422015-10-17 14:01:27 -0700666
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700667
Walter Jang82acd422015-10-17 14:01:27 -0700668 // Get the primary name kind section data
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700669 mPrimaryNameKindSectionData =
670 getOrCreateKindSectionDataList(StructuredName.CONTENT_ITEM_TYPE)
671 .getEntryToWrite(/* id =*/ -1, mPrimaryAccount, mIsUserProfile);
Walter Jang82acd422015-10-17 14:01:27 -0700672 if (mPrimaryNameKindSectionData != null) {
673 // Ensure that a structured name and photo exists
674 final RawContactDelta rawContactDelta =
675 mPrimaryNameKindSectionData.first.getRawContactDelta();
676 RawContactModifier.ensureKindExists(
677 rawContactDelta,
678 rawContactDelta.getAccountType(mAccountTypeManager),
Walter Jangcbd431d2015-10-06 13:07:30 -0700679 StructuredName.CONTENT_ITEM_TYPE);
Walter Jang82acd422015-10-17 14:01:27 -0700680 RawContactModifier.ensureKindExists(
681 rawContactDelta,
682 rawContactDelta.getAccountType(mAccountTypeManager),
Walter Jangcbd431d2015-10-06 13:07:30 -0700683 Photo.CONTENT_ITEM_TYPE);
684 }
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700685
686 // Setup the view
Walter Jang363d3fd2015-09-16 10:29:07 -0700687 addPhotoView();
Walter Jang9a552372016-08-24 11:51:05 -0700688 if (isSingleReadOnlyRawContact()) {
689 // We're want to display the inputs fields for a single read only raw contact
690 addReadOnlyRawContactEditorViews();
691 // Hide the "More fields" link
692 mMoreFields.setVisibility(View.GONE);
693 } else if (mIsEditingReadOnlyRawContactWithNewContact) {
694 // A new writable raw contact was created and joined with the read only contact
695 // that the user is trying to edit.
696 setupCompactEditorNormally();
Walter Jange3945952015-10-27 12:44:54 -0700697
Walter Jang9a552372016-08-24 11:51:05 -0700698 // TODO: Hide the raw contact selector since it will just contain the read-only raw
699 // contact and clicking that will just open the exact same editor. When we clean up
700 // the whole account header, selector, and raw contact selector mess, we can prevent
701 // the selector from being displayed in a less hacky way.
702 mRawContactContainer.setVisibility(View.GONE);
703 } else if (mRawContactDeltas.size() > 1) {
704 // We're editing an aggregate composed of more than one writable raw contacts
Walter Jangd6753152015-10-02 09:23:13 -0700705
Walter Jang9a552372016-08-24 11:51:05 -0700706 // TODO: Don't render any input fields. Eventually we will show a list of account
707 // types and names but for now just show the account selector and hide the "More fields"
708 // link.
709 addAccountInfo(rawContactDeltas);
710 mMoreFields.setVisibility(View.GONE);
711 } else {
712 setupCompactEditorNormally();
713 }
Walter Jangd6753152015-10-02 09:23:13 -0700714 if (mListener != null) mListener.onEditorsBound();
Walter Jangcab3dce2015-02-09 17:48:03 -0800715 }
716
Walter Jang9a552372016-08-24 11:51:05 -0700717 private void setupCompactEditorNormally() {
718 addAccountInfo(mRawContactDeltas);
719 addKindSectionViews();
Walter Jangcab3dce2015-02-09 17:48:03 -0800720
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700721 mMoreFields.setVisibility(hasMoreFields() ? View.VISIBLE : View.GONE);
722
Walter Jang9a552372016-08-24 11:51:05 -0700723 if (mIsExpanded) showAllFields();
724 }
725
726 private boolean isSingleReadOnlyRawContact() {
727 return mRawContactDeltas.size() == 1
728 && mRawContactDeltas.get(0).getRawContactId() == mRawContactIdToDisplayAlone
729 && mRawContactDisplayAloneIsReadOnly;
730 }
731
Walter Jangcbd431d2015-10-06 13:07:30 -0700732 private void parseRawContactDeltas(RawContactDeltaList rawContactDeltas) {
Walter Jang363d3fd2015-09-16 10:29:07 -0700733 // Build the kind section data list map
Walter Jang192a01c2015-09-22 15:23:55 -0700734 vlog("parse: " + rawContactDeltas.size() + " rawContactDelta(s)");
735 for (int j = 0; j < rawContactDeltas.size(); j++) {
736 final RawContactDelta rawContactDelta = rawContactDeltas.get(j);
737 vlog("parse: " + j + " rawContactDelta" + rawContactDelta);
Walter Jang363d3fd2015-09-16 10:29:07 -0700738 if (rawContactDelta == null || !rawContactDelta.isVisible()) continue;
Walter Jangcab3dce2015-02-09 17:48:03 -0800739 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
Walter Jang363d3fd2015-09-16 10:29:07 -0700740 if (accountType == null) continue;
741 final List<DataKind> dataKinds = accountType.getSortedDataKinds();
742 final int dataKindSize = dataKinds == null ? 0 : dataKinds.size();
743 vlog("parse: " + dataKindSize + " dataKinds(s)");
744 for (int i = 0; i < dataKindSize; i++) {
745 final DataKind dataKind = dataKinds.get(i);
Walter Jang9a552372016-08-24 11:51:05 -0700746 if (dataKind == null) {
747 vlog("parse: " + i + " " + dataKind.mimeType + " dropped null data kind");
Walter Jang192a01c2015-09-22 15:23:55 -0700748 continue;
749 }
750 final String mimeType = dataKind.mimeType;
751
752 // Skip psuedo mime types
753 if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
754 || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
755 vlog("parse: " + i + " " + dataKind.mimeType + " dropped pseudo type");
756 continue;
757 }
758
Walter Jang3f18d612015-10-07 16:01:05 -0700759 final KindSectionDataList kindSectionDataList =
Walter Jangcbd431d2015-10-06 13:07:30 -0700760 getOrCreateKindSectionDataList(mimeType);
Walter Jang363d3fd2015-09-16 10:29:07 -0700761 final KindSectionData kindSectionData =
762 new KindSectionData(accountType, dataKind, rawContactDelta);
763 kindSectionDataList.add(kindSectionData);
Walter Jang192a01c2015-09-22 15:23:55 -0700764
Walter Jang363d3fd2015-09-16 10:29:07 -0700765 vlog("parse: " + i + " " + dataKind.mimeType + " " +
Walter Jang228e02f2015-11-13 09:11:01 -0800766 kindSectionData.getValuesDeltas().size() + " value(s) " +
Tingting Wangd482e0c2015-11-16 10:13:29 -0800767 kindSectionData.getNonEmptyValuesDeltas().size() + " non-empty value(s) " +
Wenyi Wang42d740c2015-11-13 14:23:54 -0800768 kindSectionData.getVisibleValuesDeltas().size() +
Walter Jang228e02f2015-11-13 09:11:01 -0800769 " visible value(s)");
Walter Jangac679af2015-06-01 12:17:06 -0700770 }
771 }
Walter Jang3efae4a2015-02-18 11:12:00 -0800772 }
773
Walter Jang3f18d612015-10-07 16:01:05 -0700774 private KindSectionDataList getOrCreateKindSectionDataList(String mimeType) {
Walter Jangcbd431d2015-10-06 13:07:30 -0700775 KindSectionDataList kindSectionDataList = mKindSectionDataMap.get(mimeType);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700776 if (kindSectionDataList == null) {
Walter Jangcbd431d2015-10-06 13:07:30 -0700777 kindSectionDataList = new KindSectionDataList();
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700778 mKindSectionDataMap.put(mimeType, kindSectionDataList);
779 }
780 return kindSectionDataList;
781 }
782
Walter Jang9a552372016-08-24 11:51:05 -0700783 private void addReadOnlyRawContactEditorViews() {
784 final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
785 Context.LAYOUT_INFLATER_SERVICE);
786 final AccountTypeManager accountTypes = AccountTypeManager.getInstance(
787 getContext());
788
789 for (int i = 0; i < mRawContactDeltas.size(); i++) {
790 final RawContactDelta rawContactDelta = mRawContactDeltas.get(i);
791 if (!rawContactDelta.isVisible()) continue;
792 final AccountType type = rawContactDelta.getAccountType(accountTypes);
793 if (type.areContactsWritable()) continue;
794
795 final BaseRawContactEditorView editor = (BaseRawContactEditorView) inflater.inflate(
796 R.layout.raw_contact_readonly_editor_view, mKindSectionViews, false);
797 editor.setCollapsed(false);
798 mKindSectionViews.addView(editor);
799 editor.setState(rawContactDelta, type, mViewIdGenerator, mIsUserProfile);
800 }
801 }
802
803 // TODO: we have mRawContactDeltas, we don't need to pass the RawContactDeltaList to this method
Tingting Wang655ad1a2015-10-05 17:51:14 -0700804 private void addAccountInfo(RawContactDeltaList rawContactDeltas) {
Walter Jang82acd422015-10-17 14:01:27 -0700805 mAccountHeaderContainer.setVisibility(View.GONE);
Walter Jang82acd422015-10-17 14:01:27 -0700806 mRawContactContainer.setVisibility(View.GONE);
807
808 if (mPrimaryNameKindSectionData == null) return;
809 final RawContactDelta rawContactDelta =
810 mPrimaryNameKindSectionData.first.getRawContactDelta();
Walter Jang708ea9e2015-09-10 15:42:05 -0700811
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700812 final AccountDisplayInfo account =
813 mAccountDisplayInfoFactory.getAccountDisplayInfoFor(rawContactDelta);
814
Walter Jang708ea9e2015-09-10 15:42:05 -0700815 // Get the account information for the primary raw contact delta
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700816 final String accountLabel = mIsUserProfile
817 ? EditorUiUtils.getAccountHeaderLabelForMyProfile(getContext(), account)
818 : account.getNameLabel().toString();
Walter Jang708ea9e2015-09-10 15:42:05 -0700819
Walter Jang23709542015-10-22 12:50:58 -0700820 // Either the account header or selector should be shown, not both.
Walter Jang708ea9e2015-09-10 15:42:05 -0700821 final List<AccountWithDataSet> accounts =
822 AccountTypeManager.getInstance(getContext()).getAccounts(true);
Walter Jang82acd422015-10-17 14:01:27 -0700823 if (mHasNewContact && !mIsUserProfile) {
824 if (accounts.size() > 1) {
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700825 addAccountSelector(rawContactDelta, accountLabel);
Walter Jangbe5e1b12015-10-17 11:38:29 -0700826 } else {
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700827 addAccountHeader(accountLabel);
Walter Jangbe5e1b12015-10-17 11:38:29 -0700828 }
Tingting Wang1594c6f2015-10-26 17:39:16 -0700829 } else if (mIsUserProfile || !shouldHideAccountContainer(rawContactDeltas)) {
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700830 addAccountHeader(accountLabel);
Walter Jang708ea9e2015-09-10 15:42:05 -0700831 }
Walter Jang23709542015-10-22 12:50:58 -0700832
833 // The raw contact selector should only display linked raw contacts that can be edited in
834 // the full editor (i.e. they are not newly created raw contacts)
Tingting Wang2bb85d22015-10-23 13:01:09 -0700835 final RawContactAccountListAdapter adapter = new RawContactAccountListAdapter(getContext(),
836 getRawContactDeltaListForSelector(rawContactDeltas));
837 if (adapter.getCount() > 0) {
838 final String accountsSummary = getResources().getQuantityString(
839 R.plurals.compact_editor_linked_contacts_selector_title,
840 adapter.getCount(), adapter.getCount());
Walter Jang23709542015-10-22 12:50:58 -0700841 addRawContactAccountSelector(accountsSummary, adapter);
842 }
Walter Jang708ea9e2015-09-10 15:42:05 -0700843 }
844
Tingting Wang2bb85d22015-10-23 13:01:09 -0700845 private RawContactDeltaList getRawContactDeltaListForSelector(
846 RawContactDeltaList rawContactDeltas) {
847 // Sort raw contacts so google accounts come first
848 Collections.sort(rawContactDeltas, new RawContactDeltaComparator(getContext()));
849
850 final RawContactDeltaList result = new RawContactDeltaList();
851 for (RawContactDelta rawContactDelta : rawContactDeltas) {
852 if (rawContactDelta.isVisible() && rawContactDelta.getRawContactId() > 0) {
853 // Only add raw contacts that can be opened in the editor
854 result.add(rawContactDelta);
855 }
856 }
857 // Don't return a list of size 1 that would just open the raw contact being edited
858 // in the compact editor in the full editor
859 if (result.size() == 1 && result.get(0).getRawContactAccountType(
860 getContext()).areContactsWritable()) {
861 result.clear();
862 return result;
863 }
864 return result;
865 }
866
Tingting Wang1594c6f2015-10-26 17:39:16 -0700867 // Returns true if there are multiple writable rawcontacts and no read-only ones,
868 // or there are both writable and read-only rawcontacts.
869 private boolean shouldHideAccountContainer(RawContactDeltaList rawContactDeltas) {
Tingting Wang2bb85d22015-10-23 13:01:09 -0700870 int writable = 0;
871 int readonly = 0;
872 for (RawContactDelta rawContactDelta : rawContactDeltas) {
873 if (rawContactDelta.isVisible() && rawContactDelta.getRawContactId() > 0) {
874 if (rawContactDelta.getRawContactAccountType(getContext()).areContactsWritable()) {
875 writable++;
876 } else {
877 readonly++;
878 }
879 }
880 }
881 return (writable > 1 || (writable > 0 && readonly > 0));
882 }
883
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700884 private void addAccountHeader(String accountLabel) {
Walter Jang82acd422015-10-17 14:01:27 -0700885 mAccountHeaderContainer.setVisibility(View.VISIBLE);
886
Walter Jangbe5e1b12015-10-17 11:38:29 -0700887 // Set the account name
Walter Jangbe5e1b12015-10-17 11:38:29 -0700888 mAccountHeaderName.setVisibility(View.VISIBLE);
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700889 mAccountHeaderName.setText(accountLabel);
Walter Jangbe5e1b12015-10-17 11:38:29 -0700890
891 // Set the account type
892 final String selectorTitle = getResources().getString(
893 R.string.compact_editor_account_selector_title);
894 mAccountHeaderType.setText(selectorTitle);
895
896 // Set the icon
Walter Jang82acd422015-10-17 14:01:27 -0700897 if (mPrimaryNameKindSectionData != null) {
898 final RawContactDelta rawContactDelta =
899 mPrimaryNameKindSectionData.first.getRawContactDelta();
900 if (rawContactDelta != null) {
901 final AccountType accountType =
902 rawContactDelta.getRawContactAccountType(getContext());
903 mAccountHeaderIcon.setImageDrawable(accountType.getDisplayIcon(getContext()));
904 }
905 }
Walter Jangbe5e1b12015-10-17 11:38:29 -0700906
907 // Set the content description
908 mAccountHeaderContainer.setContentDescription(
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700909 EditorUiUtils.getAccountInfoContentDescription(accountLabel,
910 selectorTitle));
Walter Jangbe5e1b12015-10-17 11:38:29 -0700911 }
912
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700913 private void addAccountSelector(final RawContactDelta rawContactDelta, CharSequence nameLabel) {
Gary Mai46cb3102016-08-10 18:14:09 -0700914 // Show save to default account.
Marcus Hagerottfac695a2016-08-24 17:02:40 -0700915 addAccountHeader(nameLabel.toString());
Gary Mai46cb3102016-08-10 18:14:09 -0700916 // Add handlers for choosing another account to save to.
917 mAccountHeaderExpanderIcon.setVisibility(View.VISIBLE);
918 mAccountHeaderContainer.setOnClickListener(new View.OnClickListener() {
Walter Jang708ea9e2015-09-10 15:42:05 -0700919 @Override
920 public void onClick(View v) {
921 final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
922 final AccountsListAdapter adapter =
923 new AccountsListAdapter(getContext(),
924 AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE,
925 mPrimaryAccount);
Gary Mai46cb3102016-08-10 18:14:09 -0700926 popup.setWidth(mAccountHeaderContainer.getWidth());
927 popup.setAnchorView(mAccountHeaderContainer);
Walter Jang708ea9e2015-09-10 15:42:05 -0700928 popup.setAdapter(adapter);
929 popup.setModal(true);
930 popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
931 popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
932 @Override
933 public void onItemClick(AdapterView<?> parent, View view, int position,
934 long id) {
935 UiClosables.closeQuietly(popup);
936 final AccountWithDataSet newAccount = adapter.getItem(position);
937 if (mListener != null && !mPrimaryAccount.equals(newAccount)) {
938 mListener.onRebindEditorsForNewContact(
Walter Jang82acd422015-10-17 14:01:27 -0700939 rawContactDelta,
Walter Jang708ea9e2015-09-10 15:42:05 -0700940 mPrimaryAccount,
941 newAccount);
942 }
943 }
944 });
945 popup.show();
946 }
947 });
948 }
949
Walter Jang23709542015-10-22 12:50:58 -0700950 private void addRawContactAccountSelector(String accountsSummary,
951 final RawContactAccountListAdapter adapter) {
Tingting Wang655ad1a2015-10-05 17:51:14 -0700952 mRawContactContainer.setVisibility(View.VISIBLE);
953
Tingting Wang655ad1a2015-10-05 17:51:14 -0700954 mRawContactSummary.setText(accountsSummary);
Tingting Wang655ad1a2015-10-05 17:51:14 -0700955
956 mRawContactContainer.setOnClickListener(new View.OnClickListener() {
957 @Override
958 public void onClick(View v) {
959 final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
Tingting Wang655ad1a2015-10-05 17:51:14 -0700960 popup.setWidth(mRawContactContainer.getWidth());
961 popup.setAnchorView(mRawContactContainer);
962 popup.setAdapter(adapter);
963 popup.setModal(true);
964 popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
965 popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
966 @Override
967 public void onItemClick(AdapterView<?> parent, View view, int position,
968 long id) {
969 UiClosables.closeQuietly(popup);
Tingting Wang655ad1a2015-10-05 17:51:14 -0700970
971 if (mListener != null) {
Tingting Wang91cee282015-10-07 13:48:17 -0700972 final long rawContactId = adapter.getItemId(position);
973 final Uri rawContactUri = ContentUris.withAppendedId(
974 ContactsContract.RawContacts.CONTENT_URI, rawContactId);
975 final RawContactDelta rawContactDelta = adapter.getItem(position);
976 final AccountTypeManager accountTypes = AccountTypeManager.getInstance(
977 getContext());
978 final AccountType accountType = rawContactDelta.getAccountType(
979 accountTypes);
980 final boolean isReadOnly = !accountType.areContactsWritable();
981
982 mListener.onRawContactSelected(rawContactUri, rawContactId, isReadOnly);
Tingting Wang655ad1a2015-10-05 17:51:14 -0700983 }
984 }
985 });
986 popup.show();
987 }
988 });
989 }
990
Walter Jang363d3fd2015-09-16 10:29:07 -0700991 private void addPhotoView() {
Walter Jang31a74ad2015-10-02 19:17:39 -0700992 // Get the kind section data and values delta that we will display in the photo view
Walter Jangcbd431d2015-10-06 13:07:30 -0700993 final KindSectionDataList kindSectionDataList =
Marcus Hagerottcf7f2952016-09-06 13:49:17 -0700994 getOrCreateKindSectionDataList(Photo.CONTENT_ITEM_TYPE);
Walter Jangcbd431d2015-10-06 13:07:30 -0700995 final Pair<KindSectionData,ValuesDelta> photoToDisplay =
996 kindSectionDataList.getEntryToDisplay(mPhotoId);
997 if (photoToDisplay == null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700998 wlog("photo: no kind section data parsed");
Walter Jangcbd431d2015-10-06 13:07:30 -0700999 mPhotoView.setVisibility(View.GONE);
Walter Jang363d3fd2015-09-16 10:29:07 -07001000 return;
Marcus Hagerottcf7f2952016-09-06 13:49:17 -07001001 } else {
1002 mPhotoView.setVisibility(View.VISIBLE);
Walter Jang363d3fd2015-09-16 10:29:07 -07001003 }
Walter Jang06f73a12015-06-17 11:15:48 -07001004
Walter Jang31a74ad2015-10-02 19:17:39 -07001005 // Set the photo view
Walter Jangcbd431d2015-10-06 13:07:30 -07001006 mPhotoView.setPhoto(photoToDisplay.second, mMaterialPalette);
Walter Jang31a74ad2015-10-02 19:17:39 -07001007
1008 // Find the raw contact ID and values delta that will be written when the photo is edited
Walter Jangda258ff2015-11-17 11:06:02 -08001009 final Pair<KindSectionData, ValuesDelta> photoToWrite = kindSectionDataList.getEntryToWrite(
Walter Jang82acd422015-10-17 14:01:27 -07001010 mPhotoId, mPrimaryAccount, mIsUserProfile);
Walter Jangda258ff2015-11-17 11:06:02 -08001011 if (photoToWrite == null) {
Walter Jang31a74ad2015-10-02 19:17:39 -07001012 mPhotoView.setReadOnly(true);
1013 return;
1014 }
Walter Jang31a74ad2015-10-02 19:17:39 -07001015 mPhotoView.setReadOnly(false);
Walter Jangda258ff2015-11-17 11:06:02 -08001016 mPhotoRawContactId = photoToWrite.first.getRawContactDelta().getRawContactId();
1017 mPhotoValuesDelta = photoToWrite.second;
Walter Jang31a74ad2015-10-02 19:17:39 -07001018 }
1019
Walter Jangf5dfea42015-09-16 12:30:36 -07001020 private void addKindSectionViews() {
1021 // Sort the kinds
Walter Jangcbd431d2015-10-06 13:07:30 -07001022 final TreeSet<Map.Entry<String,KindSectionDataList>> entries =
Walter Jang192a01c2015-09-22 15:23:55 -07001023 new TreeSet<>(KIND_SECTION_DATA_MAP_ENTRY_COMPARATOR);
Walter Jangf5dfea42015-09-16 12:30:36 -07001024 entries.addAll(mKindSectionDataMap.entrySet());
Walter Jang3efae4a2015-02-18 11:12:00 -08001025
Walter Jangf5dfea42015-09-16 12:30:36 -07001026 vlog("kind: " + entries.size() + " kindSection(s)");
Walter Jang3e5ae0d2015-09-20 12:43:37 -07001027 int i = -1;
Walter Jangcbd431d2015-10-06 13:07:30 -07001028 for (Map.Entry<String, KindSectionDataList> entry : entries) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -07001029 i++;
1030
Walter Jangf5dfea42015-09-16 12:30:36 -07001031 final String mimeType = entry.getKey();
Walter Jang82acd422015-10-17 14:01:27 -07001032
Tingting Wangf695eb32015-10-15 18:45:15 -07001033 if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang82acd422015-10-17 14:01:27 -07001034 if (mPrimaryNameKindSectionData == null) {
1035 vlog("kind: " + i + " " + mimeType + " dropped");
1036 continue;
Tingting Wangf695eb32015-10-15 18:45:15 -07001037 }
Walter Jang82acd422015-10-17 14:01:27 -07001038 vlog("kind: " + i + " " + mimeType + " using first entry only");
1039 final KindSectionDataList kindSectionDataList = new KindSectionDataList();
1040 kindSectionDataList.add(mPrimaryNameKindSectionData.first);
Walter Jangf5dfea42015-09-16 12:30:36 -07001041 final CompactKindSectionView kindSectionView = inflateKindSectionView(
Walter Jang82acd422015-10-17 14:01:27 -07001042 mKindSectionViews, kindSectionDataList, mimeType,
1043 mPrimaryNameKindSectionData.second);
Walter Jangf5dfea42015-09-16 12:30:36 -07001044 mKindSectionViews.addView(kindSectionView);
Walter Jangf10ca152015-09-22 15:23:55 -07001045
1046 // Keep a pointer to all the KindSectionsViews for each mimeType
1047 getKindSectionViews(mimeType).add(kindSectionView);
Walter Jang82acd422015-10-17 14:01:27 -07001048 } else {
1049 final KindSectionDataList kindSectionDataList = entry.getValue();
1050
1051 // Ignore mime types that we've already handled
1052 if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
1053 vlog("kind: " + i + " " + mimeType + " dropped");
1054 continue;
1055 }
1056
1057 // Don't show more than one group editor on the compact editor.
1058 // Groups will still be editable for each raw contact individually on the full editor.
1059 if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)
1060 && kindSectionDataList.size() > 1) {
1061 vlog("kind: " + i + " " + mimeType + " dropped");
1062 continue;
1063 }
1064
1065 if (kindSectionDataList != null && !kindSectionDataList.isEmpty()) {
1066 vlog("kind: " + i + " " + mimeType + " " + kindSectionDataList.size() +
1067 " kindSectionData(s)");
1068
1069 final CompactKindSectionView kindSectionView = inflateKindSectionView(
1070 mKindSectionViews, kindSectionDataList, mimeType,
1071 /* primaryValueDelta =*/ null);
1072 mKindSectionViews.addView(kindSectionView);
1073
1074 // Keep a pointer to all the KindSectionsViews for each mimeType
1075 getKindSectionViews(mimeType).add(kindSectionView);
1076 }
Walter Jangcab3dce2015-02-09 17:48:03 -08001077 }
1078 }
1079 }
1080
Walter Jangf10ca152015-09-22 15:23:55 -07001081 private List<CompactKindSectionView> getKindSectionViews(String mimeType) {
1082 List<CompactKindSectionView> kindSectionViews = mKindSectionViewsMap.get(mimeType);
1083 if (kindSectionViews == null) {
1084 kindSectionViews = new ArrayList<>();
1085 mKindSectionViewsMap.put(mimeType, kindSectionViews);
1086 }
1087 return kindSectionViews;
1088 }
1089
Walter Jangf5dfea42015-09-16 12:30:36 -07001090 private CompactKindSectionView inflateKindSectionView(ViewGroup viewGroup,
Walter Jang82acd422015-10-17 14:01:27 -07001091 KindSectionDataList kindSectionDataList, String mimeType,
1092 ValuesDelta primaryValuesDelta) {
Walter Jangf5dfea42015-09-16 12:30:36 -07001093 final CompactKindSectionView kindSectionView = (CompactKindSectionView)
1094 mLayoutInflater.inflate(R.layout.compact_item_kind_section, viewGroup,
1095 /* attachToRoot =*/ false);
Walter Jang45b86d52015-10-15 15:23:16 -07001096 kindSectionView.setIsUserProfile(mIsUserProfile);
Walter Jangf5dfea42015-09-16 12:30:36 -07001097
Walter Jang192a01c2015-09-22 15:23:55 -07001098 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
Walter Jangf5dfea42015-09-16 12:30:36 -07001099 || Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang192a01c2015-09-22 15:23:55 -07001100 // Phone numbers and email addresses are always displayed,
1101 // even if they are empty
Walter Jangf5dfea42015-09-16 12:30:36 -07001102 kindSectionView.setHideWhenEmpty(false);
1103 }
Walter Jangf5dfea42015-09-16 12:30:36 -07001104
Walter Jang192a01c2015-09-22 15:23:55 -07001105 // Since phone numbers and email addresses displayed even if they are empty,
1106 // they will be the only types you add new values to initially for new contacts
1107 kindSectionView.setShowOneEmptyEditor(true);
1108
Walter Jang82acd422015-10-17 14:01:27 -07001109 // Sort non-name editors so they wind up in the order we want
1110 if (!StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang192a01c2015-09-22 15:23:55 -07001111 Collections.sort(kindSectionDataList, new EditorComparator(getContext()));
Walter Jang3e5ae0d2015-09-20 12:43:37 -07001112 }
1113
Walter Jang82acd422015-10-17 14:01:27 -07001114 kindSectionView.setState(kindSectionDataList, mViewIdGenerator, mListener,
1115 primaryValuesDelta);
Walter Jangf5dfea42015-09-16 12:30:36 -07001116
1117 return kindSectionView;
Walter Jangcab3dce2015-02-09 17:48:03 -08001118 }
1119
Walter Jange3945952015-10-27 12:44:54 -07001120 void maybeSetReadOnlyDisplayNameAsPrimary(String readOnlyDisplayName) {
1121 if (TextUtils.isEmpty(readOnlyDisplayName)) return;
1122 final CompactKindSectionView primaryNameKindSectionView = getPrimaryNameKindSectionView();
1123 if (primaryNameKindSectionView != null && primaryNameKindSectionView.isEmptyName()) {
1124 vlog("name: using read only display name as primary name");
1125 primaryNameKindSectionView.setName(readOnlyDisplayName);
1126 }
1127 }
1128
1129 private CompactKindSectionView getPrimaryNameKindSectionView() {
Walter Jang4f5594a2015-10-06 18:40:31 -07001130 final List<CompactKindSectionView> kindSectionViews
1131 = mKindSectionViewsMap.get(StructuredName.CONTENT_ITEM_TYPE);
Walter Jange3945952015-10-27 12:44:54 -07001132 return kindSectionViews == null || kindSectionViews.isEmpty()
1133 ? null : kindSectionViews.get(0);
Walter Jang4f5594a2015-10-06 18:40:31 -07001134 }
1135
Walter Jangd6753152015-10-02 09:23:13 -07001136 private void showAllFields() {
Walter Jang79658e12015-09-24 10:36:26 -07001137 // Stop hiding empty editors and allow the user to enter values for all kinds now
1138 for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
1139 final CompactKindSectionView kindSectionView =
1140 (CompactKindSectionView) mKindSectionViews.getChildAt(i);
1141 kindSectionView.setHideWhenEmpty(false);
1142 kindSectionView.updateEmptyEditors(/* shouldAnimate =*/ true);
1143 }
1144 mIsExpanded = true;
Walter Jang79658e12015-09-24 10:36:26 -07001145
Walter Jangf5dfea42015-09-16 12:30:36 -07001146 // Hide the more fields button
1147 mMoreFields.setVisibility(View.GONE);
Walter Jangcab3dce2015-02-09 17:48:03 -08001148 }
1149
Marcus Hagerottcf7f2952016-09-06 13:49:17 -07001150 private boolean hasMoreFields() {
1151 for (List<CompactKindSectionView> sections : mKindSectionViewsMap.values()) {
1152 for (CompactKindSectionView section : sections) {
1153 if (section.getVisibility() != View.VISIBLE) {
1154 return true;
1155 }
1156 }
1157 }
1158 return false;
1159 }
1160
Walter Jangbf63a6d2015-05-05 09:14:35 -07001161 private static void vlog(String message) {
1162 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1163 Log.v(TAG, message);
Walter Jangcab3dce2015-02-09 17:48:03 -08001164 }
1165 }
Walter Jang363d3fd2015-09-16 10:29:07 -07001166
1167 private static void wlog(String message) {
1168 if (Log.isLoggable(TAG, Log.WARN)) {
1169 Log.w(TAG, message);
1170 }
1171 }
1172
1173 private static void elog(String message) {
1174 Log.e(TAG, message);
1175 }
Walter Jangcab3dce2015-02-09 17:48:03 -08001176}