blob: 8ca638947b0fa7df44ccf3311ad16fde267901b1 [file] [log] [blame]
Walter Jangcab3dce2015-02-09 17:48:03 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.contacts.editor;
18
19import com.android.contacts.R;
20import com.android.contacts.common.model.AccountTypeManager;
21import com.android.contacts.common.model.RawContactDelta;
22import com.android.contacts.common.model.RawContactDeltaList;
Walter Jange720fde2015-02-17 10:54:14 -080023import com.android.contacts.common.model.RawContactModifier;
Walter Jangcab3dce2015-02-09 17:48:03 -080024import com.android.contacts.common.model.ValuesDelta;
25import com.android.contacts.common.model.account.AccountType;
Walter Jang2d3f31c2015-06-18 23:15:31 -070026import com.android.contacts.common.model.account.AccountWithDataSet;
Walter Jangcab3dce2015-02-09 17:48:03 -080027import com.android.contacts.common.model.dataitem.DataKind;
Walter Jang708ea9e2015-09-10 15:42:05 -070028import com.android.contacts.common.util.AccountsListAdapter;
Walter Jangf46abd82015-02-20 16:52:04 -080029import com.android.contacts.common.util.MaterialColorMapUtils;
Walter Jang3efae4a2015-02-18 11:12:00 -080030import com.android.contacts.editor.CompactContactEditorFragment.PhotoHandler;
Walter Jang708ea9e2015-09-10 15:42:05 -070031import com.android.contacts.util.UiClosables;
Walter Jangcab3dce2015-02-09 17:48:03 -080032
33import android.content.Context;
Walter Jangf10ca152015-09-22 15:23:55 -070034import android.database.Cursor;
Walter Jang3efae4a2015-02-18 11:12:00 -080035import android.graphics.Bitmap;
Walter Jang41b3ea12015-03-09 17:30:06 -070036import android.net.Uri;
Walter Jangcab3dce2015-02-09 17:48:03 -080037import android.provider.ContactsContract.CommonDataKinds.Email;
Walter Jangf5dfea42015-09-16 12:30:36 -070038import android.provider.ContactsContract.CommonDataKinds.Event;
Walter Jangcab3dce2015-02-09 17:48:03 -080039import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
Walter Jangf5dfea42015-09-16 12:30:36 -070040import android.provider.ContactsContract.CommonDataKinds.Im;
Walter Jang3efae4a2015-02-18 11:12:00 -080041import android.provider.ContactsContract.CommonDataKinds.Nickname;
Walter Jangf5dfea42015-09-16 12:30:36 -070042import android.provider.ContactsContract.CommonDataKinds.Note;
43import android.provider.ContactsContract.CommonDataKinds.Organization;
Walter Jangcab3dce2015-02-09 17:48:03 -080044import android.provider.ContactsContract.CommonDataKinds.Phone;
45import android.provider.ContactsContract.CommonDataKinds.Photo;
Walter Jangf5dfea42015-09-16 12:30:36 -070046import android.provider.ContactsContract.CommonDataKinds.Relation;
47import android.provider.ContactsContract.CommonDataKinds.SipAddress;
Walter Jangcab3dce2015-02-09 17:48:03 -080048import android.provider.ContactsContract.CommonDataKinds.StructuredName;
Walter Jangf5dfea42015-09-16 12:30:36 -070049import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
50import android.provider.ContactsContract.CommonDataKinds.Website;
Walter Jangcab3dce2015-02-09 17:48:03 -080051import android.text.TextUtils;
52import android.util.AttributeSet;
53import android.util.Log;
Walter Jang2d3f31c2015-06-18 23:15:31 -070054import android.util.Pair;
Walter Jangcab3dce2015-02-09 17:48:03 -080055import android.view.LayoutInflater;
Walter Jangb1c87622015-02-13 17:51:38 -080056import android.view.View;
Walter Jangcab3dce2015-02-09 17:48:03 -080057import android.view.ViewGroup;
Walter Jang708ea9e2015-09-10 15:42:05 -070058import android.widget.AdapterView;
Walter Jangcab3dce2015-02-09 17:48:03 -080059import android.widget.LinearLayout;
Walter Jang708ea9e2015-09-10 15:42:05 -070060import android.widget.ListPopupWindow;
Walter Jang2d3f31c2015-06-18 23:15:31 -070061import android.widget.TextView;
Walter Jangcab3dce2015-02-09 17:48:03 -080062
63import java.util.ArrayList;
Walter Jangf5dfea42015-09-16 12:30:36 -070064import java.util.Arrays;
Walter Jang192a01c2015-09-22 15:23:55 -070065import java.util.Collections;
Walter Jangf5dfea42015-09-16 12:30:36 -070066import java.util.Comparator;
Walter Jang19d985f2015-07-01 13:36:27 -070067import java.util.HashMap;
Walter Jangcab3dce2015-02-09 17:48:03 -080068import java.util.List;
Walter Jang19d985f2015-07-01 13:36:27 -070069import java.util.Map;
Walter Jang708ea9e2015-09-10 15:42:05 -070070import java.util.Objects;
Walter Jangf5dfea42015-09-16 12:30:36 -070071import java.util.TreeSet;
Walter Jangcab3dce2015-02-09 17:48:03 -080072
73/**
Walter Jangf5dfea42015-09-16 12:30:36 -070074 * View to display information from multiple {@link RawContactDelta}s grouped together.
Walter Jangcab3dce2015-02-09 17:48:03 -080075 */
Walter Jangb6ca2722015-02-20 11:10:25 -080076public class CompactRawContactsEditorView extends LinearLayout implements View.OnClickListener {
Walter Jangcab3dce2015-02-09 17:48:03 -080077
78 private static final String TAG = "CompactEditorView";
79
Walter Jang192a01c2015-09-22 15:23:55 -070080 private static final KindSectionDataMapEntryComparator
81 KIND_SECTION_DATA_MAP_ENTRY_COMPARATOR = new KindSectionDataMapEntryComparator();
Walter Jangf5dfea42015-09-16 12:30:36 -070082
Walter Jangb6ca2722015-02-20 11:10:25 -080083 /**
84 * Callbacks for hosts of {@link CompactRawContactsEditorView}s.
85 */
86 public interface Listener {
87
88 /**
Walter Jang151f3e62015-02-26 15:29:40 -080089 * Invoked when the structured name editor field has changed.
90 *
91 * @param rawContactId The raw contact ID from the underlying {@link RawContactDelta}.
92 * @param valuesDelta The values from the underlying {@link RawContactDelta}.
93 */
94 public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta);
Walter Jang708ea9e2015-09-10 15:42:05 -070095
96 /**
97 * Invoked when the compact editor should rebind editors for a new account.
98 *
99 * @param oldState Old data being edited.
100 * @param oldAccount Old account associated with oldState.
101 * @param newAccount New account to be used.
102 */
103 public void onRebindEditorsForNewContact(RawContactDelta oldState,
104 AccountWithDataSet oldAccount, AccountWithDataSet newAccount);
Walter Jang151f3e62015-02-26 15:29:40 -0800105 }
106
Walter Jang192a01c2015-09-22 15:23:55 -0700107 /** Used to sort entire kind sections. */
108 private static final class KindSectionDataMapEntryComparator implements
Walter Jangf5dfea42015-09-16 12:30:36 -0700109 Comparator<Map.Entry<String,List<KindSectionData>>> {
110
Walter Jang192a01c2015-09-22 15:23:55 -0700111 final MimeTypeComparator mMimeTypeComparator = new MimeTypeComparator();
112
113 @Override
114 public int compare(Map.Entry<String, List<KindSectionData>> entry1,
115 Map.Entry<String, List<KindSectionData>> entry2) {
116 if (entry1 == entry2) return 0;
117 if (entry1 == null) return -1;
118 if (entry2 == null) return 1;
119
120 final String mimeType1 = entry1.getKey();
121 final String mimeType2 = entry2.getKey();
122
123 return mMimeTypeComparator.compare(mimeType1, mimeType2);
124 }
125 }
126
127 /**
128 * Sorts kinds roughly the same as quick contacts; we diverge in the following ways:
129 * <ol>
130 * <li>All names are together at the top.</li>
131 * <li>IM is moved up after addresses</li>
132 * <li>SIP addresses are moved to below phone numbers</li>
Walter Jangf10ca152015-09-22 15:23:55 -0700133 * <li>Group membership is palced at the end</li>
Walter Jang192a01c2015-09-22 15:23:55 -0700134 * </ol>
135 */
136 private static final class MimeTypeComparator implements Comparator<String> {
137
Walter Jangf5dfea42015-09-16 12:30:36 -0700138 private static final List<String> MIME_TYPE_ORDER = Arrays.asList(new String[] {
139 StructuredName.CONTENT_ITEM_TYPE,
Walter Jangf5dfea42015-09-16 12:30:36 -0700140 Nickname.CONTENT_ITEM_TYPE,
141 Phone.CONTENT_ITEM_TYPE,
142 SipAddress.CONTENT_ITEM_TYPE,
143 Email.CONTENT_ITEM_TYPE,
144 StructuredPostal.CONTENT_ITEM_TYPE,
145 Im.CONTENT_ITEM_TYPE,
146 Website.CONTENT_ITEM_TYPE,
147 Organization.CONTENT_ITEM_TYPE,
148 Event.CONTENT_ITEM_TYPE,
149 Relation.CONTENT_ITEM_TYPE,
Walter Jangf10ca152015-09-22 15:23:55 -0700150 Note.CONTENT_ITEM_TYPE,
151 GroupMembership.CONTENT_ITEM_TYPE
Walter Jangf5dfea42015-09-16 12:30:36 -0700152 });
153
154 @Override
Walter Jang192a01c2015-09-22 15:23:55 -0700155 public int compare(String mimeType1, String mimeType2) {
156 if (mimeType1 == mimeType2) return 0;
157 if (mimeType1 == null) return -1;
158 if (mimeType2 == null) return 1;
Walter Jangf5dfea42015-09-16 12:30:36 -0700159
160 int index1 = MIME_TYPE_ORDER.indexOf(mimeType1);
161 int index2 = MIME_TYPE_ORDER.indexOf(mimeType2);
162
163 // Fallback to alphabetical ordering of the mime type if both are not found
164 if (index1 < 0 && index2 < 0) return mimeType1.compareTo(mimeType2);
165 if (index1 < 0) return 1;
166 if (index2 < 0) return -1;
167
168 return index1 < index2 ? -1 : 1;
169 }
170 }
171
Walter Jang192a01c2015-09-22 15:23:55 -0700172 /**
173 * Sorts primary accounts and google account types before others.
174 */
175 private static final class EditorComparator implements Comparator<KindSectionData> {
176
177 private RawContactDeltaComparator mRawContactDeltaComparator;
178
179 private EditorComparator(Context context) {
180 mRawContactDeltaComparator = new RawContactDeltaComparator(context);
181 }
182
183 @Override
184 public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
185 if (kindSectionData1 == kindSectionData2) return 0;
186 if (kindSectionData1 == null) return -1;
187 if (kindSectionData2 == null) return 1;
188
189 final RawContactDelta rawContactDelta1 = kindSectionData1.getRawContactDelta();
190 final RawContactDelta rawContactDelta2 = kindSectionData2.getRawContactDelta();
191
192 if (rawContactDelta1 == rawContactDelta2) return 0;
193 if (rawContactDelta1 == null) return -1;
194 if (rawContactDelta2 == null) return 1;
195
196 return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
197 }
198 }
199
200 /**
201 * Sorts primary account names first, followed by google account types, and other account
202 * types last. For names from the same account we order structured names before nicknames,
203 * but still keep names from the same account together.
204 */
205 private static final class NameEditorComparator implements Comparator<KindSectionData> {
206
207 private RawContactDeltaComparator mRawContactDeltaComparator;
208 private MimeTypeComparator mMimeTypeComparator;
209 private RawContactDelta mPrimaryRawContactDelta;
210
211 private NameEditorComparator(Context context, RawContactDelta primaryRawContactDelta) {
212 mRawContactDeltaComparator = new RawContactDeltaComparator(context);
213 mMimeTypeComparator = new MimeTypeComparator();
214 mPrimaryRawContactDelta = primaryRawContactDelta;
215 }
216
217 @Override
218 public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
219 if (kindSectionData1 == kindSectionData2) return 0;
220 if (kindSectionData1 == null) return -1;
221 if (kindSectionData2 == null) return 1;
222
223 final RawContactDelta rawContactDelta1 = kindSectionData1.getRawContactDelta();
224 final RawContactDelta rawContactDelta2 = kindSectionData2.getRawContactDelta();
225
226 if (rawContactDelta1 == rawContactDelta2) return 0;
227 if (rawContactDelta1 == null) return -1;
228 if (rawContactDelta2 == null) return 1;
229
230 final boolean isRawContactDelta1Primary =
231 mPrimaryRawContactDelta.equals(rawContactDelta1);
232 final boolean isRawContactDelta2Primary =
233 mPrimaryRawContactDelta.equals(rawContactDelta2);
234
235 // If both names are from the primary account, sort my by mime type
236 if (isRawContactDelta1Primary && isRawContactDelta2Primary) {
237 final String mimeType1 = kindSectionData1.getDataKind().mimeType;
238 final String mimeType2 = kindSectionData2.getDataKind().mimeType;
239 return mMimeTypeComparator.compare(mimeType1, mimeType2);
240 }
241
242 // The primary account name should be before all others
243 if (isRawContactDelta1Primary) return 1;
244 if (isRawContactDelta2Primary) return -1;
245
246 return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
247 }
248 }
249
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700250 private CompactRawContactsEditorView.Listener mListener;
Walter Jangb6ca2722015-02-20 11:10:25 -0800251
Walter Jangcab3dce2015-02-09 17:48:03 -0800252 private AccountTypeManager mAccountTypeManager;
253 private LayoutInflater mLayoutInflater;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800254
Walter Jangcab3dce2015-02-09 17:48:03 -0800255 private ViewIdGenerator mViewIdGenerator;
Walter Jangf46abd82015-02-20 16:52:04 -0800256 private MaterialColorMapUtils.MaterialPalette mMaterialPalette;
Walter Jang708ea9e2015-09-10 15:42:05 -0700257 private long mPhotoId;
Walter Jang708ea9e2015-09-10 15:42:05 -0700258 private boolean mHasNewContact;
259 private boolean mIsUserProfile;
260 private AccountWithDataSet mPrimaryAccount;
261 private RawContactDelta mPrimaryRawContactDelta;
Walter Jang363d3fd2015-09-16 10:29:07 -0700262 private Map<String,List<KindSectionData>> mKindSectionDataMap = new HashMap<>();
Walter Jangcab3dce2015-02-09 17:48:03 -0800263
Walter Jang708ea9e2015-09-10 15:42:05 -0700264 // Account header
265 private View mAccountHeaderContainer;
266 private TextView mAccountHeaderType;
267 private TextView mAccountHeaderName;
268
269 // Account selector
270 private View mAccountSelectorContainer;
271 private View mAccountSelector;
272 private TextView mAccountSelectorType;
273 private TextView mAccountSelectorName;
274
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700275 private CompactPhotoEditorView mPhotoView;
Walter Jangf5dfea42015-09-16 12:30:36 -0700276 private ViewGroup mKindSectionViews;
Walter Jangf10ca152015-09-22 15:23:55 -0700277 private Map<String,List<CompactKindSectionView>> mKindSectionViewsMap = new HashMap<>();
Walter Jangb6ca2722015-02-20 11:10:25 -0800278 private View mMoreFields;
Walter Jangcab3dce2015-02-09 17:48:03 -0800279
Walter Jang3efae4a2015-02-18 11:12:00 -0800280 private long mPhotoRawContactId;
281
Walter Jangcab3dce2015-02-09 17:48:03 -0800282 public CompactRawContactsEditorView(Context context) {
283 super(context);
284 }
285
286 public CompactRawContactsEditorView(Context context, AttributeSet attrs) {
287 super(context, attrs);
288 }
289
Walter Jangb6ca2722015-02-20 11:10:25 -0800290 /**
291 * Sets the receiver for {@link CompactRawContactsEditorView} callbacks.
292 */
293 public void setListener(Listener listener) {
294 mListener = listener;
295 }
296
Walter Jangcab3dce2015-02-09 17:48:03 -0800297 @Override
298 protected void onFinishInflate() {
299 super.onFinishInflate();
300
301 mAccountTypeManager = AccountTypeManager.getInstance(getContext());
302 mLayoutInflater = (LayoutInflater)
303 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
304
Walter Jang708ea9e2015-09-10 15:42:05 -0700305 // Account header
306 mAccountHeaderContainer = findViewById(R.id.account_container);
307 mAccountHeaderType = (TextView) findViewById(R.id.account_type);
308 mAccountHeaderName = (TextView) findViewById(R.id.account_name);
309
310 // Account selector
311 mAccountSelectorContainer = findViewById(R.id.account_selector_container);
312 mAccountSelector = findViewById(R.id.account);
313 mAccountSelectorType = (TextView) findViewById(R.id.account_type_selector);
314 mAccountSelectorName = (TextView) findViewById(R.id.account_name_selector);
315
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700316 mPhotoView = (CompactPhotoEditorView) findViewById(R.id.photo_editor);
Walter Jangf5dfea42015-09-16 12:30:36 -0700317 mKindSectionViews = (LinearLayout) findViewById(R.id.kind_section_views);
Walter Jangb6ca2722015-02-20 11:10:25 -0800318 mMoreFields = findViewById(R.id.more_fields);
319 mMoreFields.setOnClickListener(this);
320 }
321
Walter Jangb6ca2722015-02-20 11:10:25 -0800322 @Override
323 public void onClick(View view) {
Walter Jangf5dfea42015-09-16 12:30:36 -0700324 if (view.getId() == R.id.more_fields) {
325 // Stop hiding empty editors and allow the user to enter values for all kinds now
326 for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
327 final CompactKindSectionView kindSectionView =
328 (CompactKindSectionView) mKindSectionViews.getChildAt(i);
329 kindSectionView.setHideWhenEmpty(false);
Walter Jang192a01c2015-09-22 15:23:55 -0700330 // Except the user is never allowed to add new names
331 final String mimeType = kindSectionView.getMimeType();
332 if (!StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700333 kindSectionView.setShowOneEmptyEditor(true);
334 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700335 kindSectionView.updateEmptyEditors(/* shouldAnimate =*/ false);
336 }
337
338 updateMoreFieldsButton();
Walter Jangb6ca2722015-02-20 11:10:25 -0800339 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800340 }
341
342 @Override
343 public void setEnabled(boolean enabled) {
344 super.setEnabled(enabled);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700345 final int childCount = mKindSectionViews.getChildCount();
346 for (int i = 0; i < childCount; i++) {
347 mKindSectionViews.getChildAt(i).setEnabled(enabled);
Walter Jangcab3dce2015-02-09 17:48:03 -0800348 }
349 }
350
Walter Jang3efae4a2015-02-18 11:12:00 -0800351 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800352 * Pass through to {@link CompactPhotoEditorView#setPhotoHandler}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800353 */
354 public void setPhotoHandler(PhotoHandler photoHandler) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700355 mPhotoView.setPhotoHandler(photoHandler);
Walter Jang3efae4a2015-02-18 11:12:00 -0800356 }
357
358 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800359 * Pass through to {@link CompactPhotoEditorView#setPhoto}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800360 */
361 public void setPhoto(Bitmap bitmap) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700362 mPhotoView.setPhoto(bitmap);
Walter Jang3efae4a2015-02-18 11:12:00 -0800363 }
364
365 /**
Walter Jang41b3ea12015-03-09 17:30:06 -0700366 * Pass through to {@link CompactPhotoEditorView#setFullSizedPhoto(Uri)}.
367 */
368 public void setFullSizePhoto(Uri photoUri) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700369 mPhotoView.setFullSizedPhoto(photoUri);
Walter Jang41b3ea12015-03-09 17:30:06 -0700370 }
371
372 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800373 * Pass through to {@link CompactPhotoEditorView#isWritablePhotoSet}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800374 */
375 public boolean isWritablePhotoSet() {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700376 return mPhotoView.isWritablePhotoSet();
Walter Jang3efae4a2015-02-18 11:12:00 -0800377 }
378
379 /**
Walter Jang3efae4a2015-02-18 11:12:00 -0800380 * Get the raw contact ID for the CompactHeaderView photo.
381 */
Walter Jang3efae4a2015-02-18 11:12:00 -0800382 public long getPhotoRawContactId() {
383 return mPhotoRawContactId;
384 }
385
Walter Jangd35e5ef2015-02-24 09:18:16 -0800386 public View getAggregationAnchorView() {
Walter Jangf10ca152015-09-22 15:23:55 -0700387 final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
Walter Jang192a01c2015-09-22 15:23:55 -0700388 StructuredName.CONTENT_ITEM_TYPE);
Walter Jangf10ca152015-09-22 15:23:55 -0700389 if (!kindSectionViews.isEmpty()) {
Walter Jang192a01c2015-09-22 15:23:55 -0700390 return mKindSectionViews.getChildAt(0).findViewById(R.id.anchor_view);
Walter Jangd35e5ef2015-02-24 09:18:16 -0800391 }
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700392 return null;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800393 }
394
Walter Jangf10ca152015-09-22 15:23:55 -0700395 public void setGroupMetaData(Cursor groupMetaData) {
396 final List<CompactKindSectionView> kindSectionViews = getKindSectionViews(
397 GroupMembership.CONTENT_ITEM_TYPE);
398 for (CompactKindSectionView kindSectionView : kindSectionViews) {
399 kindSectionView.setGroupMetaData(groupMetaData);
400 }
401 }
402
Walter Jangf46abd82015-02-20 16:52:04 -0800403 public void setState(RawContactDeltaList rawContactDeltas,
Walter Jang06f73a12015-06-17 11:15:48 -0700404 MaterialColorMapUtils.MaterialPalette materialPalette, ViewIdGenerator viewIdGenerator,
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700405 long photoId, boolean hasNewContact, boolean isUserProfile,
406 AccountWithDataSet primaryAccount) {
407 // Clear previous state and reset views
Walter Jang363d3fd2015-09-16 10:29:07 -0700408 mKindSectionDataMap.clear();
Walter Jangf5dfea42015-09-16 12:30:36 -0700409 mKindSectionViews.removeAllViews();
Walter Jang363d3fd2015-09-16 10:29:07 -0700410 mMoreFields.setVisibility(View.VISIBLE);
Walter Jangcab3dce2015-02-09 17:48:03 -0800411
Walter Jangf46abd82015-02-20 16:52:04 -0800412 mMaterialPalette = materialPalette;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700413 mViewIdGenerator = viewIdGenerator;
Walter Jang708ea9e2015-09-10 15:42:05 -0700414 mPhotoId = photoId;
Walter Jang708ea9e2015-09-10 15:42:05 -0700415 mHasNewContact = hasNewContact;
416 mIsUserProfile = isUserProfile;
417 mPrimaryAccount = primaryAccount;
418 if (mPrimaryAccount == null) {
419 mPrimaryAccount = ContactEditorUtils.getInstance(getContext()).getDefaultAccount();
420 }
421 vlog("state: primary " + mPrimaryAccount);
Walter Jangcab3dce2015-02-09 17:48:03 -0800422
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700423 // Parse the given raw contact deltas
424 if (rawContactDeltas == null || rawContactDeltas.isEmpty()) {
425 elog("No raw contact deltas");
Walter Jangf5dfea42015-09-16 12:30:36 -0700426 return;
427 }
Walter Jang192a01c2015-09-22 15:23:55 -0700428 parseRawContactDeltas(rawContactDeltas, mPrimaryAccount);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700429 if (mKindSectionDataMap == null || mKindSectionDataMap.isEmpty()) {
430 elog("No kind section data parsed from RawContactDelta(s)");
431 return;
432 }
433
434 // Setup the view
435 setId(mViewIdGenerator.getId(rawContactDeltas.get(0), /* dataKind =*/ null,
436 /* valuesDelta =*/ null, ViewIdGenerator.NO_VIEW_INDEX));
Walter Jang708ea9e2015-09-10 15:42:05 -0700437 addAccountInfo();
Walter Jang363d3fd2015-09-16 10:29:07 -0700438 addPhotoView();
Walter Jangf5dfea42015-09-16 12:30:36 -0700439 addKindSectionViews();
Walter Jangf5dfea42015-09-16 12:30:36 -0700440 updateMoreFieldsButton();
Walter Jangcab3dce2015-02-09 17:48:03 -0800441 }
442
Walter Jang192a01c2015-09-22 15:23:55 -0700443 private void parseRawContactDeltas(RawContactDeltaList rawContactDeltas,
444 AccountWithDataSet primaryAccount) {
445 if (primaryAccount != null) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700446 // Use the first writable contact that matches the primary account
447 for (RawContactDelta rawContactDelta : rawContactDeltas) {
448 if (!rawContactDelta.isVisible()) continue;
449 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700450 if (accountType == null || !accountType.areContactsWritable()) continue;
Walter Jang192a01c2015-09-22 15:23:55 -0700451 if (matchesAccount(primaryAccount, rawContactDelta)) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700452 vlog("parse: matched primary account raw contact");
Walter Jang708ea9e2015-09-10 15:42:05 -0700453 mPrimaryRawContactDelta = rawContactDelta;
454 break;
455 }
Walter Jang2d3f31c2015-06-18 23:15:31 -0700456 }
457 }
Walter Jang708ea9e2015-09-10 15:42:05 -0700458 if (mPrimaryRawContactDelta == null) {
459 // Fall back to the first writable raw contact
460 for (RawContactDelta rawContactDelta : rawContactDeltas) {
461 if (!rawContactDelta.isVisible()) continue;
462 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
463 if (accountType != null && accountType.areContactsWritable()) {
464 vlog("parse: falling back to the first writable raw contact as primary");
465 mPrimaryRawContactDelta = rawContactDelta;
466 break;
467 }
468 }
Walter Jang2d3f31c2015-06-18 23:15:31 -0700469 }
Walter Jang192a01c2015-09-22 15:23:55 -0700470
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700471 if (mPrimaryRawContactDelta != null) {
472 RawContactModifier.ensureKindExists(mPrimaryRawContactDelta,
473 mPrimaryRawContactDelta.getAccountType(mAccountTypeManager),
474 StructuredName.CONTENT_ITEM_TYPE);
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700475 RawContactModifier.ensureKindExists(mPrimaryRawContactDelta,
476 mPrimaryRawContactDelta.getAccountType(mAccountTypeManager),
477 Photo.CONTENT_ITEM_TYPE);
478 }
Walter Jangfa127a12015-06-18 09:48:18 -0700479
Walter Jang363d3fd2015-09-16 10:29:07 -0700480 // Build the kind section data list map
Walter Jang192a01c2015-09-22 15:23:55 -0700481 vlog("parse: " + rawContactDeltas.size() + " rawContactDelta(s)");
482 for (int j = 0; j < rawContactDeltas.size(); j++) {
483 final RawContactDelta rawContactDelta = rawContactDeltas.get(j);
484 vlog("parse: " + j + " rawContactDelta" + rawContactDelta);
Walter Jang363d3fd2015-09-16 10:29:07 -0700485 if (rawContactDelta == null || !rawContactDelta.isVisible()) continue;
Walter Jangcab3dce2015-02-09 17:48:03 -0800486 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
Walter Jang363d3fd2015-09-16 10:29:07 -0700487 if (accountType == null) continue;
488 final List<DataKind> dataKinds = accountType.getSortedDataKinds();
489 final int dataKindSize = dataKinds == null ? 0 : dataKinds.size();
490 vlog("parse: " + dataKindSize + " dataKinds(s)");
491 for (int i = 0; i < dataKindSize; i++) {
492 final DataKind dataKind = dataKinds.get(i);
Walter Jang192a01c2015-09-22 15:23:55 -0700493 if (dataKind == null || !dataKind.editable) {
494 vlog("parse: " + i + " " + dataKind.mimeType + " dropped read-only");
495 continue;
496 }
497 final String mimeType = dataKind.mimeType;
498
499 // Skip psuedo mime types
500 if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
501 || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
502 vlog("parse: " + i + " " + dataKind.mimeType + " dropped pseudo type");
503 continue;
504 }
505
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700506 final List<KindSectionData> kindSectionDataList =
Walter Jang192a01c2015-09-22 15:23:55 -0700507 getKindSectionDataList(mimeType);
Walter Jang363d3fd2015-09-16 10:29:07 -0700508 final KindSectionData kindSectionData =
509 new KindSectionData(accountType, dataKind, rawContactDelta);
510 kindSectionDataList.add(kindSectionData);
Walter Jang192a01c2015-09-22 15:23:55 -0700511
512 // Note we must create a nickname entry on inserts
513 if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)
514 && kindSectionData.getValuesDeltas().isEmpty()
515 && mHasNewContact) {
516 RawContactModifier.insertChild(rawContactDelta, dataKind);
517 }
518
Walter Jang363d3fd2015-09-16 10:29:07 -0700519 vlog("parse: " + i + " " + dataKind.mimeType + " " +
Walter Jang192a01c2015-09-22 15:23:55 -0700520 kindSectionData.getValuesDeltas().size() + " value(s)");
Walter Jangac679af2015-06-01 12:17:06 -0700521 }
522 }
Walter Jang3efae4a2015-02-18 11:12:00 -0800523 }
524
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700525 private List<KindSectionData> getKindSectionDataList(String mimeType) {
Walter Jang192a01c2015-09-22 15:23:55 -0700526 // Put structured names and nicknames together
527 mimeType = Nickname.CONTENT_ITEM_TYPE.equals(mimeType)
528 ? StructuredName.CONTENT_ITEM_TYPE : mimeType;
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700529 List<KindSectionData> kindSectionDataList = mKindSectionDataMap.get(mimeType);
530 if (kindSectionDataList == null) {
531 kindSectionDataList = new ArrayList<>();
532 mKindSectionDataMap.put(mimeType, kindSectionDataList);
533 }
534 return kindSectionDataList;
535 }
536
Walter Jang192a01c2015-09-22 15:23:55 -0700537 /** Whether the given RawContactDelta belong to the given account. */
538 private boolean matchesAccount(AccountWithDataSet accountWithDataSet,
539 RawContactDelta rawContactDelta) {
540 if (accountWithDataSet == null) return false;
541 return Objects.equals(accountWithDataSet.name, rawContactDelta.getAccountName())
542 && Objects.equals(accountWithDataSet.type, rawContactDelta.getAccountType())
543 && Objects.equals(accountWithDataSet.dataSet, rawContactDelta.getDataSet());
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700544 }
545
Walter Jang708ea9e2015-09-10 15:42:05 -0700546 private void addAccountInfo() {
547 if (mPrimaryRawContactDelta == null) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700548 mAccountHeaderContainer.setVisibility(View.GONE);
549 mAccountSelectorContainer.setVisibility(View.GONE);
550 return;
551 }
552
553 // Get the account information for the primary raw contact delta
554 final Pair<String,String> accountInfo = EditorUiUtils.getAccountInfo(getContext(),
555 mIsUserProfile, mPrimaryRawContactDelta.getAccountName(),
556 mPrimaryRawContactDelta.getAccountType(mAccountTypeManager));
557
558 // The account header and selector show the same information so both shouldn't be visible
559 // at the same time
560 final List<AccountWithDataSet> accounts =
561 AccountTypeManager.getInstance(getContext()).getAccounts(true);
562 if (mHasNewContact && !mIsUserProfile && accounts.size() > 1) {
563 mAccountHeaderContainer.setVisibility(View.GONE);
564 addAccountSelector(accountInfo);
565 } else {
566 addAccountHeader(accountInfo);
567 mAccountSelectorContainer.setVisibility(View.GONE);
568 }
569 }
570
571 private void addAccountHeader(Pair<String,String> accountInfo) {
Walter Jang03cea2e2015-09-18 17:04:21 -0700572 if (TextUtils.isEmpty(accountInfo.first)) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700573 // Hide this view so the other text view will be centered vertically
574 mAccountHeaderName.setVisibility(View.GONE);
575 } else {
576 mAccountHeaderName.setVisibility(View.VISIBLE);
577 mAccountHeaderName.setText(accountInfo.first);
578 }
579 mAccountHeaderType.setText(accountInfo.second);
580
581 mAccountHeaderContainer.setContentDescription(
582 EditorUiUtils.getAccountInfoContentDescription(
583 accountInfo.first, accountInfo.second));
584 }
585
586 private void addAccountSelector(Pair<String,String> accountInfo) {
587 mAccountSelectorContainer.setVisibility(View.VISIBLE);
588
Walter Jang03cea2e2015-09-18 17:04:21 -0700589 if (TextUtils.isEmpty(accountInfo.first)) {
Walter Jang708ea9e2015-09-10 15:42:05 -0700590 // Hide this view so the other text view will be centered vertically
591 mAccountSelectorName.setVisibility(View.GONE);
592 } else {
593 mAccountSelectorName.setVisibility(View.VISIBLE);
594 mAccountSelectorName.setText(accountInfo.first);
595 }
596 mAccountSelectorType.setText(accountInfo.second);
597
598 mAccountSelectorContainer.setContentDescription(
599 EditorUiUtils.getAccountInfoContentDescription(
600 accountInfo.first, accountInfo.second));
601
602 mAccountSelector.setOnClickListener(new View.OnClickListener() {
603 @Override
604 public void onClick(View v) {
605 final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
606 final AccountsListAdapter adapter =
607 new AccountsListAdapter(getContext(),
608 AccountsListAdapter.AccountListFilter.ACCOUNTS_CONTACT_WRITABLE,
609 mPrimaryAccount);
610 popup.setWidth(mAccountSelectorContainer.getWidth());
611 popup.setAnchorView(mAccountSelectorContainer);
612 popup.setAdapter(adapter);
613 popup.setModal(true);
614 popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
615 popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
616 @Override
617 public void onItemClick(AdapterView<?> parent, View view, int position,
618 long id) {
619 UiClosables.closeQuietly(popup);
620 final AccountWithDataSet newAccount = adapter.getItem(position);
621 if (mListener != null && !mPrimaryAccount.equals(newAccount)) {
622 mListener.onRebindEditorsForNewContact(
623 mPrimaryRawContactDelta,
624 mPrimaryAccount,
625 newAccount);
626 }
627 }
628 });
629 popup.show();
630 }
631 });
632 }
633
Walter Jang363d3fd2015-09-16 10:29:07 -0700634 private void addPhotoView() {
635 // Get the kind section data and values delta that will back the photo view
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700636 Pair<KindSectionData,ValuesDelta> pair = getPrimaryKindSectionData(mPhotoId);
Walter Jang363d3fd2015-09-16 10:29:07 -0700637 if (pair == null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700638 wlog("photo: no kind section data parsed");
Walter Jang363d3fd2015-09-16 10:29:07 -0700639 return;
640 }
641 final KindSectionData kindSectionData = pair.first;
642 final ValuesDelta valuesDelta = pair.second;
Walter Jang06f73a12015-06-17 11:15:48 -0700643
Walter Jang363d3fd2015-09-16 10:29:07 -0700644 // If we're editing a read-only contact we want to display the photo from the
645 // read-only contact in a photo editor backed by the new raw contact
Walter Jang192a01c2015-09-22 15:23:55 -0700646 // that was created.
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700647 if (mHasNewContact) {
648 mPhotoRawContactId = mPrimaryRawContactDelta == null
649 ? null : mPrimaryRawContactDelta.getRawContactId();
Walter Jang363d3fd2015-09-16 10:29:07 -0700650 }
Walter Jang06f73a12015-06-17 11:15:48 -0700651
Walter Jang363d3fd2015-09-16 10:29:07 -0700652 mPhotoRawContactId = kindSectionData.getRawContactDelta().getRawContactId();
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700653 mPhotoView.setValues(kindSectionData.getDataKind(), valuesDelta,
Walter Jang363d3fd2015-09-16 10:29:07 -0700654 kindSectionData.getRawContactDelta(),
655 !kindSectionData.getAccountType().areContactsWritable(), mMaterialPalette,
656 mViewIdGenerator);
657 }
658
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700659 private Pair<KindSectionData,ValuesDelta> getPrimaryKindSectionData(long id) {
660 final String mimeType = Photo.CONTENT_ITEM_TYPE;
Walter Jang363d3fd2015-09-16 10:29:07 -0700661 final List<KindSectionData> kindSectionDataList = mKindSectionDataMap.get(mimeType);
662 if (kindSectionDataList == null || kindSectionDataList.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700663 wlog("photo: no kind section data parsed");
Walter Jang363d3fd2015-09-16 10:29:07 -0700664 return null;
665 }
Walter Jang151f3e62015-02-26 15:29:40 -0800666
Walter Jang363d3fd2015-09-16 10:29:07 -0700667 KindSectionData resultKindSectionData = null;
668 ValuesDelta resultValuesDelta = null;
669 if (id > 0) {
670 // Look for a match for the ID that was passed in
671 for (KindSectionData kindSectionData : kindSectionDataList) {
672 resultValuesDelta = kindSectionData.getValuesDeltaById(id);
673 if (resultValuesDelta != null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700674 vlog("photo: matched kind section data by ID");
Walter Jang363d3fd2015-09-16 10:29:07 -0700675 resultKindSectionData = kindSectionData;
676 break;
Walter Jang398cd4b2015-06-16 11:17:53 -0700677 }
678 }
679 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700680 if (resultKindSectionData == null) {
681 // Look for a super primary photo
682 for (KindSectionData kindSectionData : kindSectionDataList) {
683 resultValuesDelta = kindSectionData.getSuperPrimaryValuesDelta();
684 if (resultValuesDelta != null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700685 wlog("photo: matched super primary kind section data");
Walter Jang363d3fd2015-09-16 10:29:07 -0700686 resultKindSectionData = kindSectionData;
687 break;
688 }
Walter Jang151f3e62015-02-26 15:29:40 -0800689 }
690 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700691 if (resultKindSectionData == null) {
692 // Fall back to the first non-empty value
693 for (KindSectionData kindSectionData : kindSectionDataList) {
694 resultValuesDelta = kindSectionData.getFirstNonEmptyValuesDelta();
695 if (resultValuesDelta != null) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700696 vlog("photo: using first non empty value");
Walter Jang363d3fd2015-09-16 10:29:07 -0700697 resultKindSectionData = kindSectionData;
698 break;
699 }
Walter Jang151f3e62015-02-26 15:29:40 -0800700 }
701 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700702 if (resultKindSectionData == null || resultValuesDelta == null) {
703 final List<ValuesDelta> valuesDeltaList = kindSectionDataList.get(0).getValuesDeltas();
704 if (valuesDeltaList != null && !valuesDeltaList.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700705 vlog("photo: falling back to first empty entry");
Walter Jang363d3fd2015-09-16 10:29:07 -0700706 resultValuesDelta = valuesDeltaList.get(0);
707 resultKindSectionData = kindSectionDataList.get(0);
Walter Jang10446452015-02-20 13:51:16 -0800708 }
709 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700710 return resultKindSectionData != null && resultValuesDelta != null
711 ? new Pair<>(resultKindSectionData, resultValuesDelta) : null;
Walter Jang10446452015-02-20 13:51:16 -0800712 }
713
Walter Jangf5dfea42015-09-16 12:30:36 -0700714 private void addKindSectionViews() {
715 // Sort the kinds
716 final TreeSet<Map.Entry<String,List<KindSectionData>>> entries =
Walter Jang192a01c2015-09-22 15:23:55 -0700717 new TreeSet<>(KIND_SECTION_DATA_MAP_ENTRY_COMPARATOR);
Walter Jangf5dfea42015-09-16 12:30:36 -0700718 entries.addAll(mKindSectionDataMap.entrySet());
Walter Jang3efae4a2015-02-18 11:12:00 -0800719
Walter Jangf5dfea42015-09-16 12:30:36 -0700720 vlog("kind: " + entries.size() + " kindSection(s)");
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700721 int i = -1;
Walter Jangf5dfea42015-09-16 12:30:36 -0700722 for (Map.Entry<String, List<KindSectionData>> entry : entries) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700723 i++;
724
Walter Jangf5dfea42015-09-16 12:30:36 -0700725 final String mimeType = entry.getKey();
726 final List<KindSectionData> kindSectionDataList = entry.getValue();
Walter Jangab50e6f2015-06-15 08:57:22 -0700727
Walter Jangf5dfea42015-09-16 12:30:36 -0700728 // Ignore mime types that we've already handled
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700729 if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
730 vlog("kind: " + i + " " + mimeType + " dropped");
731 continue;
732 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700733
Walter Jang192a01c2015-09-22 15:23:55 -0700734 if (kindSectionDataList != null && !kindSectionDataList.isEmpty()) {
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700735 vlog("kind: " + i + " " + mimeType + ": " + kindSectionDataList.size() +
736 " kindSectionData(s)");
737
Walter Jangf5dfea42015-09-16 12:30:36 -0700738 final CompactKindSectionView kindSectionView = inflateKindSectionView(
739 mKindSectionViews, kindSectionDataList, mimeType);
Walter Jangf5dfea42015-09-16 12:30:36 -0700740 mKindSectionViews.addView(kindSectionView);
Walter Jangf10ca152015-09-22 15:23:55 -0700741
742 // Keep a pointer to all the KindSectionsViews for each mimeType
743 getKindSectionViews(mimeType).add(kindSectionView);
Walter Jangcab3dce2015-02-09 17:48:03 -0800744 }
745 }
746 }
747
Walter Jangf10ca152015-09-22 15:23:55 -0700748 private List<CompactKindSectionView> getKindSectionViews(String mimeType) {
749 List<CompactKindSectionView> kindSectionViews = mKindSectionViewsMap.get(mimeType);
750 if (kindSectionViews == null) {
751 kindSectionViews = new ArrayList<>();
752 mKindSectionViewsMap.put(mimeType, kindSectionViews);
753 }
754 return kindSectionViews;
755 }
756
Walter Jangf5dfea42015-09-16 12:30:36 -0700757 private CompactKindSectionView inflateKindSectionView(ViewGroup viewGroup,
758 List<KindSectionData> kindSectionDataList, String mimeType) {
759 final CompactKindSectionView kindSectionView = (CompactKindSectionView)
760 mLayoutInflater.inflate(R.layout.compact_item_kind_section, viewGroup,
761 /* attachToRoot =*/ false);
762
Walter Jang192a01c2015-09-22 15:23:55 -0700763 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
Walter Jangf5dfea42015-09-16 12:30:36 -0700764 || Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang192a01c2015-09-22 15:23:55 -0700765 // Phone numbers and email addresses are always displayed,
766 // even if they are empty
Walter Jangf5dfea42015-09-16 12:30:36 -0700767 kindSectionView.setHideWhenEmpty(false);
768 }
Walter Jangf5dfea42015-09-16 12:30:36 -0700769
Walter Jang192a01c2015-09-22 15:23:55 -0700770 // Since phone numbers and email addresses displayed even if they are empty,
771 // they will be the only types you add new values to initially for new contacts
772 kindSectionView.setShowOneEmptyEditor(true);
773
774 // Sort so the editors wind up in the order we want
775 if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
776 Collections.sort(kindSectionDataList, new NameEditorComparator(getContext(),
777 mPrimaryRawContactDelta));
778 } else {
779 Collections.sort(kindSectionDataList, new EditorComparator(getContext()));
Walter Jang3e5ae0d2015-09-20 12:43:37 -0700780 }
781
782 kindSectionView.setState(kindSectionDataList, /* readOnly =*/ false, mViewIdGenerator,
783 mListener);
Walter Jangf5dfea42015-09-16 12:30:36 -0700784
785 return kindSectionView;
Walter Jangcab3dce2015-02-09 17:48:03 -0800786 }
787
Walter Jangf5dfea42015-09-16 12:30:36 -0700788 private void updateMoreFieldsButton() {
789 // If any kind section views are hidden then show the link
790 for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
791 final CompactKindSectionView kindSectionView =
792 (CompactKindSectionView) mKindSectionViews.getChildAt(i);
793 if (kindSectionView.getVisibility() == View.GONE) {
794 // Show the more fields button
795 mMoreFields.setVisibility(View.VISIBLE);
796 return;
797 }
798 }
799 // Hide the more fields button
800 mMoreFields.setVisibility(View.GONE);
Walter Jangcab3dce2015-02-09 17:48:03 -0800801 }
802
Walter Jangbf63a6d2015-05-05 09:14:35 -0700803 private static void vlog(String message) {
804 if (Log.isLoggable(TAG, Log.VERBOSE)) {
805 Log.v(TAG, message);
Walter Jangcab3dce2015-02-09 17:48:03 -0800806 }
807 }
Walter Jang363d3fd2015-09-16 10:29:07 -0700808
809 private static void wlog(String message) {
810 if (Log.isLoggable(TAG, Log.WARN)) {
811 Log.w(TAG, message);
812 }
813 }
814
815 private static void elog(String message) {
816 Log.e(TAG, message);
817 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800818}