blob: 2855fff5d53e96f78313a05fe06bbe21bc6052fe [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;
23import com.android.contacts.common.model.ValuesDelta;
24import com.android.contacts.common.model.account.AccountType;
25import com.android.contacts.common.model.account.AccountType.EditField;
26import com.android.contacts.common.model.dataitem.DataKind;
27
28import android.content.Context;
29import android.provider.ContactsContract.CommonDataKinds.Email;
30import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
31import android.provider.ContactsContract.CommonDataKinds.Phone;
32import android.provider.ContactsContract.CommonDataKinds.Photo;
33import android.provider.ContactsContract.CommonDataKinds.Nickname;
34import android.provider.ContactsContract.CommonDataKinds.StructuredName;
35import android.text.TextUtils;
36import android.util.AttributeSet;
37import android.util.Log;
38import android.view.LayoutInflater;
39import android.view.ViewGroup;
40import android.widget.LinearLayout;
41
42import java.util.ArrayList;
43import java.util.List;
44
45/**
46 * View to display information from multiple {@link RawContactDelta}s grouped together
47 * (e.g. all the phone numbers from a {@link com.android.contacts.common.model.Contact} together.
48 */
49public class CompactRawContactsEditorView extends LinearLayout {
50
51 private static final String TAG = "CompactEditorView";
52
53 private AccountTypeManager mAccountTypeManager;
54 private LayoutInflater mLayoutInflater;
55 private ViewIdGenerator mViewIdGenerator;
56
57 private ViewGroup mNames;
58 private ViewGroup mPhoneNumbers;
59 private ViewGroup mEmails;
60 private ViewGroup mOther;
61
62 public CompactRawContactsEditorView(Context context) {
63 super(context);
64 }
65
66 public CompactRawContactsEditorView(Context context, AttributeSet attrs) {
67 super(context, attrs);
68 }
69
70 @Override
71 protected void onFinishInflate() {
72 super.onFinishInflate();
73
74 mAccountTypeManager = AccountTypeManager.getInstance(getContext());
75 mLayoutInflater = (LayoutInflater)
76 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
77
78 mNames = (LinearLayout) findViewById(R.id.names);
79 mPhoneNumbers = (LinearLayout) findViewById(R.id.phone_numbers);
80 mEmails = (LinearLayout) findViewById(R.id.emails);
81 mOther = (LinearLayout) findViewById(R.id.other);
82 }
83
84 @Override
85 public void setEnabled(boolean enabled) {
86 super.setEnabled(enabled);
87 setEnabled(enabled, mNames);
88 setEnabled(enabled, mPhoneNumbers);
89 setEnabled(enabled, mEmails);
90 setEnabled(enabled, mOther);
91 }
92
93 private void setEnabled(boolean enabled, ViewGroup viewGroup) {
94 if (viewGroup != null) {
95 final int childCount = viewGroup.getChildCount();
96 for (int i = 0; i < childCount; i++) {
97 viewGroup.getChildAt(i).setEnabled(enabled);
98 }
99 }
100 }
101
102 public void setState(RawContactDeltaList rawContactDeltas, ViewIdGenerator viewIdGenerator) {
103 mNames.removeAllViews();
104 mPhoneNumbers.removeAllViews();
105 mEmails.removeAllViews();
106 mOther.removeAllViews();
107
108 if (rawContactDeltas == null || rawContactDeltas.isEmpty()) {
109 return;
110 }
111
112 mViewIdGenerator = viewIdGenerator;
113
114 setId(mViewIdGenerator.getId(rawContactDeltas.get(0), /* dataKind =*/ null,
115 /* valuesDelta =*/ null, ViewIdGenerator.NO_VIEW_INDEX));
116
117 addEditorViews(rawContactDeltas);
118 }
119
120 private void addEditorViews(RawContactDeltaList rawContactDeltas) {
121 for (RawContactDelta rawContactDelta : rawContactDeltas) {
122 if (!rawContactDelta.isVisible()) {
123 continue;
124 }
125 final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
126 for (DataKind dataKind : accountType.getSortedDataKinds()) {
127 if (!dataKind.editable) {
128 continue;
129 }
130 final String mimeType = dataKind.mimeType;
131 log(Log.VERBOSE, mimeType + " " + dataKind.fieldList.size() + " field(s)");
132 if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)
133 || GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
134 // Photos are handled separately and group membership is not supported
135 continue;
136 } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
137 final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(mimeType);
138
139 if (valuesDelta != null) {
140 mNames.addView(inflateStructuredNameEditorView(
141 mNames, accountType, valuesDelta, rawContactDelta));
142 }
143 } else if (DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
144 // Use the StructuredName mime type to get values
145 if (hasNonEmptyPrimaryValuesDelta(
146 rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind)) {
147 final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(
148 StructuredName.CONTENT_ITEM_TYPE);
149 mNames.addView(inflatePhoneticNameEditorView(
150 mNames, accountType, valuesDelta, rawContactDelta));
151 }
152 } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
153 if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
154 for (ValuesDelta valuesDelta :
155 getNonEmptyValuesDeltas(rawContactDelta, mimeType, dataKind)) {
156 mNames.addView(inflateNicknameEditorView(
157 mNames, accountType, valuesDelta, rawContactDelta));
158 }
159 }
160 } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
161 if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
162 mPhoneNumbers.addView(inflateKindSectionView(
163 mPhoneNumbers, dataKind, rawContactDelta));
164 }
165 } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
166 if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
167 mEmails.addView(inflateKindSectionView(
168 mEmails, dataKind, rawContactDelta));
169 }
170 } else if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
171 mOther.addView(inflateKindSectionView(
172 mOther, dataKind, rawContactDelta));
173 }
174 }
175 }
176 }
177
178 private static boolean hasNonEmptyValuesDelta(RawContactDelta rawContactDelta,
179 String mimeType, DataKind dataKind) {
180 return !getNonEmptyValuesDeltas(rawContactDelta, mimeType, dataKind).isEmpty();
181 }
182
183 private static List<ValuesDelta> getNonEmptyValuesDeltas(RawContactDelta rawContactDelta,
184 String mimeType, DataKind dataKind) {
185 final List<ValuesDelta> result = new ArrayList<>();
186 if (rawContactDelta == null) {
187 log(Log.VERBOSE, "Null RawContactDelta");
188 return result;
189 }
190 if (!rawContactDelta.hasMimeEntries(mimeType)) {
191 log(Log.VERBOSE, "No ValueDeltas");
192 return result;
193 }
194 for (ValuesDelta valuesDelta : rawContactDelta.getMimeEntries(mimeType)) {
195 if (valuesDelta == null) {
196 log(Log.VERBOSE, "Null valuesDelta");
197 }
198 for (EditField editField : dataKind.fieldList) {
199 final String column = editField.column;
200 final String value = valuesDelta == null ? null : valuesDelta.getAsString(column);
201 log(Log.VERBOSE, "Field " + column + " empty=" + TextUtils.isEmpty(value) +
202 " value=" + value);
203 if (!TextUtils.isEmpty(value)) {
204 result.add(valuesDelta);
205 }
206 }
207 }
208 return result;
209 }
210
211 private static boolean hasNonEmptyPrimaryValuesDelta(RawContactDelta rawContactDelta,
212 String mimeType, DataKind dataKind) {
213 final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(mimeType);
214 if (valuesDelta == null) {
215 return false;
216 }
217 for (EditField editField : dataKind.fieldList) {
218 final String column = editField.column;
219 final String value = valuesDelta == null ? null : valuesDelta.getAsString(column);
220 log(Log.VERBOSE, "Field (primary) " + column + " empty=" + TextUtils.isEmpty(value) +
221 " value=" + value);
222 if (!TextUtils.isEmpty(value)) {
223 return true;
224 }
225 }
226 return false;
227 }
228
229 private StructuredNameEditorView inflateStructuredNameEditorView(ViewGroup viewGroup,
230 AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
231 final StructuredNameEditorView result = (StructuredNameEditorView) mLayoutInflater.inflate(
232 R.layout.structured_name_editor_view, viewGroup, /* attachToRoot =*/ false);
233 result.setValues(
234 accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
235 valuesDelta,
236 rawContactDelta,
237 /* readOnly =*/ false,
238 mViewIdGenerator);
239 return result;
240 }
241
242 private PhoneticNameEditorView inflatePhoneticNameEditorView(ViewGroup viewGroup,
243 AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
244 final PhoneticNameEditorView result = (PhoneticNameEditorView) mLayoutInflater.inflate(
245 R.layout.phonetic_name_editor_view, viewGroup, /* attachToRoot =*/ false);
246 result.setValues(
247 accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME),
248 valuesDelta,
249 rawContactDelta,
250 /* readOnly =*/ false,
251 mViewIdGenerator);
252 return result;
253 }
254
255 private TextFieldsEditorView inflateNicknameEditorView(ViewGroup viewGroup,
256 AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
257 final TextFieldsEditorView result = (TextFieldsEditorView) mLayoutInflater.inflate(
258 R.layout.text_fields_editor_view, viewGroup, /* attachToRoot =*/ false);
259 result.setValues(
260 accountType.getKindForMimetype(Nickname.CONTENT_ITEM_TYPE),
261 valuesDelta,
262 rawContactDelta,
263 /* readOnly =*/ false,
264 mViewIdGenerator);
265 return result;
266 }
267
268 private KindSectionView inflateKindSectionView(ViewGroup viewGroup, DataKind dataKind,
269 RawContactDelta rawContactDelta) {
270 final KindSectionView result = (KindSectionView) mLayoutInflater.inflate(
271 R.layout.item_kind_section, viewGroup, /* attachToRoot =*/ false);
272 result.setState(
273 dataKind,
274 rawContactDelta,
275 /* readOnly =*/ false,
276 mViewIdGenerator);
277 return result;
278 }
279
280 private static void log(int level, String message) {
281 log(TAG, level, message);
282 }
283
284 private static void log(String tag, int level, String message) {
285 if (Log.isLoggable(tag, level)) {
286 switch (level) {
287 case Log.VERBOSE:
288 Log.v(tag, message);
289 break;
290 case Log.DEBUG:
291 Log.d(tag, message);
292 break;
293 case Log.INFO:
294 Log.i(tag, message);
295 break;
296 case Log.WARN:
297 Log.w(tag, message);
298 break;
299 case Log.ERROR:
300 Log.e(tag, message);
301 break;
302 default:
303 Log.v(tag, message);
304 break;
305 }
306 }
307 }
308}