| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.contacts.editor; |
| |
| import com.android.contacts.common.model.RawContactDelta; |
| import com.android.contacts.common.model.ValuesDelta; |
| import com.android.contacts.common.model.account.AccountWithDataSet; |
| import com.android.contacts.common.model.dataitem.DataKind; |
| import com.android.contacts.common.model.RawContactModifier; |
| |
| import android.util.Log; |
| import android.util.Pair; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Objects; |
| |
| /** |
| * Container for multiple {@link KindSectionData} objects. Provides convenience methods for |
| * interrogating the collection for a certain KindSectionData item (e.g. the first writable, or |
| * "primary", one. Also enforces that only items with the same DataKind/mime-type are added. |
| */ |
| public class KindSectionDataList extends ArrayList<KindSectionData> { |
| |
| private static final String TAG = CompactRawContactsEditorView.TAG; |
| |
| /** |
| * Returns the mime type for all DataKinds in this List. |
| */ |
| public String getMimeType() { |
| if (isEmpty()) return null; |
| return get(0).getDataKind().mimeType; |
| } |
| |
| /** |
| * Returns the DataKind for all entries in this List. |
| */ |
| public DataKind getDataKind() { |
| return isEmpty() ? null : get(0).getDataKind(); |
| } |
| |
| /** |
| * Returns the primary KindSectionData and ValuesDelta that should be written for this List. |
| */ |
| public Pair<KindSectionData,ValuesDelta> getEntryToWrite(long id, |
| AccountWithDataSet primaryAccount, boolean isUserProfile) { |
| final String mimeType = getMimeType(); |
| if (mimeType == null) return null; |
| |
| if (!isUserProfile) { |
| if (id > 0) { |
| // Look for a match for the ID that was passed in |
| for (KindSectionData kindSectionData : this) { |
| if (kindSectionData.getAccountType().areContactsWritable()) { |
| final ValuesDelta valuesDelta = kindSectionData.getValuesDeltaById(id); |
| if (valuesDelta != null) { |
| vlog(mimeType + ": matched kind section data to write by ID"); |
| return new Pair<>(kindSectionData, valuesDelta); |
| } |
| } |
| } |
| } |
| |
| // Look for a super primary entry |
| for (KindSectionData kindSectionData : this) { |
| if (kindSectionData.getAccountType().areContactsWritable()) { |
| final ValuesDelta valuesDelta = kindSectionData.getSuperPrimaryValuesDelta(); |
| if (valuesDelta != null) { |
| vlog(mimeType + ": matched kind section data to write by super primary"); |
| return new Pair<>(kindSectionData, valuesDelta); |
| } |
| } |
| } |
| |
| // Use the first writable contact that matches the primary account |
| if (primaryAccount != null) { |
| for (KindSectionData kindSectionData : this) { |
| if (kindSectionData.getAccountType().areContactsWritable()) { |
| if (matchesAccount(primaryAccount, kindSectionData.getRawContactDelta()) |
| && !kindSectionData.getValuesDeltas().isEmpty()) { |
| vlog(mimeType + ": matched kind section data to write by primary " + |
| "account"); |
| return new Pair<>(kindSectionData, |
| kindSectionData.getValuesDeltas().get(0)); |
| } |
| } |
| } |
| } |
| } |
| |
| // Just return the first writable entry. |
| for (KindSectionData kindSectionData : this) { |
| if (kindSectionData.getAccountType().areContactsWritable()) { |
| // Create an entry if necessary |
| RawContactModifier.ensureKindExists(kindSectionData.getRawContactDelta(), |
| kindSectionData.getAccountType(), mimeType); |
| |
| if (!kindSectionData.getValuesDeltas().isEmpty()) { |
| vlog(mimeType + ": falling back to first kind section data to write"); |
| return new Pair<>(kindSectionData, kindSectionData.getValuesDeltas().get(0)); |
| } |
| } |
| } |
| |
| wlog(mimeType+ ": no writable kind section data found"); |
| return null; |
| } |
| |
| /** Whether the given RawContactDelta belong to the given account. */ |
| private static boolean matchesAccount(AccountWithDataSet accountWithDataSet, |
| RawContactDelta rawContactDelta) { |
| return Objects.equals(accountWithDataSet.name, rawContactDelta.getAccountName()) |
| && Objects.equals(accountWithDataSet.type, rawContactDelta.getAccountType()) |
| && Objects.equals(accountWithDataSet.dataSet, rawContactDelta.getDataSet()); |
| } |
| |
| /** |
| * Returns the KindSectionData and ValuesDelta that should be displayed to the user. |
| */ |
| public Pair<KindSectionData,ValuesDelta> getEntryToDisplay(long id) { |
| final String mimeType = getMimeType(); |
| if (mimeType == null) return null; |
| |
| if (id > 0) { |
| // Look for a match for the ID that was passed in |
| for (KindSectionData kindSectionData : this) { |
| final ValuesDelta valuesDelta = kindSectionData.getValuesDeltaById(id); |
| if (valuesDelta != null) { |
| vlog(mimeType + ": matched kind section data to display by ID"); |
| return new Pair<>(kindSectionData, valuesDelta); |
| } |
| } |
| } |
| // Look for a super primary entry |
| for (KindSectionData kindSectionData : this) { |
| final ValuesDelta valuesDelta = kindSectionData.getSuperPrimaryValuesDelta(); |
| if (valuesDelta != null) { |
| vlog(mimeType + ": matched kind section data to display by super primary"); |
| return new Pair<>(kindSectionData, valuesDelta); |
| } |
| } |
| |
| // Fall back to the first non-empty value |
| for (KindSectionData kindSectionData : this) { |
| final ValuesDelta valuesDelta = kindSectionData.getFirstNonEmptyValuesDelta(); |
| if (valuesDelta != null) { |
| vlog(mimeType + ": using first non empty value to display"); |
| return new Pair<>(kindSectionData, valuesDelta); |
| } |
| } |
| |
| for (KindSectionData kindSectionData : this) { |
| final List<ValuesDelta> valuesDeltaList = kindSectionData.getValuesDeltas(); |
| if (!valuesDeltaList.isEmpty()) { |
| vlog(mimeType + ": falling back to first empty entry to display"); |
| final ValuesDelta valuesDelta = valuesDeltaList.get(0); |
| return new Pair<>(kindSectionData, valuesDelta); |
| } |
| } |
| |
| wlog(mimeType + ": no kind section data found to display"); |
| return null; |
| } |
| |
| @Override |
| public boolean add(KindSectionData kindSectionData) { |
| if (kindSectionData == null) throw new NullPointerException(); |
| |
| // Enforce that only entries of the same type are added to this list |
| final String listMimeType = getMimeType(); |
| if (listMimeType != null) { |
| final String newEntryMimeType = kindSectionData.getDataKind().mimeType; |
| if (!listMimeType.equals(newEntryMimeType)) { |
| throw new IllegalArgumentException( |
| "Can't add " + newEntryMimeType + " to list with type " + listMimeType); |
| } |
| } |
| return super.add(kindSectionData); |
| } |
| |
| private static void wlog(String message) { |
| if (Log.isLoggable(TAG, Log.WARN)) { |
| Log.w(TAG, message); |
| } |
| } |
| |
| private static void vlog(String message) { |
| if (Log.isLoggable(TAG, Log.VERBOSE)) { |
| Log.v(TAG, message); |
| } |
| } |
| } |