blob: cb605c645234e9d2d71414f62e1be01c5dde76a6 [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;
26import com.android.contacts.common.model.account.AccountType.EditField;
27import com.android.contacts.common.model.dataitem.DataKind;
Walter Jangf46abd82015-02-20 16:52:04 -080028import com.android.contacts.common.util.MaterialColorMapUtils;
Walter Jang3efae4a2015-02-18 11:12:00 -080029import com.android.contacts.editor.CompactContactEditorFragment.PhotoHandler;
Walter Jangcab3dce2015-02-09 17:48:03 -080030
31import android.content.Context;
Walter Jang3efae4a2015-02-18 11:12:00 -080032import android.graphics.Bitmap;
Walter Jangcab3dce2015-02-09 17:48:03 -080033import android.provider.ContactsContract.CommonDataKinds.Email;
34import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
Walter Jang3efae4a2015-02-18 11:12:00 -080035import android.provider.ContactsContract.CommonDataKinds.Nickname;
Walter Jangcab3dce2015-02-09 17:48:03 -080036import android.provider.ContactsContract.CommonDataKinds.Phone;
37import android.provider.ContactsContract.CommonDataKinds.Photo;
Walter Jangcab3dce2015-02-09 17:48:03 -080038import android.provider.ContactsContract.CommonDataKinds.StructuredName;
39import android.text.TextUtils;
40import android.util.AttributeSet;
41import android.util.Log;
42import android.view.LayoutInflater;
Walter Jangb1c87622015-02-13 17:51:38 -080043import android.view.View;
Walter Jangcab3dce2015-02-09 17:48:03 -080044import android.view.ViewGroup;
45import android.widget.LinearLayout;
46
47import java.util.ArrayList;
48import java.util.List;
49
50/**
51 * View to display information from multiple {@link RawContactDelta}s grouped together
52 * (e.g. all the phone numbers from a {@link com.android.contacts.common.model.Contact} together.
53 */
Walter Jangb6ca2722015-02-20 11:10:25 -080054public class CompactRawContactsEditorView extends LinearLayout implements View.OnClickListener {
Walter Jangcab3dce2015-02-09 17:48:03 -080055
56 private static final String TAG = "CompactEditorView";
57
Walter Jangb6ca2722015-02-20 11:10:25 -080058 /**
59 * Callbacks for hosts of {@link CompactRawContactsEditorView}s.
60 */
61 public interface Listener {
62
63 /**
64 * Invoked when the compact editor should be expanded to show all fields.
65 */
66 public void onExpandEditor();
Walter Jang151f3e62015-02-26 15:29:40 -080067
68 /**
69 * Invoked when the structured name editor field has changed.
70 *
71 * @param rawContactId The raw contact ID from the underlying {@link RawContactDelta}.
72 * @param valuesDelta The values from the underlying {@link RawContactDelta}.
73 */
74 public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta);
75 }
76
77 /**
78 * Marks a name as super primary when it is changed.
79 *
80 * This is for the case when two or more raw contacts with names are joined where neither is
81 * marked as super primary. If the user hits back (which causes a save) after changing the
82 * name that was arbitrarily displayed, we want that to be the name that is used.
83 *
84 * Should only be set when a super primary name does not already exist since we only show
85 * one name field.
86 */
87 static final class NameEditorListener implements Editor.EditorListener {
88
89 private final ValuesDelta mValuesDelta;
90 private final long mRawContactId;
91 private final Listener mListener;
92
93 public NameEditorListener(ValuesDelta valuesDelta, long rawContactId,
94 Listener listener) {
95 mValuesDelta = valuesDelta;
96 mRawContactId = rawContactId;
97 mListener = listener;
98 }
99
100 @Override
101 public void onRequest(int request) {
102 if (request == Editor.EditorListener.FIELD_CHANGED) {
103 mValuesDelta.setSuperPrimary(true);
104 if (mListener != null) {
105 mListener.onNameFieldChanged(mRawContactId, mValuesDelta);
106 }
107 } else if (request == Editor.EditorListener.FIELD_TURNED_EMPTY) {
108 mValuesDelta.setSuperPrimary(false);
109 }
110 }
111
112 @Override
113 public void onDeleteRequested(Editor editor) {
114 }
Walter Jangb6ca2722015-02-20 11:10:25 -0800115 }
116
117 private Listener mListener;
118
Walter Jangcab3dce2015-02-09 17:48:03 -0800119 private AccountTypeManager mAccountTypeManager;
120 private LayoutInflater mLayoutInflater;
Walter Jangd35e5ef2015-02-24 09:18:16 -0800121
Walter Jangcab3dce2015-02-09 17:48:03 -0800122 private ViewIdGenerator mViewIdGenerator;
Walter Jangf46abd82015-02-20 16:52:04 -0800123 private MaterialColorMapUtils.MaterialPalette mMaterialPalette;
Walter Jangcab3dce2015-02-09 17:48:03 -0800124
Walter Janga5e4bb22015-02-24 13:08:16 -0800125 private CompactPhotoEditorView mPhoto;
Walter Jangcab3dce2015-02-09 17:48:03 -0800126 private ViewGroup mNames;
Walter Jangb1c87622015-02-13 17:51:38 -0800127 private ViewGroup mPhoneticNames;
128 private ViewGroup mNicknames;
Walter Jangcab3dce2015-02-09 17:48:03 -0800129 private ViewGroup mPhoneNumbers;
130 private ViewGroup mEmails;
131 private ViewGroup mOther;
Walter Jangb6ca2722015-02-20 11:10:25 -0800132 private View mMoreFields;
Walter Jangcab3dce2015-02-09 17:48:03 -0800133
Walter Jang151f3e62015-02-26 15:29:40 -0800134 // The ValuesDelta for the non super primary name that was displayed to the user.
135 private ValuesDelta mNameValuesDelta;
136
Walter Jang3efae4a2015-02-18 11:12:00 -0800137 private long mPhotoRawContactId;
138
Walter Jangcab3dce2015-02-09 17:48:03 -0800139 public CompactRawContactsEditorView(Context context) {
140 super(context);
141 }
142
143 public CompactRawContactsEditorView(Context context, AttributeSet attrs) {
144 super(context, attrs);
145 }
146
Walter Jangb6ca2722015-02-20 11:10:25 -0800147 /**
148 * Sets the receiver for {@link CompactRawContactsEditorView} callbacks.
149 */
150 public void setListener(Listener listener) {
151 mListener = listener;
152 }
153
Walter Jangcab3dce2015-02-09 17:48:03 -0800154 @Override
155 protected void onFinishInflate() {
156 super.onFinishInflate();
157
158 mAccountTypeManager = AccountTypeManager.getInstance(getContext());
159 mLayoutInflater = (LayoutInflater)
160 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
161
Walter Janga5e4bb22015-02-24 13:08:16 -0800162 mPhoto = (CompactPhotoEditorView) findViewById(R.id.photo_editor);
Walter Jangcab3dce2015-02-09 17:48:03 -0800163 mNames = (LinearLayout) findViewById(R.id.names);
Walter Jangb1c87622015-02-13 17:51:38 -0800164 mPhoneticNames = (LinearLayout) findViewById(R.id.phonetic_names);
165 mNicknames = (LinearLayout) findViewById(R.id.nicknames);
Walter Jangcab3dce2015-02-09 17:48:03 -0800166 mPhoneNumbers = (LinearLayout) findViewById(R.id.phone_numbers);
167 mEmails = (LinearLayout) findViewById(R.id.emails);
168 mOther = (LinearLayout) findViewById(R.id.other);
Walter Jangb6ca2722015-02-20 11:10:25 -0800169 mMoreFields = findViewById(R.id.more_fields);
170 mMoreFields.setOnClickListener(this);
171 }
172
Walter Jangb6ca2722015-02-20 11:10:25 -0800173 @Override
174 public void onClick(View view) {
175 if (view.getId() == R.id.more_fields && mListener != null ) {
Walter Jang151f3e62015-02-26 15:29:40 -0800176 // We mark the name that was displayed as super primary before expanding
177 // so that a save on the expanded editor (without a name change) does not
178 // cause the displayed name to change.
179 if (mNameValuesDelta != null) {
180 mNameValuesDelta.setSuperPrimary(true);
181 }
182
Walter Jangb6ca2722015-02-20 11:10:25 -0800183 mListener.onExpandEditor();
184 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800185 }
186
187 @Override
188 public void setEnabled(boolean enabled) {
189 super.setEnabled(enabled);
190 setEnabled(enabled, mNames);
Walter Jangb1c87622015-02-13 17:51:38 -0800191 setEnabled(enabled, mPhoneticNames);
192 setEnabled(enabled, mNicknames);
Walter Jangcab3dce2015-02-09 17:48:03 -0800193 setEnabled(enabled, mPhoneNumbers);
194 setEnabled(enabled, mEmails);
195 setEnabled(enabled, mOther);
196 }
197
198 private void setEnabled(boolean enabled, ViewGroup viewGroup) {
199 if (viewGroup != null) {
200 final int childCount = viewGroup.getChildCount();
201 for (int i = 0; i < childCount; i++) {
202 viewGroup.getChildAt(i).setEnabled(enabled);
203 }
204 }
205 }
206
Walter Jang3efae4a2015-02-18 11:12:00 -0800207 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800208 * Pass through to {@link CompactPhotoEditorView#setPhotoHandler}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800209 */
210 public void setPhotoHandler(PhotoHandler photoHandler) {
Walter Janga5e4bb22015-02-24 13:08:16 -0800211 mPhoto.setPhotoHandler(photoHandler);
Walter Jang3efae4a2015-02-18 11:12:00 -0800212 }
213
214 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800215 * Pass through to {@link CompactPhotoEditorView#setPhoto}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800216 */
217 public void setPhoto(Bitmap bitmap) {
Walter Janga5e4bb22015-02-24 13:08:16 -0800218 mPhoto.setPhoto(bitmap);
Walter Jang3efae4a2015-02-18 11:12:00 -0800219 }
220
221 /**
Walter Janga5e4bb22015-02-24 13:08:16 -0800222 * Pass through to {@link CompactPhotoEditorView#isWritablePhotoSet}.
Walter Jang3efae4a2015-02-18 11:12:00 -0800223 */
224 public boolean isWritablePhotoSet() {
Walter Janga5e4bb22015-02-24 13:08:16 -0800225 return mPhoto.isWritablePhotoSet();
Walter Jang3efae4a2015-02-18 11:12:00 -0800226 }
227
228 /**
Walter Jang3efae4a2015-02-18 11:12:00 -0800229 * Get the raw contact ID for the CompactHeaderView photo.
230 */
Walter Jang3efae4a2015-02-18 11:12:00 -0800231 public long getPhotoRawContactId() {
232 return mPhotoRawContactId;
233 }
234
Walter Jangd35e5ef2015-02-24 09:18:16 -0800235 public StructuredNameEditorView getStructuredNameEditorView() {
236 // We only ever show one StructuredName
237 return mNames.getChildCount() == 0
238 ? null : (StructuredNameEditorView) mNames.getChildAt(0);
239 }
240
241 public View getAggregationAnchorView() {
242 // Since there is only one structured name we can just return it as the anchor for
243 // the aggregation suggestions popup
244 if (mNames.getChildCount() == 0) {
245 return null;
246 }
247 return mNames.getChildAt(0).findViewById(R.id.anchor_view);
248 }
249
Walter Jangf46abd82015-02-20 16:52:04 -0800250 public void setState(RawContactDeltaList rawContactDeltas,
251 MaterialColorMapUtils.MaterialPalette materialPalette,
252 ViewIdGenerator viewIdGenerator) {
Walter Jangcab3dce2015-02-09 17:48:03 -0800253 mNames.removeAllViews();
Walter Jangb1c87622015-02-13 17:51:38 -0800254 mPhoneticNames.removeAllViews();
255 mNicknames.removeAllViews();
Walter Jangcab3dce2015-02-09 17:48:03 -0800256 mPhoneNumbers.removeAllViews();
257 mEmails.removeAllViews();
258 mOther.removeAllViews();
259
260 if (rawContactDeltas == null || rawContactDeltas.isEmpty()) {
261 return;
262 }
263
264 mViewIdGenerator = viewIdGenerator;
Walter Jangcab3dce2015-02-09 17:48:03 -0800265 setId(mViewIdGenerator.getId(rawContactDeltas.get(0), /* dataKind =*/ null,
266 /* valuesDelta =*/ null, ViewIdGenerator.NO_VIEW_INDEX));
Walter Jangf46abd82015-02-20 16:52:04 -0800267 mMaterialPalette = materialPalette;
Walter Jangcab3dce2015-02-09 17:48:03 -0800268
Walter Jang151f3e62015-02-26 15:29:40 -0800269 addPhotoView(rawContactDeltas, viewIdGenerator);
Walter Jang10446452015-02-20 13:51:16 -0800270 addStructuredNameView(rawContactDeltas);
Walter Jang3efae4a2015-02-18 11:12:00 -0800271 addEditorViews(rawContactDeltas);
Walter Jange720fde2015-02-17 10:54:14 -0800272 removeExtraEmptyTextFields(mPhoneNumbers);
273 removeExtraEmptyTextFields(mEmails);
Walter Jangcab3dce2015-02-09 17:48:03 -0800274 }
275
Walter Jang151f3e62015-02-26 15:29:40 -0800276 private void addPhotoView(RawContactDeltaList rawContactDeltas,
Walter Jange720fde2015-02-17 10:54:14 -0800277 ViewIdGenerator viewIdGenerator) {
Walter Jangcab3dce2015-02-09 17:48:03 -0800278 for (RawContactDelta rawContactDelta : rawContactDeltas) {
279 if (!rawContactDelta.isVisible()) {
280 continue;
281 }
282 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
Walter Jange720fde2015-02-17 10:54:14 -0800283
Walter Jang3efae4a2015-02-18 11:12:00 -0800284 // Make sure we have a photo
285 RawContactModifier.ensureKindExists(
286 rawContactDelta, accountType, Photo.CONTENT_ITEM_TYPE);
287
288 final DataKind dataKind = accountType.getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
289 if (dataKind != null) {
Walter Jang10446452015-02-20 13:51:16 -0800290 if (Photo.CONTENT_ITEM_TYPE.equals(dataKind.mimeType)) {
Walter Jang3efae4a2015-02-18 11:12:00 -0800291 mPhotoRawContactId = rawContactDelta.getRawContactId();
292 final ValuesDelta valuesDelta = rawContactDelta.getSuperPrimaryEntry(
Walter Jang10446452015-02-20 13:51:16 -0800293 dataKind.mimeType, /* forceSelection =*/ true);
Walter Janga5e4bb22015-02-24 13:08:16 -0800294 mPhoto.setValues(dataKind, valuesDelta, rawContactDelta,
Walter Jangf46abd82015-02-20 16:52:04 -0800295 /* readOnly =*/ !dataKind.editable, mMaterialPalette, viewIdGenerator);
Walter Jang3efae4a2015-02-18 11:12:00 -0800296 return;
297 }
298 }
299 }
300 }
301
Walter Jang10446452015-02-20 13:51:16 -0800302 private void addStructuredNameView(RawContactDeltaList rawContactDeltas) {
303 for (RawContactDelta rawContactDelta : rawContactDeltas) {
Walter Jang151f3e62015-02-26 15:29:40 -0800304 if (!rawContactDelta.isVisible()) continue;
Walter Jang10446452015-02-20 13:51:16 -0800305 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
306
307 // Make sure we have a structured name
308 RawContactModifier.ensureKindExists(
309 rawContactDelta, accountType, StructuredName.CONTENT_ITEM_TYPE);
310
Walter Jang151f3e62015-02-26 15:29:40 -0800311 // Note use of pseudo mime type to get the DataKind and StructuredName to get value
Walter Jang10446452015-02-20 13:51:16 -0800312 final DataKind dataKind = accountType.getKindForMimetype(
Walter Jang151f3e62015-02-26 15:29:40 -0800313 DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
314 if (dataKind == null || !dataKind.editable) continue;
315
316 final ValuesDelta superPrimaryValuesDelta = getNonEmptySuperPrimaryValuesDeltas(
317 rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind);
318 if (superPrimaryValuesDelta != null) {
319 // Our first preference is for a non-empty super primary name
320 mNames.addView(inflateStructuredNameEditorView(mNames, accountType,
321 superPrimaryValuesDelta, rawContactDelta, /* nameEditorListener =*/ null));
322 return;
323 }
324 }
325 // We didn't find a super primary name
326 for (RawContactDelta rawContactDelta : rawContactDeltas) {
327 if (!rawContactDelta.isVisible()) continue;
328 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
329
330 final DataKind dataKind = accountType.getKindForMimetype(
331 DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
332 if (dataKind == null || !dataKind.editable) continue;
333
334 final List<ValuesDelta> nonEmptyValuesDeltas = getNonEmptyValuesDeltas(
335 rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind);
336 if (nonEmptyValuesDeltas != null && !nonEmptyValuesDeltas.isEmpty()) {
337 // Take the first non-empty name, also make it super primary before expanding to the
338 // full editor (see #onCLick) so that name does not change if the user saves from
339 // the fully expanded editor.
340 mNameValuesDelta = nonEmptyValuesDeltas.get(0);
341 final NameEditorListener nameEditorListener = new NameEditorListener(
342 mNameValuesDelta, rawContactDelta.getRawContactId(), mListener);
343 mNames.addView(inflateStructuredNameEditorView(mNames, accountType,
344 mNameValuesDelta, rawContactDelta, nameEditorListener));
345 return;
346 }
347 }
348 for (RawContactDelta rawContactDelta : rawContactDeltas) {
349 if (!rawContactDelta.isVisible()) continue;
350 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
351
352 final DataKind dataKind = accountType.getKindForMimetype(
353 DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
354 if (dataKind == null || !dataKind.editable) continue;
355
356 // Fall back to the first entry
357 final ArrayList<ValuesDelta> valuesDeltas = rawContactDelta.getMimeEntries(
Walter Jang10446452015-02-20 13:51:16 -0800358 StructuredName.CONTENT_ITEM_TYPE);
Walter Jang151f3e62015-02-26 15:29:40 -0800359 if (valuesDeltas != null && !valuesDeltas.isEmpty()) {
360 mNameValuesDelta = valuesDeltas.get(0);
361 final NameEditorListener nameEditorListener = new NameEditorListener(
362 mNameValuesDelta, rawContactDelta.getRawContactId(), mListener);
363 mNames.addView(inflateStructuredNameEditorView(mNames, accountType,
364 mNameValuesDelta, rawContactDelta, nameEditorListener));
365 return;
Walter Jang10446452015-02-20 13:51:16 -0800366 }
367 }
368 }
369
Walter Jang3efae4a2015-02-18 11:12:00 -0800370 private void addEditorViews(RawContactDeltaList rawContactDeltas) {
371 for (RawContactDelta rawContactDelta : rawContactDeltas) {
372 if (!rawContactDelta.isVisible()) {
373 continue;
374 }
375 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
376
Walter Jangcab3dce2015-02-09 17:48:03 -0800377 for (DataKind dataKind : accountType.getSortedDataKinds()) {
378 if (!dataKind.editable) {
379 continue;
380 }
381 final String mimeType = dataKind.mimeType;
382 log(Log.VERBOSE, mimeType + " " + dataKind.fieldList.size() + " field(s)");
383 if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)
Walter Jang10446452015-02-20 13:51:16 -0800384 || StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)
Walter Jangcab3dce2015-02-09 17:48:03 -0800385 || GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang151f3e62015-02-26 15:29:40 -0800386 // Photos and structured names are handled separately and
387 // group membership is not supported
Walter Jangcab3dce2015-02-09 17:48:03 -0800388 continue;
Walter Jangcab3dce2015-02-09 17:48:03 -0800389 } else if (DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
Walter Jang151f3e62015-02-26 15:29:40 -0800390 // Only add phonetic names if there is a non-empty one. Note the use of
391 // StructuredName mimeType below, even though we matched a pseudo mime type.
392 if (hasNonEmptyValuesDelta(
Walter Jangcab3dce2015-02-09 17:48:03 -0800393 rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind)) {
Walter Jang151f3e62015-02-26 15:29:40 -0800394 for (ValuesDelta valuesDelta : getNonEmptyValuesDeltas(
395 rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind)) {
396 mPhoneticNames.addView(inflatePhoneticNameEditorView(
397 mPhoneticNames, accountType, valuesDelta, rawContactDelta));
398 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800399 }
400 } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jang151f3e62015-02-26 15:29:40 -0800401 // Only add nicknames if there is a non-empty one
Walter Jangcab3dce2015-02-09 17:48:03 -0800402 if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
Walter Jang151f3e62015-02-26 15:29:40 -0800403 mNicknames.addView(inflateKindSectionView(
Walter Jangb1c87622015-02-13 17:51:38 -0800404 mNicknames, dataKind, rawContactDelta));
Walter Jangcab3dce2015-02-09 17:48:03 -0800405 }
406 } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jange720fde2015-02-17 10:54:14 -0800407 mPhoneNumbers.addView(inflateKindSectionView(
408 mPhoneNumbers, dataKind, rawContactDelta));
Walter Jangcab3dce2015-02-09 17:48:03 -0800409 } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
Walter Jange720fde2015-02-17 10:54:14 -0800410 mEmails.addView(inflateKindSectionView(
411 mEmails, dataKind, rawContactDelta));
Walter Jangcab3dce2015-02-09 17:48:03 -0800412 } else if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
413 mOther.addView(inflateKindSectionView(
414 mOther, dataKind, rawContactDelta));
415 }
416 }
417 }
418 }
419
Walter Jange720fde2015-02-17 10:54:14 -0800420 // TODO: avoid inflating extra views and deleting them
421 private void removeExtraEmptyTextFields(ViewGroup viewGroup) {
422 // If there is one (or less) editors, leave it whether it is empty or not
423 if (viewGroup.getChildCount() <= 1) {
Walter Jangb1c87622015-02-13 17:51:38 -0800424 return;
425 }
Walter Jange720fde2015-02-17 10:54:14 -0800426 // Determine if there are any non-empty editors
427 boolean hasAtLeastOneNonEmptyEditorView = false;
428 for (int i = 0; i < viewGroup.getChildCount(); i++) {
429 if (!isEmptyEditorView(viewGroup.getChildAt(i))) {
430 hasAtLeastOneNonEmptyEditorView = true;
Walter Jangb1c87622015-02-13 17:51:38 -0800431 break;
432 }
433 }
Walter Jange720fde2015-02-17 10:54:14 -0800434 if (hasAtLeastOneNonEmptyEditorView) {
435 // There is at least one non-empty editor, remove all the empty ones
436 for (int i = 0; i < viewGroup.getChildCount(); i++) {
437 if (isEmptyEditorView(viewGroup.getChildAt(i))) {
438 viewGroup.getChildAt(i).setVisibility(View.GONE);
Walter Jangb1c87622015-02-13 17:51:38 -0800439 }
440 }
441 } else {
Walter Jange720fde2015-02-17 10:54:14 -0800442 // There is no non-empty editor, keep the first empty view and remove the rest
443 for (int i = 1; i < viewGroup.getChildCount(); i++) {
444 viewGroup.getChildAt(i).setVisibility(View.GONE);
Walter Jangb1c87622015-02-13 17:51:38 -0800445 }
446 }
447 }
448
Walter Jange720fde2015-02-17 10:54:14 -0800449 private static boolean isEmptyEditorView(View view) {
450 if (view instanceof TextFieldsEditorView) {
451 final TextFieldsEditorView textFieldsEditorView = (TextFieldsEditorView) view;
452 return textFieldsEditorView.isEmpty();
453 }
454 if (view instanceof KindSectionView) {
455 final KindSectionView kindSectionView = (KindSectionView) view;
456 return kindSectionView.hasEmptyEditor();
457 }
458 return false;
459 }
460
Walter Jangcab3dce2015-02-09 17:48:03 -0800461 private static boolean hasNonEmptyValuesDelta(RawContactDelta rawContactDelta,
462 String mimeType, DataKind dataKind) {
463 return !getNonEmptyValuesDeltas(rawContactDelta, mimeType, dataKind).isEmpty();
464 }
465
Walter Jang151f3e62015-02-26 15:29:40 -0800466 private static ValuesDelta getNonEmptySuperPrimaryValuesDeltas(RawContactDelta rawContactDelta,
467 String mimeType, DataKind dataKind) {
468 for (ValuesDelta valuesDelta : getNonEmptyValuesDeltas(
469 rawContactDelta, mimeType, dataKind)) {
470 if (valuesDelta.isSuperPrimary()) {
471 return valuesDelta;
472 }
473 }
474 return null;
475 }
476
477 static List<ValuesDelta> getNonEmptyValuesDeltas(RawContactDelta rawContactDelta,
Walter Jangcab3dce2015-02-09 17:48:03 -0800478 String mimeType, DataKind dataKind) {
479 final List<ValuesDelta> result = new ArrayList<>();
480 if (rawContactDelta == null) {
481 log(Log.VERBOSE, "Null RawContactDelta");
482 return result;
483 }
484 if (!rawContactDelta.hasMimeEntries(mimeType)) {
485 log(Log.VERBOSE, "No ValueDeltas");
486 return result;
487 }
488 for (ValuesDelta valuesDelta : rawContactDelta.getMimeEntries(mimeType)) {
489 if (valuesDelta == null) {
490 log(Log.VERBOSE, "Null valuesDelta");
491 }
492 for (EditField editField : dataKind.fieldList) {
493 final String column = editField.column;
494 final String value = valuesDelta == null ? null : valuesDelta.getAsString(column);
495 log(Log.VERBOSE, "Field " + column + " empty=" + TextUtils.isEmpty(value) +
496 " value=" + value);
497 if (!TextUtils.isEmpty(value)) {
498 result.add(valuesDelta);
499 }
500 }
501 }
502 return result;
503 }
504
Walter Jangcab3dce2015-02-09 17:48:03 -0800505 private StructuredNameEditorView inflateStructuredNameEditorView(ViewGroup viewGroup,
Walter Jang151f3e62015-02-26 15:29:40 -0800506 AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta,
507 NameEditorListener nameEditorListener) {
Walter Jangcab3dce2015-02-09 17:48:03 -0800508 final StructuredNameEditorView result = (StructuredNameEditorView) mLayoutInflater.inflate(
509 R.layout.structured_name_editor_view, viewGroup, /* attachToRoot =*/ false);
Walter Jang151f3e62015-02-26 15:29:40 -0800510 if (nameEditorListener != null) {
511 result.setEditorListener(nameEditorListener);
512 }
Walter Jangcab3dce2015-02-09 17:48:03 -0800513 result.setValues(
514 accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
515 valuesDelta,
516 rawContactDelta,
517 /* readOnly =*/ false,
518 mViewIdGenerator);
519 return result;
520 }
521
522 private PhoneticNameEditorView inflatePhoneticNameEditorView(ViewGroup viewGroup,
523 AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
524 final PhoneticNameEditorView result = (PhoneticNameEditorView) mLayoutInflater.inflate(
525 R.layout.phonetic_name_editor_view, viewGroup, /* attachToRoot =*/ false);
526 result.setValues(
527 accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME),
528 valuesDelta,
529 rawContactDelta,
530 /* readOnly =*/ false,
531 mViewIdGenerator);
532 return result;
533 }
534
Walter Jangcab3dce2015-02-09 17:48:03 -0800535 private KindSectionView inflateKindSectionView(ViewGroup viewGroup, DataKind dataKind,
536 RawContactDelta rawContactDelta) {
537 final KindSectionView result = (KindSectionView) mLayoutInflater.inflate(
538 R.layout.item_kind_section, viewGroup, /* attachToRoot =*/ false);
539 result.setState(
540 dataKind,
541 rawContactDelta,
542 /* readOnly =*/ false,
Walter Jang10446452015-02-20 13:51:16 -0800543 /* showOneEmptyEditor =*/ false,
Walter Jangcab3dce2015-02-09 17:48:03 -0800544 mViewIdGenerator);
545 return result;
546 }
547
548 private static void log(int level, String message) {
549 log(TAG, level, message);
550 }
551
552 private static void log(String tag, int level, String message) {
553 if (Log.isLoggable(tag, level)) {
554 switch (level) {
555 case Log.VERBOSE:
556 Log.v(tag, message);
557 break;
558 case Log.DEBUG:
559 Log.d(tag, message);
560 break;
561 case Log.INFO:
562 Log.i(tag, message);
563 break;
564 case Log.WARN:
565 Log.w(tag, message);
566 break;
567 case Log.ERROR:
568 Log.e(tag, message);
569 break;
570 default:
571 Log.v(tag, message);
572 break;
573 }
574 }
575 }
576}