am 5d2be5b3: Merge "Move ContactLoader related code to ContactsCommon" into klp-dev
* commit '5d2be5b3d6f467d044f5e8cbe819b811da05561f':
Move ContactLoader related code to ContactsCommon
diff --git a/res/values/strings.xml b/res/values/strings.xml
index dd0406b..0d25bb25 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -451,12 +451,6 @@
<!-- The button to add an organization field to a contact in the Raw Contact Editor [CHAR LIMIT=15] -->
<string name="group_edit_field_hint_text">Group name</string>
- <!-- Attribution of a contact status update, when the time of update is unknown -->
- <string name="contact_status_update_attribution">via <xliff:g id="source" example="Google Talk">%1$s</xliff:g></string>
-
- <!-- Attribution of a contact status update, when the time of update is known -->
- <string name="contact_status_update_attribution_with_date"><xliff:g id="date" example="3 hours ago">%1$s</xliff:g> via <xliff:g id="source" example="Google Talk">%2$s</xliff:g></string>
-
<!-- String describing the Star/Favorite checkbox
Used by AccessibilityService to announce the purpose of the view.
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 9f916fb..7a8f9f3 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -49,9 +49,9 @@
import com.android.contacts.common.database.ContactUpdateUtils;
import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDeltaList;
-import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.util.CallerInfoCacheUtils;
import com.android.contacts.util.ContactPhotoUtils;
diff --git a/src/com/android/contacts/ContactsActivity.java b/src/com/android/contacts/ContactsActivity.java
index f3ac147..b94a237 100644
--- a/src/com/android/contacts/ContactsActivity.java
+++ b/src/com/android/contacts/ContactsActivity.java
@@ -26,7 +26,7 @@
import android.view.View;
import com.android.contacts.common.activity.TransactionSafeActivity;
-import com.android.contacts.test.InjectedServices;
+import com.android.contacts.common.test.InjectedServices;
/**
* A common superclass for Contacts activities that handles application-wide services.
diff --git a/src/com/android/contacts/ContactsApplication.java b/src/com/android/contacts/ContactsApplication.java
index 82b2a25..95fad48 100644
--- a/src/com/android/contacts/ContactsApplication.java
+++ b/src/com/android/contacts/ContactsApplication.java
@@ -32,7 +32,7 @@
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.list.ContactListFilterController;
import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.test.InjectedServices;
+import com.android.contacts.common.test.InjectedServices;
import com.android.contacts.common.util.Constants;
import com.google.common.annotations.VisibleForTesting;
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
deleted file mode 100644
index 6b7114c..0000000
--- a/src/com/android/contacts/ContactsUtils.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2009 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;
-
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.DisplayPhoto;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.common.test.NeededForTesting;
-import com.android.contacts.common.model.AccountTypeManager;
-
-import java.util.List;
-
-public class ContactsUtils {
- private static final String TAG = "ContactsUtils";
-
- private static int sThumbnailSize = -1;
-
- // TODO find a proper place for the canonical version of these
- public interface ProviderNames {
- String YAHOO = "Yahoo";
- String GTALK = "GTalk";
- String MSN = "MSN";
- String ICQ = "ICQ";
- String AIM = "AIM";
- String XMPP = "XMPP";
- String JABBER = "JABBER";
- String SKYPE = "SKYPE";
- String QQ = "QQ";
- }
-
- /**
- * This looks up the provider name defined in
- * ProviderNames from the predefined IM protocol id.
- * This is used for interacting with the IM application.
- *
- * @param protocol the protocol ID
- * @return the provider name the IM app uses for the given protocol, or null if no
- * provider is defined for the given protocol
- * @hide
- */
- public static String lookupProviderNameFromId(int protocol) {
- switch (protocol) {
- case Im.PROTOCOL_GOOGLE_TALK:
- return ProviderNames.GTALK;
- case Im.PROTOCOL_AIM:
- return ProviderNames.AIM;
- case Im.PROTOCOL_MSN:
- return ProviderNames.MSN;
- case Im.PROTOCOL_YAHOO:
- return ProviderNames.YAHOO;
- case Im.PROTOCOL_ICQ:
- return ProviderNames.ICQ;
- case Im.PROTOCOL_JABBER:
- return ProviderNames.JABBER;
- case Im.PROTOCOL_SKYPE:
- return ProviderNames.SKYPE;
- case Im.PROTOCOL_QQ:
- return ProviderNames.QQ;
- }
- return null;
- }
-
- /**
- * Test if the given {@link CharSequence} contains any graphic characters,
- * first checking {@link TextUtils#isEmpty(CharSequence)} to handle null.
- */
- public static boolean isGraphic(CharSequence str) {
- return !TextUtils.isEmpty(str) && TextUtils.isGraphic(str);
- }
-
- /**
- * Returns true if two objects are considered equal. Two null references are equal here.
- */
- @NeededForTesting
- public static boolean areObjectsEqual(Object a, Object b) {
- return a == b || (a != null && a.equals(b));
- }
-
- /**
- * Returns true if two {@link Intent}s are both null, or have the same action.
- */
- public static final boolean areIntentActionEqual(Intent a, Intent b) {
- if (a == b) {
- return true;
- }
- if (a == null || b == null) {
- return false;
- }
- return TextUtils.equals(a.getAction(), b.getAction());
- }
-
- public static boolean areContactWritableAccountsAvailable(Context context) {
- final List<AccountWithDataSet> accounts =
- AccountTypeManager.getInstance(context).getAccounts(true /* writeable */);
- return !accounts.isEmpty();
- }
-
- public static boolean areGroupWritableAccountsAvailable(Context context) {
- final List<AccountWithDataSet> accounts =
- AccountTypeManager.getInstance(context).getGroupWritableAccounts();
- return !accounts.isEmpty();
- }
-
- /**
- * Returns the size (width and height) of thumbnail pictures as configured in the provider. This
- * can safely be called from the UI thread, as the provider can serve this without performing
- * a database access
- */
- public static int getThumbnailSize(Context context) {
- if (sThumbnailSize == -1) {
- final Cursor c = context.getContentResolver().query(
- DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
- new String[] { DisplayPhoto.THUMBNAIL_MAX_DIM }, null, null, null);
- try {
- c.moveToFirst();
- sThumbnailSize = c.getInt(0);
- } finally {
- c.close();
- }
- }
- return sThumbnailSize;
- }
-
-}
diff --git a/src/com/android/contacts/GroupMetaData.java b/src/com/android/contacts/GroupMetaData.java
deleted file mode 100644
index 462ac4a..0000000
--- a/src/com/android/contacts/GroupMetaData.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 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;
-
-/**
- * Meta-data for a contact group. We load all groups associated with the contact's
- * constituent accounts.
- */
-public final class GroupMetaData {
- private String mAccountName;
- private String mAccountType;
- private String mDataSet;
- private long mGroupId;
- private String mTitle;
- private boolean mDefaultGroup;
- private boolean mFavorites;
-
- public GroupMetaData(String accountName, String accountType, String dataSet, long groupId,
- String title, boolean defaultGroup, boolean favorites) {
- this.mAccountName = accountName;
- this.mAccountType = accountType;
- this.mDataSet = dataSet;
- this.mGroupId = groupId;
- this.mTitle = title;
- this.mDefaultGroup = defaultGroup;
- this.mFavorites = favorites;
- }
-
- public String getAccountName() {
- return mAccountName;
- }
-
- public String getAccountType() {
- return mAccountType;
- }
-
- public String getDataSet() {
- return mDataSet;
- }
-
- public long getGroupId() {
- return mGroupId;
- }
-
- public String getTitle() {
- return mTitle;
- }
-
- public boolean isDefaultGroup() {
- return mDefaultGroup;
- }
-
- public boolean isFavorites() {
- return mFavorites;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/TypePrecedence.java b/src/com/android/contacts/TypePrecedence.java
index 53b8343..0a193b5 100644
--- a/src/com/android/contacts/TypePrecedence.java
+++ b/src/com/android/contacts/TypePrecedence.java
@@ -23,7 +23,7 @@
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactModifier;
/**
* This class contains utility functions for determining the precedence of
diff --git a/src/com/android/contacts/ViewNotificationService.java b/src/com/android/contacts/ViewNotificationService.java
index 3bc5ed2..0f2922a 100644
--- a/src/com/android/contacts/ViewNotificationService.java
+++ b/src/com/android/contacts/ViewNotificationService.java
@@ -23,8 +23,8 @@
import android.os.IBinder;
import android.util.Log;
-import com.android.contacts.model.Contact;
-import com.android.contacts.model.ContactLoader;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.ContactLoader;
/**
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 78b482e..2d9e9f5 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -33,12 +33,12 @@
import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsActivity;
-import com.android.contacts.ContactsUtils;
-import com.android.contacts.model.Contact;
-import com.android.contacts.model.ContactLoader;
-import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDeltaList;
-import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.ContactLoader;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.util.ContactPhotoUtils;
diff --git a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
index fd12d7f..d60cc73 100644
--- a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
+++ b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
@@ -63,11 +63,11 @@
import com.android.contacts.editor.EditorUiUtils;
import com.android.contacts.editor.ViewIdGenerator;
import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.model.RawContact;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.model.RawContactDeltaList;
-import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index 0f793e2..03821a7 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -46,7 +46,7 @@
import com.android.contacts.detail.ContactLoaderFragment;
import com.android.contacts.detail.ContactLoaderFragment.ContactLoaderFragmentListener;
import com.android.contacts.interactions.ContactDeletionInteraction;
-import com.android.contacts.model.Contact;
+import com.android.contacts.common.model.Contact;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.util.PhoneCapabilityTester;
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 2d69917..bfcd79e 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -51,7 +51,6 @@
import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsActivity;
-import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.activities.ActionBarAdapter.TabState;
import com.android.contacts.detail.ContactDetailFragment;
@@ -59,6 +58,7 @@
import com.android.contacts.detail.ContactDetailUpdatesFragment;
import com.android.contacts.detail.ContactLoaderFragment;
import com.android.contacts.detail.ContactLoaderFragment.ContactLoaderFragmentListener;
+import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.dialog.ClearFrequentsDialog;
import com.android.contacts.group.GroupBrowseListFragment;
import com.android.contacts.group.GroupBrowseListFragment.OnGroupBrowserActionListener;
@@ -81,7 +81,7 @@
import com.android.contacts.list.OnContactsUnavailableActionListener;
import com.android.contacts.list.ProviderStatusWatcher;
import com.android.contacts.list.ProviderStatusWatcher.ProviderStatusListener;
-import com.android.contacts.model.Contact;
+import com.android.contacts.common.model.Contact;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.preference.ContactsPreferenceActivity;
import com.android.contacts.preference.DisplayOptionsPreferenceFragment;
diff --git a/src/com/android/contacts/activities/PhotoSelectionActivity.java b/src/com/android/contacts/activities/PhotoSelectionActivity.java
index 6d74863..20892d6 100644
--- a/src/com/android/contacts/activities/PhotoSelectionActivity.java
+++ b/src/com/android/contacts/activities/PhotoSelectionActivity.java
@@ -39,7 +39,7 @@
import com.android.contacts.R;
import com.android.contacts.detail.PhotoSelectionHandler;
import com.android.contacts.editor.PhotoActionPopup;
-import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactDeltaList;
import com.android.contacts.util.ContactPhotoUtils;
import com.android.contacts.util.SchedulingUtils;
diff --git a/src/com/android/contacts/datepicker/DatePickerDialog.java b/src/com/android/contacts/datepicker/DatePickerDialog.java
index 7681898..5ed143b 100644
--- a/src/com/android/contacts/datepicker/DatePickerDialog.java
+++ b/src/com/android/contacts/datepicker/DatePickerDialog.java
@@ -31,8 +31,8 @@
import android.widget.TextView;
import com.android.contacts.R;
+import com.android.contacts.common.util.DateUtils;
import com.android.contacts.datepicker.DatePicker.OnDateChangedListener;
-import com.android.contacts.util.DateUtils;
import java.text.DateFormat;
import java.util.Calendar;
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index c856f97..e1aa217 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -42,15 +42,15 @@
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.R;
-import com.android.contacts.model.Contact;
-import com.android.contacts.model.RawContact;
-import com.android.contacts.model.dataitem.DataItem;
-import com.android.contacts.model.dataitem.OrganizationDataItem;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.dataitem.DataItem;
+import com.android.contacts.common.model.dataitem.OrganizationDataItem;
import com.android.contacts.common.preference.ContactsPreferences;
+import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.ContactBadgeUtil;
import com.android.contacts.util.HtmlUtils;
import com.android.contacts.util.MoreMath;
-import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemPhotoEntry;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Iterables;
@@ -233,17 +233,6 @@
CharSequence snippet = null;
String photoUri = null;
- if (!contactData.getStreamItems().isEmpty()) {
- StreamItemEntry firstEntry = contactData.getStreamItems().get(0);
- snippet = HtmlUtils.fromHtml(context, firstEntry.getText());
- if (!firstEntry.getPhotos().isEmpty()) {
- StreamItemPhotoEntry firstPhoto = firstEntry.getPhotos().get(0);
- photoUri = firstPhoto.getPhotoUri();
-
- // If displaying an image, hide the snippet text.
- snippet = null;
- }
- }
setDataOrHideIfNone(snippet, statusView);
if (photoUri != null) {
ContactPhotoManager.getInstance(context).loadPhoto(
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 34583dc..abaa8eb 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -70,14 +70,14 @@
import android.widget.TextView;
import com.android.contacts.ContactSaveService;
-import com.android.contacts.ContactsUtils;
-import com.android.contacts.GroupMetaData;
import com.android.contacts.R;
import com.android.contacts.TypePrecedence;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
import com.android.contacts.common.CallUtil;
import com.android.contacts.common.ClipboardUtils;
import com.android.contacts.common.Collapser;
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.GroupMetaData;
import com.android.contacts.common.Collapser.Collapsible;
import com.android.contacts.common.ContactPresenceIconUtil;
import com.android.contacts.common.GeoUtil;
@@ -91,27 +91,27 @@
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.common.util.ContactDisplayUtils;
-import com.android.contacts.model.Contact;
-import com.android.contacts.model.RawContact;
-import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDeltaList;
-import com.android.contacts.model.RawContactModifier;
-import com.android.contacts.model.dataitem.DataItem;
-import com.android.contacts.model.dataitem.EmailDataItem;
-import com.android.contacts.model.dataitem.EventDataItem;
-import com.android.contacts.model.dataitem.GroupMembershipDataItem;
-import com.android.contacts.model.dataitem.ImDataItem;
-import com.android.contacts.model.dataitem.NicknameDataItem;
-import com.android.contacts.model.dataitem.NoteDataItem;
-import com.android.contacts.model.dataitem.OrganizationDataItem;
-import com.android.contacts.model.dataitem.PhoneDataItem;
-import com.android.contacts.model.dataitem.RelationDataItem;
-import com.android.contacts.model.dataitem.SipAddressDataItem;
-import com.android.contacts.model.dataitem.StructuredNameDataItem;
-import com.android.contacts.model.dataitem.StructuredPostalDataItem;
-import com.android.contacts.model.dataitem.WebsiteDataItem;
-import com.android.contacts.util.DataStatus;
-import com.android.contacts.util.DateUtils;
+import com.android.contacts.common.util.DataStatus;
+import com.android.contacts.common.util.DateUtils;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.dataitem.DataItem;
+import com.android.contacts.common.model.dataitem.EmailDataItem;
+import com.android.contacts.common.model.dataitem.EventDataItem;
+import com.android.contacts.common.model.dataitem.GroupMembershipDataItem;
+import com.android.contacts.common.model.dataitem.ImDataItem;
+import com.android.contacts.common.model.dataitem.NicknameDataItem;
+import com.android.contacts.common.model.dataitem.NoteDataItem;
+import com.android.contacts.common.model.dataitem.OrganizationDataItem;
+import com.android.contacts.common.model.dataitem.PhoneDataItem;
+import com.android.contacts.common.model.dataitem.RelationDataItem;
+import com.android.contacts.common.model.dataitem.SipAddressDataItem;
+import com.android.contacts.common.model.dataitem.StructuredNameDataItem;
+import com.android.contacts.common.model.dataitem.StructuredPostalDataItem;
+import com.android.contacts.common.model.dataitem.WebsiteDataItem;
import com.android.contacts.util.PhoneCapabilityTester;
import com.android.contacts.util.StructuredPostalUtils;
import com.android.contacts.util.UiClosables;
@@ -412,9 +412,6 @@
return;
}
- // Figure out if the contact has social updates or not
- mContactHasSocialUpdates = !mContactData.getStreamItems().isEmpty();
-
// Setup the photo if applicable
if (mStaticPhotoContainer != null) {
// The presence of a static photo container is not sufficient to determine whether or
@@ -1502,9 +1499,7 @@
}
private View getHeaderEntryView(View convertView, ViewGroup parent) {
- final int desiredLayoutResourceId = mContactHasSocialUpdates ?
- R.layout.detail_header_contact_with_updates :
- R.layout.detail_header_contact_without_updates;
+ final int desiredLayoutResourceId = R.layout.detail_header_contact_without_updates;
View result = null;
HeaderViewCache viewCache = null;
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 3c359ba..1ee31a5 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -37,7 +37,7 @@
import com.android.contacts.NfcHandler;
import com.android.contacts.R;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
-import com.android.contacts.model.Contact;
+import com.android.contacts.common.model.Contact;
import com.android.contacts.util.PhoneCapabilityTester;
import com.android.contacts.common.util.UriUtils;
import com.android.contacts.widget.FrameLayoutWithOverlay;
@@ -285,7 +285,6 @@
!UriUtils.areEqual(mContactData.getLookupUri(), data.getLookupUri());
}
mContactData = data;
- mContactHasUpdates = !data.getStreamItems().isEmpty();
if (PhoneCapabilityTester.isUsingTwoPanes(mActivity)) {
// Tablet: If we already showed data before, we want to cross-fade from screen to screen
@@ -302,12 +301,7 @@
}
}
- if (mContactHasUpdates) {
- showContactWithUpdates(
- contactWasLoaded && contactHadUpdates == false);
- } else {
- showContactWithoutUpdates();
- }
+ showContactWithoutUpdates();
}
public void showEmptyState() {
diff --git a/src/com/android/contacts/detail/ContactDetailPhotoSetter.java b/src/com/android/contacts/detail/ContactDetailPhotoSetter.java
index 2c4c2c9..112621a 100644
--- a/src/com/android/contacts/detail/ContactDetailPhotoSetter.java
+++ b/src/com/android/contacts/detail/ContactDetailPhotoSetter.java
@@ -27,8 +27,8 @@
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.activities.PhotoSelectionActivity;
-import com.android.contacts.model.Contact;
-import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.RawContactDeltaList;
import com.android.contacts.util.ImageViewDrawableSetter;
/**
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index 540f001..25bcac6 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -30,7 +30,7 @@
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.model.Contact;
+import com.android.contacts.common.model.Contact;
import com.android.contacts.util.MoreMath;
import com.android.contacts.util.SchedulingUtils;
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index b578d28..71186fe 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -31,10 +31,10 @@
import com.android.contacts.R;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
import com.android.contacts.detail.ContactDetailDisplayUtils.StreamPhotoTag;
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.model.Contact;
-import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.util.StreamItemEntry;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.account.AccountType;
public class ContactDetailUpdatesFragment extends ListFragment implements FragmentKeyListener {
@@ -111,14 +111,6 @@
mStreamItemPhotoItemClickListener);
setListAdapter(mStreamItemAdapter);
getListView().setOnScrollListener(mVerticalScrollListener);
-
- // It is possible that the contact data was set to the fragment when it was first attached
- // to the activity, but before this method was called because the fragment was not
- // visible on screen yet (i.e. using a {@link ViewPager}), so display the data if we already
- // have it.
- if (mContactData != null) {
- mStreamItemAdapter.setStreamItems(mContactData.getStreamItems());
- }
}
public void setData(Uri lookupUri, Contact result) {
@@ -127,13 +119,6 @@
}
mLookupUri = lookupUri;
mContactData = result;
-
- // If the adapter has been created already, then try to set stream items. Otherwise,
- // wait for the adapter to get initialized, after which we will try to set the stream items
- // again.
- if (mStreamItemAdapter != null) {
- mStreamItemAdapter.setStreamItems(mContactData.getStreamItems());
- }
}
/**
diff --git a/src/com/android/contacts/detail/ContactLoaderFragment.java b/src/com/android/contacts/detail/ContactLoaderFragment.java
index 5f5a137..0b420f7 100644
--- a/src/com/android/contacts/detail/ContactLoaderFragment.java
+++ b/src/com/android/contacts/detail/ContactLoaderFragment.java
@@ -44,8 +44,8 @@
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
import com.android.contacts.common.list.ShortcutIntentBuilder;
import com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener;
-import com.android.contacts.model.Contact;
-import com.android.contacts.model.ContactLoader;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.ContactLoader;
import com.android.contacts.util.PhoneCapabilityTester;
import com.google.common.base.Objects;
diff --git a/src/com/android/contacts/detail/PhotoSelectionHandler.java b/src/com/android/contacts/detail/PhotoSelectionHandler.java
index 6e2d4fa..52a292b 100644
--- a/src/com/android/contacts/detail/PhotoSelectionHandler.java
+++ b/src/com/android/contacts/detail/PhotoSelectionHandler.java
@@ -37,11 +37,11 @@
import com.android.contacts.R;
import com.android.contacts.editor.PhotoActionPopup;
import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.model.RawContactModifier;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactDeltaList;
import com.android.contacts.util.ContactPhotoUtils;
import com.android.contacts.util.UiClosables;
diff --git a/src/com/android/contacts/detail/StreamItemAdapter.java b/src/com/android/contacts/detail/StreamItemAdapter.java
index 5c827dc..6e1adc5 100644
--- a/src/com/android/contacts/detail/StreamItemAdapter.java
+++ b/src/com/android/contacts/detail/StreamItemAdapter.java
@@ -26,6 +26,7 @@
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.util.StreamItemEntry;
+
import com.google.common.collect.Lists;
import java.util.List;
diff --git a/src/com/android/contacts/editor/BaseRawContactEditorView.java b/src/com/android/contacts/editor/BaseRawContactEditorView.java
index c39d472..7e74cfb 100644
--- a/src/com/android/contacts/editor/BaseRawContactEditorView.java
+++ b/src/com/android/contacts/editor/BaseRawContactEditorView.java
@@ -28,9 +28,9 @@
import android.widget.LinearLayout;
import com.android.contacts.R;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountType.EditType;
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 767cee2..9243625 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -78,12 +78,12 @@
import com.android.contacts.detail.PhotoSelectionHandler;
import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
import com.android.contacts.editor.Editor.EditorListener;
-import com.android.contacts.model.Contact;
-import com.android.contacts.model.ContactLoader;
-import com.android.contacts.model.RawContact;
-import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDeltaList;
-import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.ContactLoader;
+import com.android.contacts.common.model.RawContact;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.RawContactModifier;
import com.android.contacts.util.ContactPhotoUtils;
import com.android.contacts.util.HelpUtils;
import com.android.contacts.util.UiClosables;
diff --git a/src/com/android/contacts/editor/Editor.java b/src/com/android/contacts/editor/Editor.java
index 12ea201..7990309 100644
--- a/src/com/android/contacts/editor/Editor.java
+++ b/src/com/android/contacts/editor/Editor.java
@@ -18,7 +18,7 @@
import android.provider.ContactsContract.Data;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/editor/EventFieldEditorView.java b/src/com/android/contacts/editor/EventFieldEditorView.java
index 3589c89..4d9411f 100644
--- a/src/com/android/contacts/editor/EventFieldEditorView.java
+++ b/src/com/android/contacts/editor/EventFieldEditorView.java
@@ -29,12 +29,13 @@
import com.android.contacts.datepicker.DatePicker;
import com.android.contacts.datepicker.DatePickerDialog;
import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType.EditField;
import com.android.contacts.common.model.account.AccountType.EventEditType;
import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.util.DateUtils;
+import com.android.contacts.common.util.CommonDateUtils;
+import com.android.contacts.common.util.DateUtils;
import java.text.ParsePosition;
import java.util.Calendar;
@@ -45,10 +46,6 @@
* Editor that allows editing Events using a {@link DatePickerDialog}
*/
public class EventFieldEditorView extends LabeledEditorView {
- /**
- * Exchange requires 8:00 for birthdays
- */
- private final static int DEFAULT_HOUR = 8;
/**
* Default string to show when there is no date selected yet.
@@ -181,7 +178,7 @@
// This value is missing the year. Add it now
calendar.setTime(date2);
calendar.set(defaultYear, calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH), DEFAULT_HOUR, 0, 0);
+ calendar.get(Calendar.DAY_OF_MONTH), CommonDateUtils.DEFAULT_HOUR, 0, 0);
onFieldChanged(column, kind.dateFormatWithYear.format(calendar.getTime()));
rebuildDateView();
@@ -237,7 +234,7 @@
// For formats other than Exchange, the time of the day is ignored
outCalendar.clear();
outCalendar.set(year == DatePickerDialog.NO_YEAR ? 2000 : year, monthOfYear,
- dayOfMonth, DEFAULT_HOUR, 0, 0);
+ dayOfMonth, CommonDateUtils.DEFAULT_HOUR, 0, 0);
final String resultString;
if (year == 0) {
@@ -254,13 +251,6 @@
return resultDialog;
}
- /**
- * @return Default hour which should be used for birthday field.
- */
- public static int getDefaultHourForBirthday() {
- return DEFAULT_HOUR;
- }
-
@Override
public void clearAllFields() {
// Update UI
diff --git a/src/com/android/contacts/editor/GroupMembershipView.java b/src/com/android/contacts/editor/GroupMembershipView.java
index d150be8..db389fb 100644
--- a/src/com/android/contacts/editor/GroupMembershipView.java
+++ b/src/com/android/contacts/editor/GroupMembershipView.java
@@ -40,9 +40,9 @@
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.interactions.GroupCreationDialogFragment;
import com.android.contacts.interactions.GroupCreationDialogFragment.OnGroupCreatedListener;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactModifier;
import com.android.contacts.util.UiClosables;
import com.google.common.base.Objects;
diff --git a/src/com/android/contacts/editor/KindSectionView.java b/src/com/android/contacts/editor/KindSectionView.java
index fb9c253..261286e 100644
--- a/src/com/android/contacts/editor/KindSectionView.java
+++ b/src/com/android/contacts/editor/KindSectionView.java
@@ -28,8 +28,8 @@
import com.android.contacts.R;
import com.android.contacts.editor.Editor.EditorListener;
-import com.android.contacts.model.RawContactModifier;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/editor/LabeledEditorView.java b/src/com/android/contacts/editor/LabeledEditorView.java
index 3c0774d..0a33b6d 100644
--- a/src/com/android/contacts/editor/LabeledEditorView.java
+++ b/src/com/android/contacts/editor/LabeledEditorView.java
@@ -44,11 +44,11 @@
import android.widget.Spinner;
import android.widget.TextView;
-import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType.EditType;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.util.DialogManager;
diff --git a/src/com/android/contacts/editor/PhoneticNameEditorView.java b/src/com/android/contacts/editor/PhoneticNameEditorView.java
index 2836c721..69e0719 100644
--- a/src/com/android/contacts/editor/PhoneticNameEditorView.java
+++ b/src/com/android/contacts/editor/PhoneticNameEditorView.java
@@ -17,14 +17,14 @@
package com.android.contacts.editor;
import android.content.Context;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.text.TextUtils;
import android.util.AttributeSet;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.model.dataitem.StructuredNameDataItem;
+import com.android.contacts.common.model.dataitem.StructuredNameDataItem;
+import com.android.contacts.common.util.NameConverter;
/**
* A dedicated editor for phonetic name. It is similar to {@link StructuredNameEditorView}.
@@ -61,7 +61,7 @@
}
private void parsePhoneticName(String value) {
- StructuredNameDataItem dataItem = PhoneticNameEditorView.parsePhoneticName(value, null);
+ StructuredNameDataItem dataItem = NameConverter.parsePhoneticName(value, null);
mValues.setPhoneticFamilyName(dataItem.getPhoneticFamilyName());
mValues.setPhoneticMiddleName(dataItem.getPhoneticMiddleName());
mValues.setPhoneticGivenName(dataItem.getPhoneticGivenName());
@@ -71,7 +71,7 @@
String family = mValues.getPhoneticFamilyName();
String middle = mValues.getPhoneticMiddleName();
String given = mValues.getPhoneticGivenName();
- mPhoneticName = PhoneticNameEditorView.buildPhoneticName(family, middle, given);
+ mPhoneticName = NameConverter.buildPhoneticName(family, middle, given);
}
@Override
@@ -85,74 +85,6 @@
}
}
- /**
- * Parses phonetic name and returns parsed data (family, middle, given) as ContentValues.
- * Parsed data should be {@link StructuredName#PHONETIC_FAMILY_NAME},
- * {@link StructuredName#PHONETIC_MIDDLE_NAME}, and
- * {@link StructuredName#PHONETIC_GIVEN_NAME}.
- * If this method cannot parse given phoneticName, null values will be stored.
- *
- * @param phoneticName Phonetic name to be parsed
- * @param values ContentValues to be used for storing data. If null, new instance will be
- * created.
- * @return ContentValues with parsed data. Those data can be null.
- */
- public static StructuredNameDataItem parsePhoneticName(String phoneticName,
- StructuredNameDataItem item) {
- String family = null;
- String middle = null;
- String given = null;
-
- if (!TextUtils.isEmpty(phoneticName)) {
- String[] strings = phoneticName.split(" ", 3);
- switch (strings.length) {
- case 1:
- family = strings[0];
- break;
- case 2:
- family = strings[0];
- given = strings[1];
- break;
- case 3:
- family = strings[0];
- middle = strings[1];
- given = strings[2];
- break;
- }
- }
-
- if (item == null) {
- item = new StructuredNameDataItem();
- }
- item.setPhoneticFamilyName(family);
- item.setPhoneticMiddleName(middle);
- item.setPhoneticGivenName(given);
- return item;
- }
-
- /**
- * Constructs and returns a phonetic full name from given parts.
- */
- public static String buildPhoneticName(String family, String middle, String given) {
- if (!TextUtils.isEmpty(family) || !TextUtils.isEmpty(middle)
- || !TextUtils.isEmpty(given)) {
- StringBuilder sb = new StringBuilder();
- if (!TextUtils.isEmpty(family)) {
- sb.append(family.trim()).append(' ');
- }
- if (!TextUtils.isEmpty(middle)) {
- sb.append(middle.trim()).append(' ');
- }
- if (!TextUtils.isEmpty(given)) {
- sb.append(given.trim()).append(' ');
- }
- sb.setLength(sb.length() - 1); // Yank the last space
- return sb.toString();
- } else {
- return null;
- }
- }
-
public static boolean isUnstructuredPhoneticNameColumn(String column) {
return DataKind.PSEUDO_COLUMN_PHONETIC_NAME.equals(column);
}
diff --git a/src/com/android/contacts/editor/PhotoEditorView.java b/src/com/android/contacts/editor/PhotoEditorView.java
index 652c8e6..bee61f4 100644
--- a/src/com/android/contacts/editor/PhotoEditorView.java
+++ b/src/com/android/contacts/editor/PhotoEditorView.java
@@ -25,9 +25,9 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
-import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.util.ContactPhotoUtils;
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index b52b0b2..c9d3c33 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -43,9 +43,9 @@
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountType.EditType;
import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactModifier;
import com.google.common.base.Objects;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java b/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
index 70a2b4e..d1fa282 100644
--- a/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
+++ b/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
@@ -39,8 +39,8 @@
import com.android.contacts.R;
import com.android.contacts.common.GeoUtil;
-import com.android.contacts.model.RawContactModifier;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
diff --git a/src/com/android/contacts/editor/StructuredNameEditorView.java b/src/com/android/contacts/editor/StructuredNameEditorView.java
index 4d72598..bf548f6 100644
--- a/src/com/android/contacts/editor/StructuredNameEditorView.java
+++ b/src/com/android/contacts/editor/StructuredNameEditorView.java
@@ -25,12 +25,12 @@
import android.text.TextUtils;
import android.util.AttributeSet;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.model.dataitem.DataItem;
+import com.android.contacts.common.model.dataitem.DataItem;
import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.model.dataitem.StructuredNameDataItem;
-import com.android.contacts.util.NameConverter;
+import com.android.contacts.common.util.NameConverter;
+import com.android.contacts.common.model.dataitem.StructuredNameDataItem;
import java.util.HashMap;
import java.util.Map;
diff --git a/src/com/android/contacts/editor/TextFieldsEditorView.java b/src/com/android/contacts/editor/TextFieldsEditorView.java
index a20ba77..85cbac8 100644
--- a/src/com/android/contacts/editor/TextFieldsEditorView.java
+++ b/src/com/android/contacts/editor/TextFieldsEditorView.java
@@ -35,9 +35,9 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
-import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType.EditField;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/editor/ViewIdGenerator.java b/src/com/android/contacts/editor/ViewIdGenerator.java
index 8494e1a..e7e7948 100644
--- a/src/com/android/contacts/editor/ViewIdGenerator.java
+++ b/src/com/android/contacts/editor/ViewIdGenerator.java
@@ -20,7 +20,7 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/group/GroupBrowseListFragment.java b/src/com/android/contacts/group/GroupBrowseListFragment.java
index f842db3..81cc28c 100644
--- a/src/com/android/contacts/group/GroupBrowseListFragment.java
+++ b/src/com/android/contacts/group/GroupBrowseListFragment.java
@@ -42,10 +42,10 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.contacts.ContactsUtils;
import com.android.contacts.GroupListLoader;
import com.android.contacts.R;
import com.android.contacts.group.GroupBrowseListAdapter.GroupListItemViewCache;
+import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.list.AutoScrollListView;
/**
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index 78bc3eb..14e8949 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -40,7 +40,7 @@
import com.android.contacts.common.list.ContactListAdapter;
import com.android.contacts.common.list.ContactListFilter;
import com.android.contacts.common.list.DirectoryPartition;
-import com.android.contacts.util.ContactLoaderUtils;
+import com.android.contacts.common.util.ContactLoaderUtils;
import java.util.List;
diff --git a/src/com/android/contacts/model/Contact.java b/src/com/android/contacts/model/Contact.java
deleted file mode 100644
index 9f7f217..0000000
--- a/src/com/android/contacts/model/Contact.java
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- * Copyright (C) 2012 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.model;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.net.Uri;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.Directory;
-import android.provider.ContactsContract.DisplayNameSources;
-
-import com.android.contacts.GroupMetaData;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.util.DataStatus;
-import com.android.contacts.util.StreamItemEntry;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-/**
- * A Contact represents a single person or logical entity as perceived by the user. The information
- * about a contact can come from multiple data sources, which are each represented by a RawContact
- * object. Thus, a Contact is associated with a collection of RawContact objects.
- *
- * The aggregation of raw contacts into a single contact is performed automatically, and it is
- * also possible for users to manually split and join raw contacts into various contacts.
- *
- * Only the {@link ContactLoader} class can create a Contact object with various flags to allow
- * partial loading of contact data. Thus, an instance of this class should be treated as
- * a read-only object.
- */
-public class Contact {
- private enum Status {
- /** Contact is successfully loaded */
- LOADED,
- /** There was an error loading the contact */
- ERROR,
- /** Contact is not found */
- NOT_FOUND,
- }
-
- private final Uri mRequestedUri;
- private final Uri mLookupUri;
- private final Uri mUri;
- private final long mDirectoryId;
- private final String mLookupKey;
- private final long mId;
- private final long mNameRawContactId;
- private final int mDisplayNameSource;
- private final long mPhotoId;
- private final String mPhotoUri;
- private final String mDisplayName;
- private final String mAltDisplayName;
- private final String mPhoneticName;
- private final boolean mStarred;
- private final Integer mPresence;
- private ImmutableList<RawContact> mRawContacts;
- private ImmutableMap<Long,DataStatus> mStatuses;
- private ImmutableList<AccountType> mInvitableAccountTypes;
-
- private String mDirectoryDisplayName;
- private String mDirectoryType;
- private String mDirectoryAccountType;
- private String mDirectoryAccountName;
- private int mDirectoryExportSupport;
-
- private ImmutableList<GroupMetaData> mGroups;
-
- private byte[] mPhotoBinaryData;
- private final boolean mSendToVoicemail;
- private final String mCustomRingtone;
- private final boolean mIsUserProfile;
-
- private final Contact.Status mStatus;
- private final Exception mException;
-
- /**
- * Constructor for special results, namely "no contact found" and "error".
- */
- private Contact(Uri requestedUri, Contact.Status status, Exception exception) {
- if (status == Status.ERROR && exception == null) {
- throw new IllegalArgumentException("ERROR result must have exception");
- }
- mStatus = status;
- mException = exception;
- mRequestedUri = requestedUri;
- mLookupUri = null;
- mUri = null;
- mDirectoryId = -1;
- mLookupKey = null;
- mId = -1;
- mRawContacts = null;
- mStatuses = null;
- mNameRawContactId = -1;
- mDisplayNameSource = DisplayNameSources.UNDEFINED;
- mPhotoId = -1;
- mPhotoUri = null;
- mDisplayName = null;
- mAltDisplayName = null;
- mPhoneticName = null;
- mStarred = false;
- mPresence = null;
- mInvitableAccountTypes = null;
- mSendToVoicemail = false;
- mCustomRingtone = null;
- mIsUserProfile = false;
- }
-
- public static Contact forError(Uri requestedUri, Exception exception) {
- return new Contact(requestedUri, Status.ERROR, exception);
- }
-
- public static Contact forNotFound(Uri requestedUri) {
- return new Contact(requestedUri, Status.NOT_FOUND, null);
- }
-
- /**
- * Constructor to call when contact was found
- */
- public Contact(Uri requestedUri, Uri uri, Uri lookupUri, long directoryId, String lookupKey,
- long id, long nameRawContactId, int displayNameSource, long photoId,
- String photoUri, String displayName, String altDisplayName, String phoneticName,
- boolean starred, Integer presence, boolean sendToVoicemail, String customRingtone,
- boolean isUserProfile) {
- mStatus = Status.LOADED;
- mException = null;
- mRequestedUri = requestedUri;
- mLookupUri = lookupUri;
- mUri = uri;
- mDirectoryId = directoryId;
- mLookupKey = lookupKey;
- mId = id;
- mRawContacts = null;
- mStatuses = null;
- mNameRawContactId = nameRawContactId;
- mDisplayNameSource = displayNameSource;
- mPhotoId = photoId;
- mPhotoUri = photoUri;
- mDisplayName = displayName;
- mAltDisplayName = altDisplayName;
- mPhoneticName = phoneticName;
- mStarred = starred;
- mPresence = presence;
- mInvitableAccountTypes = null;
- mSendToVoicemail = sendToVoicemail;
- mCustomRingtone = customRingtone;
- mIsUserProfile = isUserProfile;
- }
-
- public Contact(Uri requestedUri, Contact from) {
- mRequestedUri = requestedUri;
-
- mStatus = from.mStatus;
- mException = from.mException;
- mLookupUri = from.mLookupUri;
- mUri = from.mUri;
- mDirectoryId = from.mDirectoryId;
- mLookupKey = from.mLookupKey;
- mId = from.mId;
- mNameRawContactId = from.mNameRawContactId;
- mDisplayNameSource = from.mDisplayNameSource;
- mPhotoId = from.mPhotoId;
- mPhotoUri = from.mPhotoUri;
- mDisplayName = from.mDisplayName;
- mAltDisplayName = from.mAltDisplayName;
- mPhoneticName = from.mPhoneticName;
- mStarred = from.mStarred;
- mPresence = from.mPresence;
- mRawContacts = from.mRawContacts;
- mStatuses = from.mStatuses;
- mInvitableAccountTypes = from.mInvitableAccountTypes;
-
- mDirectoryDisplayName = from.mDirectoryDisplayName;
- mDirectoryType = from.mDirectoryType;
- mDirectoryAccountType = from.mDirectoryAccountType;
- mDirectoryAccountName = from.mDirectoryAccountName;
- mDirectoryExportSupport = from.mDirectoryExportSupport;
-
- mGroups = from.mGroups;
-
- mPhotoBinaryData = from.mPhotoBinaryData;
- mSendToVoicemail = from.mSendToVoicemail;
- mCustomRingtone = from.mCustomRingtone;
- mIsUserProfile = from.mIsUserProfile;
- }
-
- /**
- * @param exportSupport See {@link Directory#EXPORT_SUPPORT}.
- */
- public void setDirectoryMetaData(String displayName, String directoryType,
- String accountType, String accountName, int exportSupport) {
- mDirectoryDisplayName = displayName;
- mDirectoryType = directoryType;
- mDirectoryAccountType = accountType;
- mDirectoryAccountName = accountName;
- mDirectoryExportSupport = exportSupport;
- }
-
- /* package */ void setPhotoBinaryData(byte[] photoBinaryData) {
- mPhotoBinaryData = photoBinaryData;
- }
-
- /**
- * Returns the URI for the contact that contains both the lookup key and the ID. This is
- * the best URI to reference a contact.
- * For directory contacts, this is the same a the URI as returned by {@link #getUri()}
- */
- public Uri getLookupUri() {
- return mLookupUri;
- }
-
- public String getLookupKey() {
- return mLookupKey;
- }
-
- /**
- * Returns the contact Uri that was passed to the provider to make the query. This is
- * the same as the requested Uri, unless the requested Uri doesn't specify a Contact:
- * If it either references a Raw-Contact or a Person (a pre-Eclair style Uri), this Uri will
- * always reference the full aggregate contact.
- */
- public Uri getUri() {
- return mUri;
- }
-
- /**
- * Returns the URI for which this {@link ContactLoader) was initially requested.
- */
- public Uri getRequestedUri() {
- return mRequestedUri;
- }
-
- /**
- * Instantiate a new RawContactDeltaList for this contact.
- */
- public RawContactDeltaList createRawContactDeltaList() {
- return RawContactDeltaList.fromIterator(getRawContacts().iterator());
- }
-
- /**
- * Returns the contact ID.
- */
- @VisibleForTesting
- /* package */ long getId() {
- return mId;
- }
-
- /**
- * @return true when an exception happened during loading, in which case
- * {@link #getException} returns the actual exception object.
- * Note {@link #isNotFound()} and {@link #isError()} are mutually exclusive; If
- * {@link #isError()} is {@code true}, {@link #isNotFound()} is always {@code false},
- * and vice versa.
- */
- public boolean isError() {
- return mStatus == Status.ERROR;
- }
-
- public Exception getException() {
- return mException;
- }
-
- /**
- * @return true when the specified contact is not found.
- * Note {@link #isNotFound()} and {@link #isError()} are mutually exclusive; If
- * {@link #isError()} is {@code true}, {@link #isNotFound()} is always {@code false},
- * and vice versa.
- */
- public boolean isNotFound() {
- return mStatus == Status.NOT_FOUND;
- }
-
- /**
- * @return true if the specified contact is successfully loaded.
- * i.e. neither {@link #isError()} nor {@link #isNotFound()}.
- */
- public boolean isLoaded() {
- return mStatus == Status.LOADED;
- }
-
- public long getNameRawContactId() {
- return mNameRawContactId;
- }
-
- public int getDisplayNameSource() {
- return mDisplayNameSource;
- }
-
- public long getPhotoId() {
- return mPhotoId;
- }
-
- public String getPhotoUri() {
- return mPhotoUri;
- }
-
- public String getDisplayName() {
- return mDisplayName;
- }
-
- public String getAltDisplayName() {
- return mAltDisplayName;
- }
-
- public String getPhoneticName() {
- return mPhoneticName;
- }
-
- public boolean getStarred() {
- return mStarred;
- }
-
- public Integer getPresence() {
- return mPresence;
- }
-
- /**
- * This can return non-null invitable account types only if the {@link ContactLoader} was
- * configured to load invitable account types in its constructor.
- * @return
- */
- public ImmutableList<AccountType> getInvitableAccountTypes() {
- return mInvitableAccountTypes;
- }
-
- public ImmutableList<RawContact> getRawContacts() {
- return mRawContacts;
- }
-
- /**
- * This can return non-null stream items only if the {@link ContactLoader} was
- * configured to load stream items in its constructor.
- * @return
- */
- public ImmutableList<StreamItemEntry> getStreamItems() {
- return ImmutableList.of();
- }
-
- public ImmutableMap<Long, DataStatus> getStatuses() {
- return mStatuses;
- }
-
- public long getDirectoryId() {
- return mDirectoryId;
- }
-
- public boolean isDirectoryEntry() {
- return mDirectoryId != -1 && mDirectoryId != Directory.DEFAULT
- && mDirectoryId != Directory.LOCAL_INVISIBLE;
- }
-
- /**
- * @return true if this is a contact (not group, etc.) with at least one
- * writable raw-contact, and false otherwise.
- */
- public boolean isWritableContact(final Context context) {
- return getFirstWritableRawContactId(context) != -1;
- }
-
- /**
- * Return the ID of the first raw-contact in the contact data that belongs to a
- * contact-writable account, or -1 if no such entity exists.
- */
- public long getFirstWritableRawContactId(final Context context) {
- // Directory entries are non-writable
- if (isDirectoryEntry()) return -1;
-
- // Iterate through raw-contacts; if we find a writable on, return its ID.
- for (RawContact rawContact : getRawContacts()) {
- AccountType accountType = rawContact.getAccountType(context);
- if (accountType != null && accountType.areContactsWritable()) {
- return rawContact.getId();
- }
- }
- // No writable raw-contact was found.
- return -1;
- }
-
- public int getDirectoryExportSupport() {
- return mDirectoryExportSupport;
- }
-
- public String getDirectoryDisplayName() {
- return mDirectoryDisplayName;
- }
-
- public String getDirectoryType() {
- return mDirectoryType;
- }
-
- public String getDirectoryAccountType() {
- return mDirectoryAccountType;
- }
-
- public String getDirectoryAccountName() {
- return mDirectoryAccountName;
- }
-
- public byte[] getPhotoBinaryData() {
- return mPhotoBinaryData;
- }
-
- public ArrayList<ContentValues> getContentValues() {
- if (mRawContacts.size() != 1) {
- throw new IllegalStateException(
- "Cannot extract content values from an aggregated contact");
- }
-
- RawContact rawContact = mRawContacts.get(0);
- ArrayList<ContentValues> result = rawContact.getContentValues();
-
- // If the photo was loaded using the URI, create an entry for the photo
- // binary data.
- if (mPhotoId == 0 && mPhotoBinaryData != null) {
- ContentValues photo = new ContentValues();
- photo.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
- photo.put(Photo.PHOTO, mPhotoBinaryData);
- result.add(photo);
- }
-
- return result;
- }
-
- /**
- * This can return non-null group meta-data only if the {@link ContactLoader} was configured to
- * load group metadata in its constructor.
- * @return
- */
- public ImmutableList<GroupMetaData> getGroupMetaData() {
- return mGroups;
- }
-
- public boolean isSendToVoicemail() {
- return mSendToVoicemail;
- }
-
- public String getCustomRingtone() {
- return mCustomRingtone;
- }
-
- public boolean isUserProfile() {
- return mIsUserProfile;
- }
-
- @Override
- public String toString() {
- return "{requested=" + mRequestedUri + ",lookupkey=" + mLookupKey +
- ",uri=" + mUri + ",status=" + mStatus + "}";
- }
-
- /* package */ void setRawContacts(ImmutableList<RawContact> rawContacts) {
- mRawContacts = rawContacts;
- }
-
- /* package */ void setStatuses(ImmutableMap<Long, DataStatus> statuses) {
- mStatuses = statuses;
- }
-
- /* package */ void setInvitableAccountTypes(ImmutableList<AccountType> accountTypes) {
- mInvitableAccountTypes = accountTypes;
- }
-
- /* package */ void setGroupMetaData(ImmutableList<GroupMetaData> groups) {
- mGroups = groups;
- }
-}
diff --git a/src/com/android/contacts/model/ContactLoader.java b/src/com/android/contacts/model/ContactLoader.java
deleted file mode 100644
index e10fc6c..0000000
--- a/src/com/android/contacts/model/ContactLoader.java
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * Copyright (C) 2010 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.model;
-
-import android.content.AsyncTaskLoader;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.Directory;
-import android.provider.ContactsContract.Groups;
-import android.provider.ContactsContract.RawContacts;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.contacts.GroupMetaData;
-import com.android.contacts.common.GeoUtil;
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountTypeWithDataSet;
-import com.android.contacts.common.util.Constants;
-import com.android.contacts.common.util.UriUtils;
-import com.android.contacts.model.dataitem.DataItem;
-import com.android.contacts.model.dataitem.PhoneDataItem;
-import com.android.contacts.model.dataitem.PhotoDataItem;
-import com.android.contacts.util.ContactLoaderUtils;
-import com.android.contacts.util.DataStatus;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Loads a single Contact and all it constituent RawContacts.
- */
-public class ContactLoader extends AsyncTaskLoader<Contact> {
-
- private static final String TAG = ContactLoader.class.getSimpleName();
-
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- /** A short-lived cache that can be set by {@link #cacheResult()} */
- private static Contact sCachedResult = null;
-
- private final Uri mRequestedUri;
- private Uri mLookupUri;
- private boolean mLoadGroupMetaData;
- private boolean mLoadInvitableAccountTypes;
- private boolean mPostViewNotification;
- private boolean mComputeFormattedPhoneNumber;
- private Contact mContact;
- private ForceLoadContentObserver mObserver;
- private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
-
- public ContactLoader(Context context, Uri lookupUri, boolean postViewNotification) {
- this(context, lookupUri, false, false, postViewNotification, false);
- }
-
- public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData,
- boolean loadInvitableAccountTypes,
- boolean postViewNotification, boolean computeFormattedPhoneNumber) {
- super(context);
- mLookupUri = lookupUri;
- mRequestedUri = lookupUri;
- mLoadGroupMetaData = loadGroupMetaData;
- mLoadInvitableAccountTypes = loadInvitableAccountTypes;
- mPostViewNotification = postViewNotification;
- mComputeFormattedPhoneNumber = computeFormattedPhoneNumber;
- }
-
- /**
- * Projection used for the query that loads all data for the entire contact (except for
- * social stream items).
- */
- private static class ContactQuery {
- static final String[] COLUMNS = new String[] {
- Contacts.NAME_RAW_CONTACT_ID,
- Contacts.DISPLAY_NAME_SOURCE,
- Contacts.LOOKUP_KEY,
- Contacts.DISPLAY_NAME,
- Contacts.DISPLAY_NAME_ALTERNATIVE,
- Contacts.PHONETIC_NAME,
- Contacts.PHOTO_ID,
- Contacts.STARRED,
- Contacts.CONTACT_PRESENCE,
- Contacts.CONTACT_STATUS,
- Contacts.CONTACT_STATUS_TIMESTAMP,
- Contacts.CONTACT_STATUS_RES_PACKAGE,
- Contacts.CONTACT_STATUS_LABEL,
- Contacts.Entity.CONTACT_ID,
- Contacts.Entity.RAW_CONTACT_ID,
-
- RawContacts.ACCOUNT_NAME,
- RawContacts.ACCOUNT_TYPE,
- RawContacts.DATA_SET,
- RawContacts.ACCOUNT_TYPE_AND_DATA_SET,
- RawContacts.DIRTY,
- RawContacts.VERSION,
- RawContacts.SOURCE_ID,
- RawContacts.SYNC1,
- RawContacts.SYNC2,
- RawContacts.SYNC3,
- RawContacts.SYNC4,
- RawContacts.DELETED,
- RawContacts.NAME_VERIFIED,
-
- Contacts.Entity.DATA_ID,
- Data.DATA1,
- Data.DATA2,
- Data.DATA3,
- Data.DATA4,
- Data.DATA5,
- Data.DATA6,
- Data.DATA7,
- Data.DATA8,
- Data.DATA9,
- Data.DATA10,
- Data.DATA11,
- Data.DATA12,
- Data.DATA13,
- Data.DATA14,
- Data.DATA15,
- Data.SYNC1,
- Data.SYNC2,
- Data.SYNC3,
- Data.SYNC4,
- Data.DATA_VERSION,
- Data.IS_PRIMARY,
- Data.IS_SUPER_PRIMARY,
- Data.MIMETYPE,
- Data.RES_PACKAGE,
-
- GroupMembership.GROUP_SOURCE_ID,
-
- Data.PRESENCE,
- Data.CHAT_CAPABILITY,
- Data.STATUS,
- Data.STATUS_RES_PACKAGE,
- Data.STATUS_ICON,
- Data.STATUS_LABEL,
- Data.STATUS_TIMESTAMP,
-
- Contacts.PHOTO_URI,
- Contacts.SEND_TO_VOICEMAIL,
- Contacts.CUSTOM_RINGTONE,
- Contacts.IS_USER_PROFILE,
- };
-
- public static final int NAME_RAW_CONTACT_ID = 0;
- public static final int DISPLAY_NAME_SOURCE = 1;
- public static final int LOOKUP_KEY = 2;
- public static final int DISPLAY_NAME = 3;
- public static final int ALT_DISPLAY_NAME = 4;
- public static final int PHONETIC_NAME = 5;
- public static final int PHOTO_ID = 6;
- public static final int STARRED = 7;
- public static final int CONTACT_PRESENCE = 8;
- public static final int CONTACT_STATUS = 9;
- public static final int CONTACT_STATUS_TIMESTAMP = 10;
- public static final int CONTACT_STATUS_RES_PACKAGE = 11;
- public static final int CONTACT_STATUS_LABEL = 12;
- public static final int CONTACT_ID = 13;
- public static final int RAW_CONTACT_ID = 14;
-
- public static final int ACCOUNT_NAME = 15;
- public static final int ACCOUNT_TYPE = 16;
- public static final int DATA_SET = 17;
- public static final int ACCOUNT_TYPE_AND_DATA_SET = 18;
- public static final int DIRTY = 19;
- public static final int VERSION = 20;
- public static final int SOURCE_ID = 21;
- public static final int SYNC1 = 22;
- public static final int SYNC2 = 23;
- public static final int SYNC3 = 24;
- public static final int SYNC4 = 25;
- public static final int DELETED = 26;
- public static final int NAME_VERIFIED = 27;
-
- public static final int DATA_ID = 28;
- public static final int DATA1 = 29;
- public static final int DATA2 = 30;
- public static final int DATA3 = 31;
- public static final int DATA4 = 32;
- public static final int DATA5 = 33;
- public static final int DATA6 = 34;
- public static final int DATA7 = 35;
- public static final int DATA8 = 36;
- public static final int DATA9 = 37;
- public static final int DATA10 = 38;
- public static final int DATA11 = 39;
- public static final int DATA12 = 40;
- public static final int DATA13 = 41;
- public static final int DATA14 = 42;
- public static final int DATA15 = 43;
- public static final int DATA_SYNC1 = 44;
- public static final int DATA_SYNC2 = 45;
- public static final int DATA_SYNC3 = 46;
- public static final int DATA_SYNC4 = 47;
- public static final int DATA_VERSION = 48;
- public static final int IS_PRIMARY = 49;
- public static final int IS_SUPERPRIMARY = 50;
- public static final int MIMETYPE = 51;
- public static final int RES_PACKAGE = 52;
-
- public static final int GROUP_SOURCE_ID = 53;
-
- public static final int PRESENCE = 54;
- public static final int CHAT_CAPABILITY = 55;
- public static final int STATUS = 56;
- public static final int STATUS_RES_PACKAGE = 57;
- public static final int STATUS_ICON = 58;
- public static final int STATUS_LABEL = 59;
- public static final int STATUS_TIMESTAMP = 60;
-
- public static final int PHOTO_URI = 61;
- public static final int SEND_TO_VOICEMAIL = 62;
- public static final int CUSTOM_RINGTONE = 63;
- public static final int IS_USER_PROFILE = 64;
- }
-
- /**
- * Projection used for the query that loads all data for the entire contact.
- */
- private static class DirectoryQuery {
- static final String[] COLUMNS = new String[] {
- Directory.DISPLAY_NAME,
- Directory.PACKAGE_NAME,
- Directory.TYPE_RESOURCE_ID,
- Directory.ACCOUNT_TYPE,
- Directory.ACCOUNT_NAME,
- Directory.EXPORT_SUPPORT,
- };
-
- public static final int DISPLAY_NAME = 0;
- public static final int PACKAGE_NAME = 1;
- public static final int TYPE_RESOURCE_ID = 2;
- public static final int ACCOUNT_TYPE = 3;
- public static final int ACCOUNT_NAME = 4;
- public static final int EXPORT_SUPPORT = 5;
- }
-
- private static class GroupQuery {
- static final String[] COLUMNS = new String[] {
- Groups.ACCOUNT_NAME,
- Groups.ACCOUNT_TYPE,
- Groups.DATA_SET,
- Groups.ACCOUNT_TYPE_AND_DATA_SET,
- Groups._ID,
- Groups.TITLE,
- Groups.AUTO_ADD,
- Groups.FAVORITES,
- };
-
- public static final int ACCOUNT_NAME = 0;
- public static final int ACCOUNT_TYPE = 1;
- public static final int DATA_SET = 2;
- public static final int ACCOUNT_TYPE_AND_DATA_SET = 3;
- public static final int ID = 4;
- public static final int TITLE = 5;
- public static final int AUTO_ADD = 6;
- public static final int FAVORITES = 7;
- }
-
- @Override
- public Contact loadInBackground() {
- try {
- final ContentResolver resolver = getContext().getContentResolver();
- final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(
- resolver, mLookupUri);
- final Contact cachedResult = sCachedResult;
- sCachedResult = null;
- // Is this the same Uri as what we had before already? In that case, reuse that result
- final Contact result;
- final boolean resultIsCached;
- if (cachedResult != null &&
- UriUtils.areEqual(cachedResult.getLookupUri(), mLookupUri)) {
- // We are using a cached result from earlier. Below, we should make sure
- // we are not doing any more network or disc accesses
- result = new Contact(mRequestedUri, cachedResult);
- resultIsCached = true;
- } else {
- if (uriCurrentFormat.getLastPathSegment().equals(Constants.LOOKUP_URI_ENCODED)) {
- result = loadEncodedContactEntity(uriCurrentFormat);
- } else {
- result = loadContactEntity(resolver, uriCurrentFormat);
- }
- resultIsCached = false;
- }
- if (result.isLoaded()) {
- if (result.isDirectoryEntry()) {
- if (!resultIsCached) {
- loadDirectoryMetaData(result);
- }
- } else if (mLoadGroupMetaData) {
- if (result.getGroupMetaData() == null) {
- loadGroupMetaData(result);
- }
- }
- if (mComputeFormattedPhoneNumber) {
- computeFormattedPhoneNumbers(result);
- }
- if (!resultIsCached) loadPhotoBinaryData(result);
-
- // Note ME profile should never have "Add connection"
- if (mLoadInvitableAccountTypes && result.getInvitableAccountTypes() == null) {
- loadInvitableAccountTypes(result);
- }
- }
- return result;
- } catch (Exception e) {
- Log.e(TAG, "Error loading the contact: " + mLookupUri, e);
- return Contact.forError(mRequestedUri, e);
- }
- }
-
- private Contact loadEncodedContactEntity(Uri uri) throws JSONException {
- final String jsonString = uri.getEncodedFragment();
- final JSONObject json = new JSONObject(jsonString);
-
- final long directoryId =
- Long.valueOf(uri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY));
-
- final String displayName = json.getString(Contacts.DISPLAY_NAME);
- final String altDisplayName = json.optString(
- Contacts.DISPLAY_NAME_ALTERNATIVE, displayName);
- final int displayNameSource = json.getInt(Contacts.DISPLAY_NAME_SOURCE);
- final String photoUri = json.optString(Contacts.PHOTO_URI, null);
- final Contact contact = new Contact(
- uri, uri,
- mLookupUri,
- directoryId,
- null /* lookupKey */,
- -1 /* id */,
- -1 /* nameRawContactId */,
- displayNameSource,
- 0 /* photoId */,
- photoUri,
- displayName,
- altDisplayName,
- null /* phoneticName */,
- false /* starred */,
- null /* presence */,
- false /* sendToVoicemail */,
- null /* customRingtone */,
- false /* isUserProfile */);
-
- contact.setStatuses(new ImmutableMap.Builder<Long, DataStatus>().build());
-
- final String accountName = json.optString(RawContacts.ACCOUNT_NAME, null);
- final String directoryName = uri.getQueryParameter(Directory.DISPLAY_NAME);
- if (accountName != null) {
- final String accountType = json.getString(RawContacts.ACCOUNT_TYPE);
- contact.setDirectoryMetaData(directoryName, null, accountName, accountType,
- json.optInt(Directory.EXPORT_SUPPORT,
- Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY));
- } else {
- contact.setDirectoryMetaData(directoryName, null, null, null,
- json.optInt(Directory.EXPORT_SUPPORT, Directory.EXPORT_SUPPORT_ANY_ACCOUNT));
- }
-
- final ContentValues values = new ContentValues();
- values.put(Data._ID, -1);
- values.put(Data.CONTACT_ID, -1);
- final RawContact rawContact = new RawContact(values);
-
- final JSONObject items = json.getJSONObject(Contacts.CONTENT_ITEM_TYPE);
- final Iterator keys = items.keys();
- while (keys.hasNext()) {
- final String mimetype = (String) keys.next();
-
- // Could be single object or array.
- final JSONObject obj = items.optJSONObject(mimetype);
- if (obj == null) {
- final JSONArray array = items.getJSONArray(mimetype);
- for (int i = 0; i < array.length(); i++) {
- final JSONObject item = array.getJSONObject(i);
- processOneRecord(rawContact, item, mimetype);
- }
- } else {
- processOneRecord(rawContact, obj, mimetype);
- }
- }
-
- contact.setRawContacts(new ImmutableList.Builder<RawContact>()
- .add(rawContact)
- .build());
- return contact;
- }
-
- private void processOneRecord(RawContact rawContact, JSONObject item, String mimetype)
- throws JSONException {
- final ContentValues itemValues = new ContentValues();
- itemValues.put(Data.MIMETYPE, mimetype);
- itemValues.put(Data._ID, -1);
-
- final Iterator iterator = item.keys();
- while (iterator.hasNext()) {
- String name = (String) iterator.next();
- final Object o = item.get(name);
- if (o instanceof String) {
- itemValues.put(name, (String) o);
- } else if (o instanceof Integer) {
- itemValues.put(name, (Integer) o);
- }
- }
- rawContact.addDataItemValues(itemValues);
- }
-
- private Contact loadContactEntity(ContentResolver resolver, Uri contactUri) {
- Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY);
- Cursor cursor = resolver.query(entityUri, ContactQuery.COLUMNS, null, null,
- Contacts.Entity.RAW_CONTACT_ID);
- if (cursor == null) {
- Log.e(TAG, "No cursor returned in loadContactEntity");
- return Contact.forNotFound(mRequestedUri);
- }
-
- try {
- if (!cursor.moveToFirst()) {
- cursor.close();
- return Contact.forNotFound(mRequestedUri);
- }
-
- // Create the loaded contact starting with the header data.
- Contact contact = loadContactHeaderData(cursor, contactUri);
-
- // Fill in the raw contacts, which is wrapped in an Entity and any
- // status data. Initially, result has empty entities and statuses.
- long currentRawContactId = -1;
- RawContact rawContact = null;
- ImmutableList.Builder<RawContact> rawContactsBuilder =
- new ImmutableList.Builder<RawContact>();
- ImmutableMap.Builder<Long, DataStatus> statusesBuilder =
- new ImmutableMap.Builder<Long, DataStatus>();
- do {
- long rawContactId = cursor.getLong(ContactQuery.RAW_CONTACT_ID);
- if (rawContactId != currentRawContactId) {
- // First time to see this raw contact id, so create a new entity, and
- // add it to the result's entities.
- currentRawContactId = rawContactId;
- rawContact = new RawContact(loadRawContactValues(cursor));
- rawContactsBuilder.add(rawContact);
- }
- if (!cursor.isNull(ContactQuery.DATA_ID)) {
- ContentValues data = loadDataValues(cursor);
- rawContact.addDataItemValues(data);
-
- if (!cursor.isNull(ContactQuery.PRESENCE)
- || !cursor.isNull(ContactQuery.STATUS)) {
- final DataStatus status = new DataStatus(cursor);
- final long dataId = cursor.getLong(ContactQuery.DATA_ID);
- statusesBuilder.put(dataId, status);
- }
- }
- } while (cursor.moveToNext());
-
- contact.setRawContacts(rawContactsBuilder.build());
- contact.setStatuses(statusesBuilder.build());
-
- return contact;
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Looks for the photo data item in entities. If found, creates a new Bitmap instance. If
- * not found, returns null
- */
- private void loadPhotoBinaryData(Contact contactData) {
- // If we have a photo URI, try loading that first.
- String photoUri = contactData.getPhotoUri();
- if (photoUri != null) {
- try {
- final InputStream inputStream;
- final AssetFileDescriptor fd;
- final Uri uri = Uri.parse(photoUri);
- final String scheme = uri.getScheme();
- if ("http".equals(scheme) || "https".equals(scheme)) {
- // Support HTTP urls that might come from extended directories
- inputStream = new URL(photoUri).openStream();
- fd = null;
- } else {
- fd = getContext().getContentResolver().openAssetFileDescriptor(uri, "r");
- inputStream = fd.createInputStream();
- }
- byte[] buffer = new byte[16 * 1024];
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- int size;
- while ((size = inputStream.read(buffer)) != -1) {
- baos.write(buffer, 0, size);
- }
- contactData.setPhotoBinaryData(baos.toByteArray());
- } finally {
- inputStream.close();
- if (fd != null) {
- fd.close();
- }
- }
- return;
- } catch (IOException ioe) {
- // Just fall back to the case below.
- }
- }
-
- // If we couldn't load from a file, fall back to the data blob.
- final long photoId = contactData.getPhotoId();
- if (photoId <= 0) {
- // No photo ID
- return;
- }
-
- for (RawContact rawContact : contactData.getRawContacts()) {
- for (DataItem dataItem : rawContact.getDataItems()) {
- if (dataItem.getId() == photoId) {
- if (!(dataItem instanceof PhotoDataItem)) {
- break;
- }
-
- final PhotoDataItem photo = (PhotoDataItem) dataItem;
- contactData.setPhotoBinaryData(photo.getPhoto());
- break;
- }
- }
- }
- }
-
- /**
- * Sets the "invitable" account types to {@link Contact#mInvitableAccountTypes}.
- */
- private void loadInvitableAccountTypes(Contact contactData) {
- final ImmutableList.Builder<AccountType> resultListBuilder =
- new ImmutableList.Builder<AccountType>();
- if (!contactData.isUserProfile()) {
- Map<AccountTypeWithDataSet, AccountType> invitables =
- AccountTypeManager.getInstance(getContext()).getUsableInvitableAccountTypes();
- if (!invitables.isEmpty()) {
- final Map<AccountTypeWithDataSet, AccountType> resultMap =
- Maps.newHashMap(invitables);
-
- // Remove the ones that already have a raw contact in the current contact
- for (RawContact rawContact : contactData.getRawContacts()) {
- final AccountTypeWithDataSet type = AccountTypeWithDataSet.get(
- rawContact.getAccountTypeString(),
- rawContact.getDataSet());
- resultMap.remove(type);
- }
-
- resultListBuilder.addAll(resultMap.values());
- }
- }
-
- // Set to mInvitableAccountTypes
- contactData.setInvitableAccountTypes(resultListBuilder.build());
- }
-
- /**
- * Extracts Contact level columns from the cursor.
- */
- private Contact loadContactHeaderData(final Cursor cursor, Uri contactUri) {
- final String directoryParameter =
- contactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
- final long directoryId = directoryParameter == null
- ? Directory.DEFAULT
- : Long.parseLong(directoryParameter);
- final long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
- final String lookupKey = cursor.getString(ContactQuery.LOOKUP_KEY);
- final long nameRawContactId = cursor.getLong(ContactQuery.NAME_RAW_CONTACT_ID);
- final int displayNameSource = cursor.getInt(ContactQuery.DISPLAY_NAME_SOURCE);
- final String displayName = cursor.getString(ContactQuery.DISPLAY_NAME);
- final String altDisplayName = cursor.getString(ContactQuery.ALT_DISPLAY_NAME);
- final String phoneticName = cursor.getString(ContactQuery.PHONETIC_NAME);
- final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
- final String photoUri = cursor.getString(ContactQuery.PHOTO_URI);
- final boolean starred = cursor.getInt(ContactQuery.STARRED) != 0;
- final Integer presence = cursor.isNull(ContactQuery.CONTACT_PRESENCE)
- ? null
- : cursor.getInt(ContactQuery.CONTACT_PRESENCE);
- final boolean sendToVoicemail = cursor.getInt(ContactQuery.SEND_TO_VOICEMAIL) == 1;
- final String customRingtone = cursor.getString(ContactQuery.CUSTOM_RINGTONE);
- final boolean isUserProfile = cursor.getInt(ContactQuery.IS_USER_PROFILE) == 1;
-
- Uri lookupUri;
- if (directoryId == Directory.DEFAULT || directoryId == Directory.LOCAL_INVISIBLE) {
- lookupUri = ContentUris.withAppendedId(
- Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), contactId);
- } else {
- lookupUri = contactUri;
- }
-
- return new Contact(mRequestedUri, contactUri, lookupUri, directoryId, lookupKey,
- contactId, nameRawContactId, displayNameSource, photoId, photoUri, displayName,
- altDisplayName, phoneticName, starred, presence, sendToVoicemail,
- customRingtone, isUserProfile);
- }
-
- /**
- * Extracts RawContact level columns from the cursor.
- */
- private ContentValues loadRawContactValues(Cursor cursor) {
- ContentValues cv = new ContentValues();
-
- cv.put(RawContacts._ID, cursor.getLong(ContactQuery.RAW_CONTACT_ID));
-
- cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_NAME);
- cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SET);
- cursorColumnToContentValues(cursor, cv, ContactQuery.ACCOUNT_TYPE_AND_DATA_SET);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DIRTY);
- cursorColumnToContentValues(cursor, cv, ContactQuery.VERSION);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SOURCE_ID);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC1);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC2);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC3);
- cursorColumnToContentValues(cursor, cv, ContactQuery.SYNC4);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DELETED);
- cursorColumnToContentValues(cursor, cv, ContactQuery.CONTACT_ID);
- cursorColumnToContentValues(cursor, cv, ContactQuery.STARRED);
- cursorColumnToContentValues(cursor, cv, ContactQuery.NAME_VERIFIED);
-
- return cv;
- }
-
- /**
- * Extracts Data level columns from the cursor.
- */
- private ContentValues loadDataValues(Cursor cursor) {
- ContentValues cv = new ContentValues();
-
- cv.put(Data._ID, cursor.getLong(ContactQuery.DATA_ID));
-
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA1);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA2);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA3);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA4);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA5);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA6);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA7);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA8);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA9);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA10);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA11);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA12);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA13);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA14);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA15);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC1);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC2);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC3);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_SYNC4);
- cursorColumnToContentValues(cursor, cv, ContactQuery.DATA_VERSION);
- cursorColumnToContentValues(cursor, cv, ContactQuery.IS_PRIMARY);
- cursorColumnToContentValues(cursor, cv, ContactQuery.IS_SUPERPRIMARY);
- cursorColumnToContentValues(cursor, cv, ContactQuery.MIMETYPE);
- cursorColumnToContentValues(cursor, cv, ContactQuery.RES_PACKAGE);
- cursorColumnToContentValues(cursor, cv, ContactQuery.GROUP_SOURCE_ID);
- cursorColumnToContentValues(cursor, cv, ContactQuery.CHAT_CAPABILITY);
-
- return cv;
- }
-
- private void cursorColumnToContentValues(
- Cursor cursor, ContentValues values, int index) {
- switch (cursor.getType(index)) {
- case Cursor.FIELD_TYPE_NULL:
- // don't put anything in the content values
- break;
- case Cursor.FIELD_TYPE_INTEGER:
- values.put(ContactQuery.COLUMNS[index], cursor.getLong(index));
- break;
- case Cursor.FIELD_TYPE_STRING:
- values.put(ContactQuery.COLUMNS[index], cursor.getString(index));
- break;
- case Cursor.FIELD_TYPE_BLOB:
- values.put(ContactQuery.COLUMNS[index], cursor.getBlob(index));
- break;
- default:
- throw new IllegalStateException("Invalid or unhandled data type");
- }
- }
-
- private void loadDirectoryMetaData(Contact result) {
- long directoryId = result.getDirectoryId();
-
- Cursor cursor = getContext().getContentResolver().query(
- ContentUris.withAppendedId(Directory.CONTENT_URI, directoryId),
- DirectoryQuery.COLUMNS, null, null, null);
- if (cursor == null) {
- return;
- }
- try {
- if (cursor.moveToFirst()) {
- final String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
- final String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
- final int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
- final String accountType = cursor.getString(DirectoryQuery.ACCOUNT_TYPE);
- final String accountName = cursor.getString(DirectoryQuery.ACCOUNT_NAME);
- final int exportSupport = cursor.getInt(DirectoryQuery.EXPORT_SUPPORT);
- String directoryType = null;
- if (!TextUtils.isEmpty(packageName)) {
- PackageManager pm = getContext().getPackageManager();
- try {
- Resources resources = pm.getResourcesForApplication(packageName);
- directoryType = resources.getString(typeResourceId);
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Contact directory resource not found: "
- + packageName + "." + typeResourceId);
- }
- }
-
- result.setDirectoryMetaData(
- displayName, directoryType, accountType, accountName, exportSupport);
- }
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Loads groups meta-data for all groups associated with all constituent raw contacts'
- * accounts.
- */
- private void loadGroupMetaData(Contact result) {
- StringBuilder selection = new StringBuilder();
- ArrayList<String> selectionArgs = new ArrayList<String>();
- for (RawContact rawContact : result.getRawContacts()) {
- final String accountName = rawContact.getAccountName();
- final String accountType = rawContact.getAccountTypeString();
- final String dataSet = rawContact.getDataSet();
- if (accountName != null && accountType != null) {
- if (selection.length() != 0) {
- selection.append(" OR ");
- }
- selection.append(
- "(" + Groups.ACCOUNT_NAME + "=? AND " + Groups.ACCOUNT_TYPE + "=?");
- selectionArgs.add(accountName);
- selectionArgs.add(accountType);
-
- if (dataSet != null) {
- selection.append(" AND " + Groups.DATA_SET + "=?");
- selectionArgs.add(dataSet);
- } else {
- selection.append(" AND " + Groups.DATA_SET + " IS NULL");
- }
- selection.append(")");
- }
- }
- final ImmutableList.Builder<GroupMetaData> groupListBuilder =
- new ImmutableList.Builder<GroupMetaData>();
- final Cursor cursor = getContext().getContentResolver().query(Groups.CONTENT_URI,
- GroupQuery.COLUMNS, selection.toString(), selectionArgs.toArray(new String[0]),
- null);
- try {
- while (cursor.moveToNext()) {
- final String accountName = cursor.getString(GroupQuery.ACCOUNT_NAME);
- final String accountType = cursor.getString(GroupQuery.ACCOUNT_TYPE);
- final String dataSet = cursor.getString(GroupQuery.DATA_SET);
- final long groupId = cursor.getLong(GroupQuery.ID);
- final String title = cursor.getString(GroupQuery.TITLE);
- final boolean defaultGroup = cursor.isNull(GroupQuery.AUTO_ADD)
- ? false
- : cursor.getInt(GroupQuery.AUTO_ADD) != 0;
- final boolean favorites = cursor.isNull(GroupQuery.FAVORITES)
- ? false
- : cursor.getInt(GroupQuery.FAVORITES) != 0;
-
- groupListBuilder.add(new GroupMetaData(
- accountName, accountType, dataSet, groupId, title, defaultGroup,
- favorites));
- }
- } finally {
- cursor.close();
- }
- result.setGroupMetaData(groupListBuilder.build());
- }
-
- /**
- * Iterates over all data items that represent phone numbers are tries to calculate a formatted
- * number. This function can safely be called several times as no unformatted data is
- * overwritten
- */
- private void computeFormattedPhoneNumbers(Contact contactData) {
- final String countryIso = GeoUtil.getCurrentCountryIso(getContext());
- final ImmutableList<RawContact> rawContacts = contactData.getRawContacts();
- final int rawContactCount = rawContacts.size();
- for (int rawContactIndex = 0; rawContactIndex < rawContactCount; rawContactIndex++) {
- final RawContact rawContact = rawContacts.get(rawContactIndex);
- final List<DataItem> dataItems = rawContact.getDataItems();
- final int dataCount = dataItems.size();
- for (int dataIndex = 0; dataIndex < dataCount; dataIndex++) {
- final DataItem dataItem = dataItems.get(dataIndex);
- if (dataItem instanceof PhoneDataItem) {
- final PhoneDataItem phoneDataItem = (PhoneDataItem) dataItem;
- phoneDataItem.computeFormattedPhoneNumber(countryIso);
- }
- }
- }
- }
-
- @Override
- public void deliverResult(Contact result) {
- unregisterObserver();
-
- // The creator isn't interested in any further updates
- if (isReset() || result == null) {
- return;
- }
-
- mContact = result;
-
- if (result.isLoaded()) {
- mLookupUri = result.getLookupUri();
-
- if (!result.isDirectoryEntry()) {
- Log.i(TAG, "Registering content observer for " + mLookupUri);
- if (mObserver == null) {
- mObserver = new ForceLoadContentObserver();
- }
- getContext().getContentResolver().registerContentObserver(
- mLookupUri, true, mObserver);
- }
-
- if (mPostViewNotification) {
- // inform the source of the data that this contact is being looked at
- postViewNotificationToSyncAdapter();
- }
- }
-
- super.deliverResult(mContact);
- }
-
- /**
- * Posts a message to the contributing sync adapters that have opted-in, notifying them
- * that the contact has just been loaded
- */
- private void postViewNotificationToSyncAdapter() {
- Context context = getContext();
- for (RawContact rawContact : mContact.getRawContacts()) {
- final long rawContactId = rawContact.getId();
- if (mNotifiedRawContactIds.contains(rawContactId)) {
- continue; // Already notified for this raw contact.
- }
- mNotifiedRawContactIds.add(rawContactId);
- final AccountType accountType = rawContact.getAccountType(context);
- final String serviceName = accountType.getViewContactNotifyServiceClassName();
- final String servicePackageName = accountType.getViewContactNotifyServicePackageName();
- if (!TextUtils.isEmpty(serviceName) && !TextUtils.isEmpty(servicePackageName)) {
- final Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
- final Intent intent = new Intent();
- intent.setClassName(servicePackageName, serviceName);
- intent.setAction(Intent.ACTION_VIEW);
- intent.setDataAndType(uri, RawContacts.CONTENT_ITEM_TYPE);
- try {
- context.startService(intent);
- } catch (Exception e) {
- Log.e(TAG, "Error sending message to source-app", e);
- }
- }
- }
- }
-
- private void unregisterObserver() {
- if (mObserver != null) {
- getContext().getContentResolver().unregisterContentObserver(mObserver);
- mObserver = null;
- }
- }
-
- /**
- * Fully upgrades this ContactLoader to one with all lists fully loaded. When done, the
- * new result will be delivered
- */
- public void upgradeToFullContact() {
- // Everything requested already? Nothing to do, so let's bail out
- if (mLoadGroupMetaData && mLoadInvitableAccountTypes
- && mPostViewNotification && mComputeFormattedPhoneNumber) return;
-
- mLoadGroupMetaData = true;
- mLoadInvitableAccountTypes = true;
- mPostViewNotification = true;
- mComputeFormattedPhoneNumber = true;
-
- // Cache the current result, so that we only load the "missing" parts of the contact.
- cacheResult();
-
- // Our load parameters have changed, so let's pretend the data has changed. Its the same
- // thing, essentially.
- onContentChanged();
- }
-
- public Uri getLookupUri() {
- return mLookupUri;
- }
-
- @Override
- protected void onStartLoading() {
- if (mContact != null) {
- deliverResult(mContact);
- }
-
- if (takeContentChanged() || mContact == null) {
- forceLoad();
- }
- }
-
- @Override
- protected void onStopLoading() {
- cancelLoad();
- }
-
- @Override
- protected void onReset() {
- super.onReset();
- cancelLoad();
- unregisterObserver();
- mContact = null;
- }
-
- /**
- * Caches the result, which is useful when we switch from activity to activity, using the same
- * contact. If the next load is for a different contact, the cached result will be dropped
- */
- public void cacheResult() {
- if (mContact == null || !mContact.isLoaded()) {
- sCachedResult = null;
- } else {
- sCachedResult = mContact;
- }
- }
-}
diff --git a/src/com/android/contacts/model/RawContact.java b/src/com/android/contacts/model/RawContact.java
deleted file mode 100644
index 096e377..0000000
--- a/src/com/android/contacts/model/RawContact.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2012 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.model;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Entity;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.model.dataitem.DataItem;
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * RawContact represents a single raw contact in the raw contacts database.
- * It has specialized getters/setters for raw contact
- * items, and also contains a collection of DataItem objects. A RawContact contains the information
- * from a single account.
- *
- * This allows RawContact objects to be thought of as a class with raw contact
- * fields (like account type, name, data set, sync state, etc.) and a list of
- * DataItem objects that represent contact information elements (like phone
- * numbers, email, address, etc.).
- */
-final public class RawContact implements Parcelable {
-
- private AccountTypeManager mAccountTypeManager;
- private final ContentValues mValues;
- private final ArrayList<NamedDataItem> mDataItems;
-
- final public static class NamedDataItem implements Parcelable {
- public final Uri mUri;
-
- // This use to be a DataItem. DataItem creation is now delayed until the point of request
- // since there is no benefit to storing them here due to the multiple inheritance.
- // Eventually instanceof still has to be used anyways to determine which sub-class of
- // DataItem it is. And having parent DataItem's here makes it very difficult to serialize or
- // parcelable.
- //
- // Instead of having a common DataItem super class, we should refactor this to be a generic
- // Object where the object is a concrete class that no longer relies on ContentValues.
- // (this will also make the classes easier to use).
- // Since instanceof is used later anyways, having a list of Objects won't hurt and is no
- // worse than having a DataItem.
- public final ContentValues mContentValues;
-
- public NamedDataItem(Uri uri, ContentValues values) {
- this.mUri = uri;
- this.mContentValues = values;
- }
-
- public NamedDataItem(Parcel parcel) {
- this.mUri = parcel.readParcelable(Uri.class.getClassLoader());
- this.mContentValues = parcel.readParcelable(ContentValues.class.getClassLoader());
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int i) {
- parcel.writeParcelable(mUri, i);
- parcel.writeParcelable(mContentValues, i);
- }
-
- public static final Parcelable.Creator<NamedDataItem> CREATOR
- = new Parcelable.Creator<NamedDataItem>() {
-
- @Override
- public NamedDataItem createFromParcel(Parcel parcel) {
- return new NamedDataItem(parcel);
- }
-
- @Override
- public NamedDataItem[] newArray(int i) {
- return new NamedDataItem[i];
- }
- };
-
- @Override
- public int hashCode() {
- return Objects.hashCode(mUri, mContentValues);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
-
- final NamedDataItem other = (NamedDataItem) obj;
- return Objects.equal(mUri, other.mUri) &&
- Objects.equal(mContentValues, other.mContentValues);
- }
- }
-
- public static RawContact createFrom(Entity entity) {
- final ContentValues values = entity.getEntityValues();
- final ArrayList<Entity.NamedContentValues> subValues = entity.getSubValues();
-
- RawContact rawContact = new RawContact(values);
- for (Entity.NamedContentValues subValue : subValues) {
- rawContact.addNamedDataItemValues(subValue.uri, subValue.values);
- }
- return rawContact;
- }
-
- /**
- * A RawContact object can be created with or without a context.
- */
- public RawContact() {
- this(new ContentValues());
- }
-
- public RawContact(ContentValues values) {
- mValues = values;
- mDataItems = new ArrayList<NamedDataItem>();
- }
-
- /**
- * Constructor for the parcelable.
- *
- * @param parcel The parcel to de-serialize from.
- */
- private RawContact(Parcel parcel) {
- mValues = parcel.readParcelable(ContentValues.class.getClassLoader());
- mDataItems = Lists.newArrayList();
- parcel.readTypedList(mDataItems, NamedDataItem.CREATOR);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int i) {
- parcel.writeParcelable(mValues, i);
- parcel.writeTypedList(mDataItems);
- }
-
- /**
- * Create for building the parcelable.
- */
- public static final Parcelable.Creator<RawContact> CREATOR
- = new Parcelable.Creator<RawContact>() {
-
- @Override
- public RawContact createFromParcel(Parcel parcel) {
- return new RawContact(parcel);
- }
-
- @Override
- public RawContact[] newArray(int i) {
- return new RawContact[i];
- }
- };
-
- public AccountTypeManager getAccountTypeManager(Context context) {
- if (mAccountTypeManager == null) {
- mAccountTypeManager = AccountTypeManager.getInstance(context);
- }
- return mAccountTypeManager;
- }
-
- public ContentValues getValues() {
- return mValues;
- }
-
- /**
- * Returns the id of the raw contact.
- */
- public Long getId() {
- return getValues().getAsLong(RawContacts._ID);
- }
-
- /**
- * Returns the account name of the raw contact.
- */
- public String getAccountName() {
- return getValues().getAsString(RawContacts.ACCOUNT_NAME);
- }
-
- /**
- * Returns the account type of the raw contact.
- */
- public String getAccountTypeString() {
- return getValues().getAsString(RawContacts.ACCOUNT_TYPE);
- }
-
- /**
- * Returns the data set of the raw contact.
- */
- public String getDataSet() {
- return getValues().getAsString(RawContacts.DATA_SET);
- }
-
- /**
- * Returns the account type and data set of the raw contact.
- */
- public String getAccountTypeAndDataSetString() {
- return getValues().getAsString(RawContacts.ACCOUNT_TYPE_AND_DATA_SET);
- }
-
- public boolean isDirty() {
- return getValues().getAsBoolean(RawContacts.DIRTY);
- }
-
- public String getSourceId() {
- return getValues().getAsString(RawContacts.SOURCE_ID);
- }
-
- public String getSync1() {
- return getValues().getAsString(RawContacts.SYNC1);
- }
-
- public String getSync2() {
- return getValues().getAsString(RawContacts.SYNC2);
- }
-
- public String getSync3() {
- return getValues().getAsString(RawContacts.SYNC3);
- }
-
- public String getSync4() {
- return getValues().getAsString(RawContacts.SYNC4);
- }
-
- public boolean isDeleted() {
- return getValues().getAsBoolean(RawContacts.DELETED);
- }
-
- public boolean isNameVerified() {
- return getValues().getAsBoolean(RawContacts.NAME_VERIFIED);
- }
-
- public long getContactId() {
- return getValues().getAsLong(Contacts.Entity.CONTACT_ID);
- }
-
- public boolean isStarred() {
- return getValues().getAsBoolean(Contacts.STARRED);
- }
-
- public AccountType getAccountType(Context context) {
- return getAccountTypeManager(context).getAccountType(getAccountTypeString(), getDataSet());
- }
-
- /**
- * Sets the account name, account type, and data set strings.
- * Valid combinations for account-name, account-type, data-set
- * 1) null, null, null (local account)
- * 2) non-null, non-null, null (valid account without data-set)
- * 3) non-null, non-null, non-null (valid account with data-set)
- */
- private void setAccount(String accountName, String accountType, String dataSet) {
- final ContentValues values = getValues();
- if (accountName == null) {
- if (accountType == null && dataSet == null) {
- // This is a local account
- values.putNull(RawContacts.ACCOUNT_NAME);
- values.putNull(RawContacts.ACCOUNT_TYPE);
- values.putNull(RawContacts.DATA_SET);
- return;
- }
- } else {
- if (accountType != null) {
- // This is a valid account, either with or without a dataSet.
- values.put(RawContacts.ACCOUNT_NAME, accountName);
- values.put(RawContacts.ACCOUNT_TYPE, accountType);
- if (dataSet == null) {
- values.putNull(RawContacts.DATA_SET);
- } else {
- values.put(RawContacts.DATA_SET, dataSet);
- }
- return;
- }
- }
- throw new IllegalArgumentException(
- "Not a valid combination of account name, type, and data set.");
- }
-
- public void setAccount(AccountWithDataSet accountWithDataSet) {
- setAccount(accountWithDataSet.name, accountWithDataSet.type, accountWithDataSet.dataSet);
- }
-
- public void setAccountToLocal() {
- setAccount(null, null, null);
- }
-
- /**
- * Creates and inserts a DataItem object that wraps the content values, and returns it.
- */
- public void addDataItemValues(ContentValues values) {
- addNamedDataItemValues(Data.CONTENT_URI, values);
- }
-
- public NamedDataItem addNamedDataItemValues(Uri uri, ContentValues values) {
- final NamedDataItem namedItem = new NamedDataItem(uri, values);
- mDataItems.add(namedItem);
- return namedItem;
- }
-
- public ArrayList<ContentValues> getContentValues() {
- final ArrayList<ContentValues> list = Lists.newArrayListWithCapacity(mDataItems.size());
- for (NamedDataItem dataItem : mDataItems) {
- if (Data.CONTENT_URI.equals(dataItem.mUri)) {
- list.add(dataItem.mContentValues);
- }
- }
- return list;
- }
-
- public List<DataItem> getDataItems() {
- final ArrayList<DataItem> list = Lists.newArrayListWithCapacity(mDataItems.size());
- for (NamedDataItem dataItem : mDataItems) {
- if (Data.CONTENT_URI.equals(dataItem.mUri)) {
- list.add(DataItem.createFrom(dataItem.mContentValues));
- }
- }
- return list;
- }
-
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append("RawContact: ").append(mValues);
- for (RawContact.NamedDataItem namedDataItem : mDataItems) {
- sb.append("\n ").append(namedDataItem.mUri);
- sb.append("\n -> ").append(namedDataItem.mContentValues);
- }
- return sb.toString();
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(mValues, mDataItems);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
-
- RawContact other = (RawContact) obj;
- return Objects.equal(mValues, other.mValues) &&
- Objects.equal(mDataItems, other.mDataItems);
- }
-}
diff --git a/src/com/android/contacts/model/RawContactDelta.java b/src/com/android/contacts/model/RawContactDelta.java
deleted file mode 100644
index 373eabd..0000000
--- a/src/com/android/contacts/model/RawContactDelta.java
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * Copyright (C) 2009 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.model;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderOperation.Builder;
-import android.content.ContentValues;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.provider.BaseColumns;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.Profile;
-import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
-
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.test.NeededForTesting;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * Contains a {@link RawContact} and records any modifications separately so the
- * original {@link RawContact} can be swapped out with a newer version and the
- * changes still cleanly applied.
- * <p>
- * One benefit of this approach is that we can build changes entirely on an
- * empty {@link RawContact}, which then becomes an insert {@link RawContacts} case.
- * <p>
- * When applying modifications over an {@link RawContact}, we try finding the
- * original {@link Data#_ID} rows where the modifications took place. If those
- * rows are missing from the new {@link RawContact}, we know the original data must
- * be deleted, but to preserve the user modifications we treat as an insert.
- */
-public class RawContactDelta implements Parcelable {
- // TODO: optimize by using contentvalues pool, since we allocate so many of them
-
- private static final String TAG = "EntityDelta";
- private static final boolean LOGV = false;
-
- /**
- * Direct values from {@link Entity#getEntityValues()}.
- */
- private ValuesDelta mValues;
-
- /**
- * URI used for contacts queries, by default it is set to query raw contacts.
- * It can be set to query the profile's raw contact(s).
- */
- private Uri mContactsQueryUri = RawContacts.CONTENT_URI;
-
- /**
- * Internal map of children values from {@link Entity#getSubValues()}, which
- * we store here sorted into {@link Data#MIMETYPE} bins.
- */
- private final HashMap<String, ArrayList<ValuesDelta>> mEntries = Maps.newHashMap();
-
- public RawContactDelta() {
- }
-
- public RawContactDelta(ValuesDelta values) {
- mValues = values;
- }
-
- /**
- * Build an {@link RawContactDelta} using the given {@link RawContact} as a
- * starting point; the "before" snapshot.
- */
- public static RawContactDelta fromBefore(RawContact before) {
- final RawContactDelta rawContactDelta = new RawContactDelta();
- rawContactDelta.mValues = ValuesDelta.fromBefore(before.getValues());
- rawContactDelta.mValues.setIdColumn(RawContacts._ID);
- for (final ContentValues values : before.getContentValues()) {
- rawContactDelta.addEntry(ValuesDelta.fromBefore(values));
- }
- return rawContactDelta;
- }
-
- /**
- * Merge the "after" values from the given {@link RawContactDelta} onto the
- * "before" state represented by this {@link RawContactDelta}, discarding any
- * existing "after" states. This is typically used when re-parenting changes
- * onto an updated {@link Entity}.
- */
- public static RawContactDelta mergeAfter(RawContactDelta local, RawContactDelta remote) {
- // Bail early if trying to merge delete with missing local
- final ValuesDelta remoteValues = remote.mValues;
- if (local == null && (remoteValues.isDelete() || remoteValues.isTransient())) return null;
-
- // Create local version if none exists yet
- if (local == null) local = new RawContactDelta();
-
- if (LOGV) {
- final Long localVersion = (local.mValues == null) ? null : local.mValues
- .getAsLong(RawContacts.VERSION);
- final Long remoteVersion = remote.mValues.getAsLong(RawContacts.VERSION);
- Log.d(TAG, "Re-parenting from original version " + remoteVersion + " to "
- + localVersion);
- }
-
- // Create values if needed, and merge "after" changes
- local.mValues = ValuesDelta.mergeAfter(local.mValues, remote.mValues);
-
- // Find matching local entry for each remote values, or create
- for (ArrayList<ValuesDelta> mimeEntries : remote.mEntries.values()) {
- for (ValuesDelta remoteEntry : mimeEntries) {
- final Long childId = remoteEntry.getId();
-
- // Find or create local match and merge
- final ValuesDelta localEntry = local.getEntry(childId);
- final ValuesDelta merged = ValuesDelta.mergeAfter(localEntry, remoteEntry);
-
- if (localEntry == null && merged != null) {
- // No local entry before, so insert
- local.addEntry(merged);
- }
- }
- }
-
- return local;
- }
-
- public ValuesDelta getValues() {
- return mValues;
- }
-
- public boolean isContactInsert() {
- return mValues.isInsert();
- }
-
- /**
- * Get the {@link ValuesDelta} child marked as {@link Data#IS_PRIMARY},
- * which may return null when no entry exists.
- */
- public ValuesDelta getPrimaryEntry(String mimeType) {
- final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType, false);
- if (mimeEntries == null) return null;
-
- for (ValuesDelta entry : mimeEntries) {
- if (entry.isPrimary()) {
- return entry;
- }
- }
-
- // When no direct primary, return something
- return mimeEntries.size() > 0 ? mimeEntries.get(0) : null;
- }
-
- /**
- * calls {@link #getSuperPrimaryEntry(String, boolean)} with true
- * @see #getSuperPrimaryEntry(String, boolean)
- */
- public ValuesDelta getSuperPrimaryEntry(String mimeType) {
- return getSuperPrimaryEntry(mimeType, true);
- }
-
- /**
- * Returns the super-primary entry for the given mime type
- * @param forceSelection if true, will try to return some value even if a super-primary
- * doesn't exist (may be a primary, or just a random item
- * @return
- */
- @NeededForTesting
- public ValuesDelta getSuperPrimaryEntry(String mimeType, boolean forceSelection) {
- final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType, false);
- if (mimeEntries == null) return null;
-
- ValuesDelta primary = null;
- for (ValuesDelta entry : mimeEntries) {
- if (entry.isSuperPrimary()) {
- return entry;
- } else if (entry.isPrimary()) {
- primary = entry;
- }
- }
-
- if (!forceSelection) {
- return null;
- }
-
- // When no direct super primary, return something
- if (primary != null) {
- return primary;
- }
- return mimeEntries.size() > 0 ? mimeEntries.get(0) : null;
- }
-
- /**
- * Return the AccountType that this raw-contact belongs to.
- */
- public AccountType getRawContactAccountType(Context context) {
- ContentValues entityValues = getValues().getCompleteValues();
- String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
- String dataSet = entityValues.getAsString(RawContacts.DATA_SET);
- return AccountTypeManager.getInstance(context).getAccountType(type, dataSet);
- }
-
- public Long getRawContactId() {
- return getValues().getAsLong(RawContacts._ID);
- }
-
- public String getAccountName() {
- return getValues().getAsString(RawContacts.ACCOUNT_NAME);
- }
-
- public String getAccountType() {
- return getValues().getAsString(RawContacts.ACCOUNT_TYPE);
- }
-
- public String getDataSet() {
- return getValues().getAsString(RawContacts.DATA_SET);
- }
-
- public AccountType getAccountType(AccountTypeManager manager) {
- return manager.getAccountType(getAccountType(), getDataSet());
- }
-
- public boolean isVisible() {
- return getValues().isVisible();
- }
-
- /**
- * Return the list of child {@link ValuesDelta} from our optimized map,
- * creating the list if requested.
- */
- private ArrayList<ValuesDelta> getMimeEntries(String mimeType, boolean lazyCreate) {
- ArrayList<ValuesDelta> mimeEntries = mEntries.get(mimeType);
- if (mimeEntries == null && lazyCreate) {
- mimeEntries = Lists.newArrayList();
- mEntries.put(mimeType, mimeEntries);
- }
- return mimeEntries;
- }
-
- public ArrayList<ValuesDelta> getMimeEntries(String mimeType) {
- return getMimeEntries(mimeType, false);
- }
-
- public int getMimeEntriesCount(String mimeType, boolean onlyVisible) {
- final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType);
- if (mimeEntries == null) return 0;
-
- int count = 0;
- for (ValuesDelta child : mimeEntries) {
- // Skip deleted items when requesting only visible
- if (onlyVisible && !child.isVisible()) continue;
- count++;
- }
- return count;
- }
-
- public boolean hasMimeEntries(String mimeType) {
- return mEntries.containsKey(mimeType);
- }
-
- public ValuesDelta addEntry(ValuesDelta entry) {
- final String mimeType = entry.getMimetype();
- getMimeEntries(mimeType, true).add(entry);
- return entry;
- }
-
- public ArrayList<ContentValues> getContentValues() {
- ArrayList<ContentValues> values = Lists.newArrayList();
- for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
- for (ValuesDelta entry : mimeEntries) {
- if (!entry.isDelete()) {
- values.add(entry.getCompleteValues());
- }
- }
- }
- return values;
- }
-
- /**
- * Find entry with the given {@link BaseColumns#_ID} value.
- */
- public ValuesDelta getEntry(Long childId) {
- if (childId == null) {
- // Requesting an "insert" entry, which has no "before"
- return null;
- }
-
- // Search all children for requested entry
- for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
- for (ValuesDelta entry : mimeEntries) {
- if (childId.equals(entry.getId())) {
- return entry;
- }
- }
- }
- return null;
- }
-
- /**
- * Return the total number of {@link ValuesDelta} contained.
- */
- public int getEntryCount(boolean onlyVisible) {
- int count = 0;
- for (String mimeType : mEntries.keySet()) {
- count += getMimeEntriesCount(mimeType, onlyVisible);
- }
- return count;
- }
-
- @Override
- public boolean equals(Object object) {
- if (object instanceof RawContactDelta) {
- final RawContactDelta other = (RawContactDelta)object;
-
- // Equality failed if parent values different
- if (!other.mValues.equals(mValues)) return false;
-
- for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
- for (ValuesDelta child : mimeEntries) {
- // Equality failed if any children unmatched
- if (!other.containsEntry(child)) return false;
- }
- }
-
- // Passed all tests, so equal
- return true;
- }
- return false;
- }
-
- private boolean containsEntry(ValuesDelta entry) {
- for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
- for (ValuesDelta child : mimeEntries) {
- // Contained if we find any child that matches
- if (child.equals(entry)) return true;
- }
- }
- return false;
- }
-
- /**
- * Mark this entire object deleted, including any {@link ValuesDelta}.
- */
- public void markDeleted() {
- this.mValues.markDeleted();
- for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
- for (ValuesDelta child : mimeEntries) {
- child.markDeleted();
- }
- }
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("\n(");
- builder.append("Uri=");
- builder.append(mContactsQueryUri);
- builder.append(", Values=");
- builder.append(mValues != null ? mValues.toString() : "null");
- builder.append(", Entries={");
- for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
- for (ValuesDelta child : mimeEntries) {
- builder.append("\n\t");
- child.toString(builder);
- }
- }
- builder.append("\n})\n");
- return builder.toString();
- }
-
- /**
- * Consider building the given {@link ContentProviderOperation.Builder} and
- * appending it to the given list, which only happens if builder is valid.
- */
- private void possibleAdd(ArrayList<ContentProviderOperation> diff,
- ContentProviderOperation.Builder builder) {
- if (builder != null) {
- diff.add(builder.build());
- }
- }
-
- /**
- * Build a list of {@link ContentProviderOperation} that will assert any
- * "before" state hasn't changed. This is maintained separately so that all
- * asserts can take place before any updates occur.
- */
- public void buildAssert(ArrayList<ContentProviderOperation> buildInto) {
- final boolean isContactInsert = mValues.isInsert();
- if (!isContactInsert) {
- // Assert version is consistent while persisting changes
- final Long beforeId = mValues.getId();
- final Long beforeVersion = mValues.getAsLong(RawContacts.VERSION);
- if (beforeId == null || beforeVersion == null) return;
-
- final ContentProviderOperation.Builder builder = ContentProviderOperation
- .newAssertQuery(mContactsQueryUri);
- builder.withSelection(RawContacts._ID + "=" + beforeId, null);
- builder.withValue(RawContacts.VERSION, beforeVersion);
- buildInto.add(builder.build());
- }
- }
-
- /**
- * Build a list of {@link ContentProviderOperation} that will transform the
- * current "before" {@link Entity} state into the modified state which this
- * {@link RawContactDelta} represents.
- */
- public void buildDiff(ArrayList<ContentProviderOperation> buildInto) {
- final int firstIndex = buildInto.size();
-
- final boolean isContactInsert = mValues.isInsert();
- final boolean isContactDelete = mValues.isDelete();
- final boolean isContactUpdate = !isContactInsert && !isContactDelete;
-
- final Long beforeId = mValues.getId();
-
- Builder builder;
-
- if (isContactInsert) {
- // TODO: for now simply disabling aggregation when a new contact is
- // created on the phone. In the future, will show aggregation suggestions
- // after saving the contact.
- mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
- }
-
- // Build possible operation at Contact level
- builder = mValues.buildDiff(mContactsQueryUri);
- possibleAdd(buildInto, builder);
-
- // Build operations for all children
- for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
- for (ValuesDelta child : mimeEntries) {
- // Ignore children if parent was deleted
- if (isContactDelete) continue;
-
- // Use the profile data URI if the contact is the profile.
- if (mContactsQueryUri.equals(Profile.CONTENT_RAW_CONTACTS_URI)) {
- builder = child.buildDiff(Uri.withAppendedPath(Profile.CONTENT_URI,
- RawContacts.Data.CONTENT_DIRECTORY));
- } else {
- builder = child.buildDiff(Data.CONTENT_URI);
- }
-
- if (child.isInsert()) {
- if (isContactInsert) {
- // Parent is brand new insert, so back-reference _id
- builder.withValueBackReference(Data.RAW_CONTACT_ID, firstIndex);
- } else {
- // Inserting under existing, so fill with known _id
- builder.withValue(Data.RAW_CONTACT_ID, beforeId);
- }
- } else if (isContactInsert && builder != null) {
- // Child must be insert when Contact insert
- throw new IllegalArgumentException("When parent insert, child must be also");
- }
- possibleAdd(buildInto, builder);
- }
- }
-
- final boolean addedOperations = buildInto.size() > firstIndex;
- if (addedOperations && isContactUpdate) {
- // Suspend aggregation while persisting updates
- builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_SUSPENDED);
- buildInto.add(firstIndex, builder.build());
-
- // Restore aggregation mode as last operation
- builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_DEFAULT);
- buildInto.add(builder.build());
- } else if (isContactInsert) {
- // Restore aggregation mode as last operation
- builder = ContentProviderOperation.newUpdate(mContactsQueryUri);
- builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT);
- builder.withSelection(RawContacts._ID + "=?", new String[1]);
- builder.withSelectionBackReference(0, firstIndex);
- buildInto.add(builder.build());
- }
- }
-
- /**
- * Build a {@link ContentProviderOperation} that changes
- * {@link RawContacts#AGGREGATION_MODE} to the given value.
- */
- protected Builder buildSetAggregationMode(Long beforeId, int mode) {
- Builder builder = ContentProviderOperation.newUpdate(mContactsQueryUri);
- builder.withValue(RawContacts.AGGREGATION_MODE, mode);
- builder.withSelection(RawContacts._ID + "=" + beforeId, null);
- return builder;
- }
-
- /** {@inheritDoc} */
- public int describeContents() {
- // Nothing special about this parcel
- return 0;
- }
-
- /** {@inheritDoc} */
- public void writeToParcel(Parcel dest, int flags) {
- final int size = this.getEntryCount(false);
- dest.writeInt(size);
- dest.writeParcelable(mValues, flags);
- dest.writeParcelable(mContactsQueryUri, flags);
- for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
- for (ValuesDelta child : mimeEntries) {
- dest.writeParcelable(child, flags);
- }
- }
- }
-
- public void readFromParcel(Parcel source) {
- final ClassLoader loader = getClass().getClassLoader();
- final int size = source.readInt();
- mValues = source.<ValuesDelta> readParcelable(loader);
- mContactsQueryUri = source.<Uri> readParcelable(loader);
- for (int i = 0; i < size; i++) {
- final ValuesDelta child = source.<ValuesDelta> readParcelable(loader);
- this.addEntry(child);
- }
- }
-
- /**
- * Used to set the query URI to the profile URI to store profiles.
- */
- public void setProfileQueryUri() {
- mContactsQueryUri = Profile.CONTENT_RAW_CONTACTS_URI;
- }
-
- public static final Parcelable.Creator<RawContactDelta> CREATOR =
- new Parcelable.Creator<RawContactDelta>() {
- public RawContactDelta createFromParcel(Parcel in) {
- final RawContactDelta state = new RawContactDelta();
- state.readFromParcel(in);
- return state;
- }
-
- public RawContactDelta[] newArray(int size) {
- return new RawContactDelta[size];
- }
- };
-
-}
diff --git a/src/com/android/contacts/model/RawContactDeltaList.java b/src/com/android/contacts/model/RawContactDeltaList.java
deleted file mode 100644
index 1a9eb71..0000000
--- a/src/com/android/contacts/model/RawContactDeltaList.java
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright (C) 2009 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.model;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderOperation.Builder;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Entity;
-import android.content.EntityIterator;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.provider.ContactsContract.AggregationExceptions;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
-
-import com.android.contacts.common.model.ValuesDelta;
-import com.google.common.collect.Lists;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-
-/**
- * Container for multiple {@link RawContactDelta} objects, usually when editing
- * together as an entire aggregate. Provides convenience methods for parceling
- * and applying another {@link RawContactDeltaList} over it.
- */
-public class RawContactDeltaList extends ArrayList<RawContactDelta> implements Parcelable {
- private static final String TAG = RawContactDeltaList.class.getSimpleName();
- private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
-
- private boolean mSplitRawContacts;
- private long[] mJoinWithRawContactIds;
-
- public RawContactDeltaList() {
- }
-
- /**
- * Create an {@link RawContactDeltaList} based on {@link Contacts} specified by the
- * given query parameters. This closes the {@link EntityIterator} when
- * finished, so it doesn't subscribe to updates.
- */
- public static RawContactDeltaList fromQuery(Uri entityUri, ContentResolver resolver,
- String selection, String[] selectionArgs, String sortOrder) {
- final EntityIterator iterator = RawContacts.newEntityIterator(
- resolver.query(entityUri, null, selection, selectionArgs, sortOrder));
- try {
- return fromIterator(iterator);
- } finally {
- iterator.close();
- }
- }
-
- /**
- * Create an {@link RawContactDeltaList} that contains the entities of the Iterator as before
- * values. This function can be passed an iterator of Entity objects or an iterator of
- * RawContact objects.
- */
- public static RawContactDeltaList fromIterator(Iterator<?> iterator) {
- final RawContactDeltaList state = new RawContactDeltaList();
- state.addAll(iterator);
- return state;
- }
-
- public void addAll(Iterator<?> iterator) {
- // Perform background query to pull contact details
- while (iterator.hasNext()) {
- // Read all contacts into local deltas to prepare for edits
- Object nextObject = iterator.next();
- final RawContact before = nextObject instanceof Entity
- ? RawContact.createFrom((Entity) nextObject)
- : (RawContact) nextObject;
- final RawContactDelta rawContactDelta = RawContactDelta.fromBefore(before);
- add(rawContactDelta);
- }
- }
-
- /**
- * Merge the "after" values from the given {@link RawContactDeltaList}, discarding any
- * previous "after" states. This is typically used when re-parenting user
- * edits onto an updated {@link RawContactDeltaList}.
- */
- public static RawContactDeltaList mergeAfter(RawContactDeltaList local,
- RawContactDeltaList remote) {
- if (local == null) local = new RawContactDeltaList();
-
- // For each entity in the remote set, try matching over existing
- for (RawContactDelta remoteEntity : remote) {
- final Long rawContactId = remoteEntity.getValues().getId();
-
- // Find or create local match and merge
- final RawContactDelta localEntity = local.getByRawContactId(rawContactId);
- final RawContactDelta merged = RawContactDelta.mergeAfter(localEntity, remoteEntity);
-
- if (localEntity == null && merged != null) {
- // No local entry before, so insert
- local.add(merged);
- }
- }
-
- return local;
- }
-
- /**
- * Build a list of {@link ContentProviderOperation} that will transform all
- * the "before" {@link Entity} states into the modified state which all
- * {@link RawContactDelta} objects represent. This method specifically creates
- * any {@link AggregationExceptions} rules needed to groups edits together.
- */
- public ArrayList<ContentProviderOperation> buildDiff() {
- if (VERBOSE_LOGGING) {
- Log.v(TAG, "buildDiff: list=" + toString());
- }
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
-
- final long rawContactId = this.findRawContactId();
- int firstInsertRow = -1;
-
- // First pass enforces versions remain consistent
- for (RawContactDelta delta : this) {
- delta.buildAssert(diff);
- }
-
- final int assertMark = diff.size();
- int backRefs[] = new int[size()];
-
- int rawContactIndex = 0;
-
- // Second pass builds actual operations
- for (RawContactDelta delta : this) {
- final int firstBatch = diff.size();
- final boolean isInsert = delta.isContactInsert();
- backRefs[rawContactIndex++] = isInsert ? firstBatch : -1;
-
- delta.buildDiff(diff);
-
- // If the user chose to join with some other existing raw contact(s) at save time,
- // add aggregation exceptions for all those raw contacts.
- if (mJoinWithRawContactIds != null) {
- for (Long joinedRawContactId : mJoinWithRawContactIds) {
- final Builder builder = beginKeepTogether();
- builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, joinedRawContactId);
- if (rawContactId != -1) {
- builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId);
- } else {
- builder.withValueBackReference(
- AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
- }
- diff.add(builder.build());
- }
- }
-
- // Only create rules for inserts
- if (!isInsert) continue;
-
- // If we are going to split all contacts, there is no point in first combining them
- if (mSplitRawContacts) continue;
-
- if (rawContactId != -1) {
- // Has existing contact, so bind to it strongly
- final Builder builder = beginKeepTogether();
- builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId);
- builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
- diff.add(builder.build());
-
- } else if (firstInsertRow == -1) {
- // First insert case, so record row
- firstInsertRow = firstBatch;
-
- } else {
- // Additional insert case, so point at first insert
- final Builder builder = beginKeepTogether();
- builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1,
- firstInsertRow);
- builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, firstBatch);
- diff.add(builder.build());
- }
- }
-
- if (mSplitRawContacts) {
- buildSplitContactDiff(diff, backRefs);
- }
-
- // No real changes if only left with asserts
- if (diff.size() == assertMark) {
- diff.clear();
- }
- if (VERBOSE_LOGGING) {
- Log.v(TAG, "buildDiff: ops=" + diffToString(diff));
- }
- return diff;
- }
-
- private static String diffToString(ArrayList<ContentProviderOperation> ops) {
- StringBuilder sb = new StringBuilder();
- sb.append("[\n");
- for (ContentProviderOperation op : ops) {
- sb.append(op.toString());
- sb.append(",\n");
- }
- sb.append("]\n");
- return sb.toString();
- }
-
- /**
- * Start building a {@link ContentProviderOperation} that will keep two
- * {@link RawContacts} together.
- */
- protected Builder beginKeepTogether() {
- final Builder builder = ContentProviderOperation
- .newUpdate(AggregationExceptions.CONTENT_URI);
- builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
- return builder;
- }
-
- /**
- * Builds {@link AggregationExceptions} to split all constituent raw contacts into
- * separate contacts.
- */
- private void buildSplitContactDiff(final ArrayList<ContentProviderOperation> diff,
- int[] backRefs) {
- int count = size();
- for (int i = 0; i < count; i++) {
- for (int j = 0; j < count; j++) {
- if (i != j) {
- buildSplitContactDiff(diff, i, j, backRefs);
- }
- }
- }
- }
-
- /**
- * Construct a {@link AggregationExceptions#TYPE_KEEP_SEPARATE}.
- */
- private void buildSplitContactDiff(ArrayList<ContentProviderOperation> diff, int index1,
- int index2, int[] backRefs) {
- Builder builder =
- ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
- builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_SEPARATE);
-
- Long rawContactId1 = get(index1).getValues().getAsLong(RawContacts._ID);
- int backRef1 = backRefs[index1];
- if (rawContactId1 != null && rawContactId1 >= 0) {
- builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
- } else if (backRef1 >= 0) {
- builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, backRef1);
- } else {
- return;
- }
-
- Long rawContactId2 = get(index2).getValues().getAsLong(RawContacts._ID);
- int backRef2 = backRefs[index2];
- if (rawContactId2 != null && rawContactId2 >= 0) {
- builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
- } else if (backRef2 >= 0) {
- builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, backRef2);
- } else {
- return;
- }
-
- diff.add(builder.build());
- }
-
- /**
- * Search all contained {@link RawContactDelta} for the first one with an
- * existing {@link RawContacts#_ID} value. Usually used when creating
- * {@link AggregationExceptions} during an update.
- */
- public long findRawContactId() {
- for (RawContactDelta delta : this) {
- final Long rawContactId = delta.getValues().getAsLong(RawContacts._ID);
- if (rawContactId != null && rawContactId >= 0) {
- return rawContactId;
- }
- }
- return -1;
- }
-
- /**
- * Find {@link RawContacts#_ID} of the requested {@link RawContactDelta}.
- */
- public Long getRawContactId(int index) {
- if (index >= 0 && index < this.size()) {
- final RawContactDelta delta = this.get(index);
- final ValuesDelta values = delta.getValues();
- if (values.isVisible()) {
- return values.getAsLong(RawContacts._ID);
- }
- }
- return null;
- }
-
- /**
- * Find the raw-contact (an {@link RawContactDelta}) with the specified ID.
- */
- public RawContactDelta getByRawContactId(Long rawContactId) {
- final int index = this.indexOfRawContactId(rawContactId);
- return (index == -1) ? null : this.get(index);
- }
-
- /**
- * Find index of given {@link RawContacts#_ID} when present.
- */
- public int indexOfRawContactId(Long rawContactId) {
- if (rawContactId == null) return -1;
- final int size = this.size();
- for (int i = 0; i < size; i++) {
- final Long currentId = getRawContactId(i);
- if (rawContactId.equals(currentId)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Return the index of the first RawContactDelta corresponding to a writable raw-contact, or -1.
- * */
- public int indexOfFirstWritableRawContact(Context context) {
- // Find the first writable entity.
- int entityIndex = 0;
- for (RawContactDelta delta : this) {
- if (delta.getRawContactAccountType(context).areContactsWritable()) return entityIndex;
- entityIndex++;
- }
- return -1;
- }
-
- /** Return the first RawContactDelta corresponding to a writable raw-contact, or null. */
- public RawContactDelta getFirstWritableRawContact(Context context) {
- final int index = indexOfFirstWritableRawContact(context);
- return (index == -1) ? null : get(index);
- }
-
- public ValuesDelta getSuperPrimaryEntry(final String mimeType) {
- ValuesDelta primary = null;
- ValuesDelta randomEntry = null;
- for (RawContactDelta delta : this) {
- final ArrayList<ValuesDelta> mimeEntries = delta.getMimeEntries(mimeType);
- if (mimeEntries == null) return null;
-
- for (ValuesDelta entry : mimeEntries) {
- if (entry.isSuperPrimary()) {
- return entry;
- } else if (primary == null && entry.isPrimary()) {
- primary = entry;
- } else if (randomEntry == null) {
- randomEntry = entry;
- }
- }
- }
- // When no direct super primary, return something
- if (primary != null) {
- return primary;
- }
- return randomEntry;
- }
-
- /**
- * Sets a flag that will split ("explode") the raw_contacts into seperate contacts
- */
- public void markRawContactsForSplitting() {
- mSplitRawContacts = true;
- }
-
- public boolean isMarkedForSplitting() {
- return mSplitRawContacts;
- }
-
- public void setJoinWithRawContacts(long[] rawContactIds) {
- mJoinWithRawContactIds = rawContactIds;
- }
-
- public boolean isMarkedForJoining() {
- return mJoinWithRawContactIds != null && mJoinWithRawContactIds.length > 0;
- }
-
- /** {@inheritDoc} */
- @Override
- public int describeContents() {
- // Nothing special about this parcel
- return 0;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- final int size = this.size();
- dest.writeInt(size);
- for (RawContactDelta delta : this) {
- dest.writeParcelable(delta, flags);
- }
- dest.writeLongArray(mJoinWithRawContactIds);
- dest.writeInt(mSplitRawContacts ? 1 : 0);
- }
-
- @SuppressWarnings("unchecked")
- public void readFromParcel(Parcel source) {
- final ClassLoader loader = getClass().getClassLoader();
- final int size = source.readInt();
- for (int i = 0; i < size; i++) {
- this.add(source.<RawContactDelta> readParcelable(loader));
- }
- mJoinWithRawContactIds = source.createLongArray();
- mSplitRawContacts = source.readInt() != 0;
- }
-
- public static final Parcelable.Creator<RawContactDeltaList> CREATOR =
- new Parcelable.Creator<RawContactDeltaList>() {
- @Override
- public RawContactDeltaList createFromParcel(Parcel in) {
- final RawContactDeltaList state = new RawContactDeltaList();
- state.readFromParcel(in);
- return state;
- }
-
- @Override
- public RawContactDeltaList[] newArray(int size) {
- return new RawContactDeltaList[size];
- }
- };
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("(");
- sb.append("Split=");
- sb.append(mSplitRawContacts);
- sb.append(", Join=[");
- sb.append(Arrays.toString(mJoinWithRawContactIds));
- sb.append("], Values=");
- sb.append(super.toString());
- sb.append(")");
- return sb.toString();
- }
-}
diff --git a/src/com/android/contacts/model/RawContactModifier.java b/src/com/android/contacts/model/RawContactModifier.java
deleted file mode 100644
index 5f8b410..0000000
--- a/src/com/android/contacts/model/RawContactModifier.java
+++ /dev/null
@@ -1,1429 +0,0 @@
-/*
- * Copyright (C) 2009 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.model;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.SipAddress;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.Intents;
-import android.provider.ContactsContract.Intents.Insert;
-import android.provider.ContactsContract.RawContacts;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-
-import com.android.contacts.ContactsUtils;
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.common.util.CommonDateUtils;
-import com.android.contacts.editor.EventFieldEditorView;
-import com.android.contacts.editor.PhoneticNameEditorView;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountType.EditField;
-import com.android.contacts.common.model.account.AccountType.EditType;
-import com.android.contacts.common.model.account.AccountType.EventEditType;
-import com.android.contacts.common.model.account.GoogleAccountType;
-import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.model.dataitem.PhoneDataItem;
-import com.android.contacts.model.dataitem.StructuredNameDataItem;
-import com.android.contacts.util.DateUtils;
-import com.android.contacts.util.NameConverter;
-
-import java.text.ParsePosition;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-
-/**
- * Helper methods for modifying an {@link RawContactDelta}, such as inserting
- * new rows, or enforcing {@link AccountType}.
- */
-public class RawContactModifier {
- private static final String TAG = RawContactModifier.class.getSimpleName();
-
- /** Set to true in order to view logs on entity operations */
- private static final boolean DEBUG = false;
-
- /**
- * For the given {@link RawContactDelta}, determine if the given
- * {@link DataKind} could be inserted under specific
- * {@link AccountType}.
- */
- public static boolean canInsert(RawContactDelta state, DataKind kind) {
- // Insert possible when have valid types and under overall maximum
- final int visibleCount = state.getMimeEntriesCount(kind.mimeType, true);
- final boolean validTypes = hasValidTypes(state, kind);
- final boolean validOverall = (kind.typeOverallMax == -1)
- || (visibleCount < kind.typeOverallMax);
- return (validTypes && validOverall);
- }
-
- public static boolean hasValidTypes(RawContactDelta state, DataKind kind) {
- if (RawContactModifier.hasEditTypes(kind)) {
- return (getValidTypes(state, kind).size() > 0);
- } else {
- return true;
- }
- }
-
- /**
- * Ensure that at least one of the given {@link DataKind} exists in the
- * given {@link RawContactDelta} state, and try creating one if none exist.
- * @return The child (either newly created or the first existing one), or null if the
- * account doesn't support this {@link DataKind}.
- */
- public static ValuesDelta ensureKindExists(
- RawContactDelta state, AccountType accountType, String mimeType) {
- final DataKind kind = accountType.getKindForMimetype(mimeType);
- final boolean hasChild = state.getMimeEntriesCount(mimeType, true) > 0;
-
- if (kind != null) {
- if (hasChild) {
- // Return the first entry.
- return state.getMimeEntries(mimeType).get(0);
- } else {
- // Create child when none exists and valid kind
- final ValuesDelta child = insertChild(state, kind);
- if (kind.mimeType.equals(Photo.CONTENT_ITEM_TYPE)) {
- child.setFromTemplate(true);
- }
- return child;
- }
- }
- return null;
- }
-
- /**
- * For the given {@link RawContactDelta} and {@link DataKind}, return the
- * list possible {@link EditType} options available based on
- * {@link AccountType}.
- */
- public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind) {
- return getValidTypes(state, kind, null, true, null);
- }
-
- /**
- * For the given {@link RawContactDelta} and {@link DataKind}, return the
- * list possible {@link EditType} options available based on
- * {@link AccountType}.
- *
- * @param forceInclude Always include this {@link EditType} in the returned
- * list, even when an otherwise-invalid choice. This is useful
- * when showing a dialog that includes the current type.
- */
- public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind,
- EditType forceInclude) {
- return getValidTypes(state, kind, forceInclude, true, null);
- }
-
- /**
- * For the given {@link RawContactDelta} and {@link DataKind}, return the
- * list possible {@link EditType} options available based on
- * {@link AccountType}.
- *
- * @param forceInclude Always include this {@link EditType} in the returned
- * list, even when an otherwise-invalid choice. This is useful
- * when showing a dialog that includes the current type.
- * @param includeSecondary If true, include any valid types marked as
- * {@link EditType#secondary}.
- * @param typeCount When provided, will be used for the frequency count of
- * each {@link EditType}, otherwise built using
- * {@link #getTypeFrequencies(RawContactDelta, DataKind)}.
- */
- private static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind,
- EditType forceInclude, boolean includeSecondary, SparseIntArray typeCount) {
- final ArrayList<EditType> validTypes = new ArrayList<EditType>();
-
- // Bail early if no types provided
- if (!hasEditTypes(kind)) return validTypes;
-
- if (typeCount == null) {
- // Build frequency counts if not provided
- typeCount = getTypeFrequencies(state, kind);
- }
-
- // Build list of valid types
- final int overallCount = typeCount.get(FREQUENCY_TOTAL);
- for (EditType type : kind.typeList) {
- final boolean validOverall = (kind.typeOverallMax == -1 ? true
- : overallCount < kind.typeOverallMax);
- final boolean validSpecific = (type.specificMax == -1 ? true : typeCount
- .get(type.rawValue) < type.specificMax);
- final boolean validSecondary = (includeSecondary ? true : !type.secondary);
- final boolean forcedInclude = type.equals(forceInclude);
- if (forcedInclude || (validOverall && validSpecific && validSecondary)) {
- // Type is valid when no limit, under limit, or forced include
- validTypes.add(type);
- }
- }
-
- return validTypes;
- }
-
- private static final int FREQUENCY_TOTAL = Integer.MIN_VALUE;
-
- /**
- * Count up the frequency that each {@link EditType} appears in the given
- * {@link RawContactDelta}. The returned {@link SparseIntArray} maps from
- * {@link EditType#rawValue} to counts, with the total overall count stored
- * as {@link #FREQUENCY_TOTAL}.
- */
- private static SparseIntArray getTypeFrequencies(RawContactDelta state, DataKind kind) {
- final SparseIntArray typeCount = new SparseIntArray();
-
- // Find all entries for this kind, bailing early if none found
- final List<ValuesDelta> mimeEntries = state.getMimeEntries(kind.mimeType);
- if (mimeEntries == null) return typeCount;
-
- int totalCount = 0;
- for (ValuesDelta entry : mimeEntries) {
- // Only count visible entries
- if (!entry.isVisible()) continue;
- totalCount++;
-
- final EditType type = getCurrentType(entry, kind);
- if (type != null) {
- final int count = typeCount.get(type.rawValue);
- typeCount.put(type.rawValue, count + 1);
- }
- }
- typeCount.put(FREQUENCY_TOTAL, totalCount);
- return typeCount;
- }
-
- /**
- * Check if the given {@link DataKind} has multiple types that should be
- * displayed for users to pick.
- */
- public static boolean hasEditTypes(DataKind kind) {
- return kind.typeList != null && kind.typeList.size() > 0;
- }
-
- /**
- * Find the {@link EditType} that describes the given
- * {@link ValuesDelta} row, assuming the given {@link DataKind} dictates
- * the possible types.
- */
- public static EditType getCurrentType(ValuesDelta entry, DataKind kind) {
- final Long rawValue = entry.getAsLong(kind.typeColumn);
- if (rawValue == null) return null;
- return getType(kind, rawValue.intValue());
- }
-
- /**
- * Find the {@link EditType} that describes the given {@link ContentValues} row,
- * assuming the given {@link DataKind} dictates the possible types.
- */
- public static EditType getCurrentType(ContentValues entry, DataKind kind) {
- if (kind.typeColumn == null) return null;
- final Integer rawValue = entry.getAsInteger(kind.typeColumn);
- if (rawValue == null) return null;
- return getType(kind, rawValue);
- }
-
- /**
- * Find the {@link EditType} that describes the given {@link Cursor} row,
- * assuming the given {@link DataKind} dictates the possible types.
- */
- public static EditType getCurrentType(Cursor cursor, DataKind kind) {
- if (kind.typeColumn == null) return null;
- final int index = cursor.getColumnIndex(kind.typeColumn);
- if (index == -1) return null;
- final int rawValue = cursor.getInt(index);
- return getType(kind, rawValue);
- }
-
- /**
- * Find the {@link EditType} with the given {@link EditType#rawValue}.
- */
- public static EditType getType(DataKind kind, int rawValue) {
- for (EditType type : kind.typeList) {
- if (type.rawValue == rawValue) {
- return type;
- }
- }
- return null;
- }
-
- /**
- * Return the precedence for the the given {@link EditType#rawValue}, where
- * lower numbers are higher precedence.
- */
- public static int getTypePrecedence(DataKind kind, int rawValue) {
- for (int i = 0; i < kind.typeList.size(); i++) {
- final EditType type = kind.typeList.get(i);
- if (type.rawValue == rawValue) {
- return i;
- }
- }
- return Integer.MAX_VALUE;
- }
-
- /**
- * Find the best {@link EditType} for a potential insert. The "best" is the
- * first primary type that doesn't already exist. When all valid types
- * exist, we pick the last valid option.
- */
- public static EditType getBestValidType(RawContactDelta state, DataKind kind,
- boolean includeSecondary, int exactValue) {
- // Shortcut when no types
- if (kind.typeColumn == null) return null;
-
- // Find type counts and valid primary types, bail if none
- final SparseIntArray typeCount = getTypeFrequencies(state, kind);
- final ArrayList<EditType> validTypes = getValidTypes(state, kind, null, includeSecondary,
- typeCount);
- if (validTypes.size() == 0) return null;
-
- // Keep track of the last valid type
- final EditType lastType = validTypes.get(validTypes.size() - 1);
-
- // Remove any types that already exist
- Iterator<EditType> iterator = validTypes.iterator();
- while (iterator.hasNext()) {
- final EditType type = iterator.next();
- final int count = typeCount.get(type.rawValue);
-
- if (exactValue == type.rawValue) {
- // Found exact value match
- return type;
- }
-
- if (count > 0) {
- // Type already appears, so don't consider
- iterator.remove();
- }
- }
-
- // Use the best remaining, otherwise the last valid
- if (validTypes.size() > 0) {
- return validTypes.get(0);
- } else {
- return lastType;
- }
- }
-
- /**
- * Insert a new child of kind {@link DataKind} into the given
- * {@link RawContactDelta}. Tries using the best {@link EditType} found using
- * {@link #getBestValidType(RawContactDelta, DataKind, boolean, int)}.
- */
- public static ValuesDelta insertChild(RawContactDelta state, DataKind kind) {
- // First try finding a valid primary
- EditType bestType = getBestValidType(state, kind, false, Integer.MIN_VALUE);
- if (bestType == null) {
- // No valid primary found, so expand search to secondary
- bestType = getBestValidType(state, kind, true, Integer.MIN_VALUE);
- }
- return insertChild(state, kind, bestType);
- }
-
- /**
- * Insert a new child of kind {@link DataKind} into the given
- * {@link RawContactDelta}, marked with the given {@link EditType}.
- */
- public static ValuesDelta insertChild(RawContactDelta state, DataKind kind, EditType type) {
- // Bail early if invalid kind
- if (kind == null) return null;
- final ContentValues after = new ContentValues();
-
- // Our parent CONTACT_ID is provided later
- after.put(Data.MIMETYPE, kind.mimeType);
-
- // Fill-in with any requested default values
- if (kind.defaultValues != null) {
- after.putAll(kind.defaultValues);
- }
-
- if (kind.typeColumn != null && type != null) {
- // Set type, if provided
- after.put(kind.typeColumn, type.rawValue);
- }
-
- final ValuesDelta child = ValuesDelta.fromAfter(after);
- state.addEntry(child);
- return child;
- }
-
- /**
- * Processing to trim any empty {@link ValuesDelta} and {@link RawContactDelta}
- * from the given {@link RawContactDeltaList}, assuming the given {@link AccountTypeManager}
- * dictates the structure for various fields. This method ignores rows not
- * described by the {@link AccountType}.
- */
- public static void trimEmpty(RawContactDeltaList set, AccountTypeManager accountTypes) {
- for (RawContactDelta state : set) {
- ValuesDelta values = state.getValues();
- final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = values.getAsString(RawContacts.DATA_SET);
- final AccountType type = accountTypes.getAccountType(accountType, dataSet);
- trimEmpty(state, type);
- }
- }
-
- public static boolean hasChanges(RawContactDeltaList set, AccountTypeManager accountTypes) {
- if (set.isMarkedForSplitting() || set.isMarkedForJoining()) {
- return true;
- }
-
- for (RawContactDelta state : set) {
- ValuesDelta values = state.getValues();
- final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = values.getAsString(RawContacts.DATA_SET);
- final AccountType type = accountTypes.getAccountType(accountType, dataSet);
- if (hasChanges(state, type)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Processing to trim any empty {@link ValuesDelta} rows from the given
- * {@link RawContactDelta}, assuming the given {@link AccountType} dictates
- * the structure for various fields. This method ignores rows not described
- * by the {@link AccountType}.
- */
- public static void trimEmpty(RawContactDelta state, AccountType accountType) {
- boolean hasValues = false;
-
- // Walk through entries for each well-known kind
- for (DataKind kind : accountType.getSortedDataKinds()) {
- final String mimeType = kind.mimeType;
- final ArrayList<ValuesDelta> entries = state.getMimeEntries(mimeType);
- if (entries == null) continue;
-
- for (ValuesDelta entry : entries) {
- // Skip any values that haven't been touched
- final boolean touched = entry.isInsert() || entry.isUpdate();
- if (!touched) {
- hasValues = true;
- continue;
- }
-
- // Test and remove this row if empty and it isn't a photo from google
- final boolean isGoogleAccount = TextUtils.equals(GoogleAccountType.ACCOUNT_TYPE,
- state.getValues().getAsString(RawContacts.ACCOUNT_TYPE));
- final boolean isPhoto = TextUtils.equals(Photo.CONTENT_ITEM_TYPE, kind.mimeType);
- final boolean isGooglePhoto = isPhoto && isGoogleAccount;
-
- if (RawContactModifier.isEmpty(entry, kind) && !isGooglePhoto) {
- if (DEBUG) {
- Log.v(TAG, "Trimming: " + entry.toString());
- }
- entry.markDeleted();
- } else if (!entry.isFromTemplate()) {
- hasValues = true;
- }
- }
- }
- if (!hasValues) {
- // Trim overall entity if no children exist
- state.markDeleted();
- }
- }
-
- private static boolean hasChanges(RawContactDelta state, AccountType accountType) {
- for (DataKind kind : accountType.getSortedDataKinds()) {
- final String mimeType = kind.mimeType;
- final ArrayList<ValuesDelta> entries = state.getMimeEntries(mimeType);
- if (entries == null) continue;
-
- for (ValuesDelta entry : entries) {
- // An empty Insert must be ignored, because it won't save anything (an example
- // is an empty name that stays empty)
- final boolean isRealInsert = entry.isInsert() && !isEmpty(entry, kind);
- if (isRealInsert || entry.isUpdate() || entry.isDelete()) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Test if the given {@link ValuesDelta} would be considered "empty" in
- * terms of {@link DataKind#fieldList}.
- */
- public static boolean isEmpty(ValuesDelta values, DataKind kind) {
- if (Photo.CONTENT_ITEM_TYPE.equals(kind.mimeType)) {
- return values.isInsert() && values.getAsByteArray(Photo.PHOTO) == null;
- }
-
- // No defined fields mean this row is always empty
- if (kind.fieldList == null) return true;
-
- for (EditField field : kind.fieldList) {
- // If any field has values, we're not empty
- final String value = values.getAsString(field.column);
- if (ContactsUtils.isGraphic(value)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Compares corresponding fields in values1 and values2. Only the fields
- * declared by the DataKind are taken into consideration.
- */
- protected static boolean areEqual(ValuesDelta values1, ContentValues values2, DataKind kind) {
- if (kind.fieldList == null) return false;
-
- for (EditField field : kind.fieldList) {
- final String value1 = values1.getAsString(field.column);
- final String value2 = values2.getAsString(field.column);
- if (!TextUtils.equals(value1, value2)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Parse the given {@link Bundle} into the given {@link RawContactDelta} state,
- * assuming the extras defined through {@link Intents}.
- */
- public static void parseExtras(Context context, AccountType accountType, RawContactDelta state,
- Bundle extras) {
- if (extras == null || extras.size() == 0) {
- // Bail early if no useful data
- return;
- }
-
- parseStructuredNameExtra(context, accountType, state, extras);
- parseStructuredPostalExtra(accountType, state, extras);
-
- {
- // Phone
- final DataKind kind = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- parseExtras(state, kind, extras, Insert.PHONE_TYPE, Insert.PHONE, Phone.NUMBER);
- parseExtras(state, kind, extras, Insert.SECONDARY_PHONE_TYPE, Insert.SECONDARY_PHONE,
- Phone.NUMBER);
- parseExtras(state, kind, extras, Insert.TERTIARY_PHONE_TYPE, Insert.TERTIARY_PHONE,
- Phone.NUMBER);
- }
-
- {
- // Email
- final DataKind kind = accountType.getKindForMimetype(Email.CONTENT_ITEM_TYPE);
- parseExtras(state, kind, extras, Insert.EMAIL_TYPE, Insert.EMAIL, Email.DATA);
- parseExtras(state, kind, extras, Insert.SECONDARY_EMAIL_TYPE, Insert.SECONDARY_EMAIL,
- Email.DATA);
- parseExtras(state, kind, extras, Insert.TERTIARY_EMAIL_TYPE, Insert.TERTIARY_EMAIL,
- Email.DATA);
- }
-
- {
- // Im
- final DataKind kind = accountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
- fixupLegacyImType(extras);
- parseExtras(state, kind, extras, Insert.IM_PROTOCOL, Insert.IM_HANDLE, Im.DATA);
- }
-
- // Organization
- final boolean hasOrg = extras.containsKey(Insert.COMPANY)
- || extras.containsKey(Insert.JOB_TITLE);
- final DataKind kindOrg = accountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
- if (hasOrg && RawContactModifier.canInsert(state, kindOrg)) {
- final ValuesDelta child = RawContactModifier.insertChild(state, kindOrg);
-
- final String company = extras.getString(Insert.COMPANY);
- if (ContactsUtils.isGraphic(company)) {
- child.put(Organization.COMPANY, company);
- }
-
- final String title = extras.getString(Insert.JOB_TITLE);
- if (ContactsUtils.isGraphic(title)) {
- child.put(Organization.TITLE, title);
- }
- }
-
- // Notes
- final boolean hasNotes = extras.containsKey(Insert.NOTES);
- final DataKind kindNotes = accountType.getKindForMimetype(Note.CONTENT_ITEM_TYPE);
- if (hasNotes && RawContactModifier.canInsert(state, kindNotes)) {
- final ValuesDelta child = RawContactModifier.insertChild(state, kindNotes);
-
- final String notes = extras.getString(Insert.NOTES);
- if (ContactsUtils.isGraphic(notes)) {
- child.put(Note.NOTE, notes);
- }
- }
-
- // Arbitrary additional data
- ArrayList<ContentValues> values = extras.getParcelableArrayList(Insert.DATA);
- if (values != null) {
- parseValues(state, accountType, values);
- }
- }
-
- private static void parseStructuredNameExtra(
- Context context, AccountType accountType, RawContactDelta state, Bundle extras) {
- // StructuredName
- RawContactModifier.ensureKindExists(state, accountType, StructuredName.CONTENT_ITEM_TYPE);
- final ValuesDelta child = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
-
- final String name = extras.getString(Insert.NAME);
- if (ContactsUtils.isGraphic(name)) {
- final DataKind kind = accountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
- boolean supportsDisplayName = false;
- if (kind.fieldList != null) {
- for (EditField field : kind.fieldList) {
- if (StructuredName.DISPLAY_NAME.equals(field.column)) {
- supportsDisplayName = true;
- break;
- }
- }
- }
-
- if (supportsDisplayName) {
- child.put(StructuredName.DISPLAY_NAME, name);
- } else {
- Uri uri = ContactsContract.AUTHORITY_URI.buildUpon()
- .appendPath("complete_name")
- .appendQueryParameter(StructuredName.DISPLAY_NAME, name)
- .build();
- Cursor cursor = context.getContentResolver().query(uri,
- new String[]{
- StructuredName.PREFIX,
- StructuredName.GIVEN_NAME,
- StructuredName.MIDDLE_NAME,
- StructuredName.FAMILY_NAME,
- StructuredName.SUFFIX,
- }, null, null, null);
-
- try {
- if (cursor.moveToFirst()) {
- child.put(StructuredName.PREFIX, cursor.getString(0));
- child.put(StructuredName.GIVEN_NAME, cursor.getString(1));
- child.put(StructuredName.MIDDLE_NAME, cursor.getString(2));
- child.put(StructuredName.FAMILY_NAME, cursor.getString(3));
- child.put(StructuredName.SUFFIX, cursor.getString(4));
- }
- } finally {
- cursor.close();
- }
- }
- }
-
- final String phoneticName = extras.getString(Insert.PHONETIC_NAME);
- if (ContactsUtils.isGraphic(phoneticName)) {
- child.put(StructuredName.PHONETIC_GIVEN_NAME, phoneticName);
- }
- }
-
- private static void parseStructuredPostalExtra(
- AccountType accountType, RawContactDelta state, Bundle extras) {
- // StructuredPostal
- final DataKind kind = accountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
- final ValuesDelta child = parseExtras(state, kind, extras, Insert.POSTAL_TYPE,
- Insert.POSTAL, StructuredPostal.FORMATTED_ADDRESS);
- String address = child == null ? null
- : child.getAsString(StructuredPostal.FORMATTED_ADDRESS);
- if (!TextUtils.isEmpty(address)) {
- boolean supportsFormatted = false;
- if (kind.fieldList != null) {
- for (EditField field : kind.fieldList) {
- if (StructuredPostal.FORMATTED_ADDRESS.equals(field.column)) {
- supportsFormatted = true;
- break;
- }
- }
- }
-
- if (!supportsFormatted) {
- child.put(StructuredPostal.STREET, address);
- child.putNull(StructuredPostal.FORMATTED_ADDRESS);
- }
- }
- }
-
- private static void parseValues(
- RawContactDelta state, AccountType accountType,
- ArrayList<ContentValues> dataValueList) {
- for (ContentValues values : dataValueList) {
- String mimeType = values.getAsString(Data.MIMETYPE);
- if (TextUtils.isEmpty(mimeType)) {
- Log.e(TAG, "Mimetype is required. Ignoring: " + values);
- continue;
- }
-
- // Won't override the contact name
- if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
- continue;
- } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
- values.remove(PhoneDataItem.KEY_FORMATTED_PHONE_NUMBER);
- final Integer type = values.getAsInteger(Phone.TYPE);
- // If the provided phone number provides a custom phone type but not a label,
- // replace it with mobile (by default) to avoid the "Enter custom label" from
- // popping up immediately upon entering the ContactEditorFragment
- if (type != null && type == Phone.TYPE_CUSTOM &&
- TextUtils.isEmpty(values.getAsString(Phone.LABEL))) {
- values.put(Phone.TYPE, Phone.TYPE_MOBILE);
- }
- }
-
- DataKind kind = accountType.getKindForMimetype(mimeType);
- if (kind == null) {
- Log.e(TAG, "Mimetype not supported for account type "
- + accountType.getAccountTypeAndDataSet() + ". Ignoring: " + values);
- continue;
- }
-
- ValuesDelta entry = ValuesDelta.fromAfter(values);
- if (isEmpty(entry, kind)) {
- continue;
- }
-
- ArrayList<ValuesDelta> entries = state.getMimeEntries(mimeType);
-
- if ((kind.typeOverallMax != 1) || GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
- // Check for duplicates
- boolean addEntry = true;
- int count = 0;
- if (entries != null && entries.size() > 0) {
- for (ValuesDelta delta : entries) {
- if (!delta.isDelete()) {
- if (areEqual(delta, values, kind)) {
- addEntry = false;
- break;
- }
- count++;
- }
- }
- }
-
- if (kind.typeOverallMax != -1 && count >= kind.typeOverallMax) {
- Log.e(TAG, "Mimetype allows at most " + kind.typeOverallMax
- + " entries. Ignoring: " + values);
- addEntry = false;
- }
-
- if (addEntry) {
- addEntry = adjustType(entry, entries, kind);
- }
-
- if (addEntry) {
- state.addEntry(entry);
- }
- } else {
- // Non-list entries should not be overridden
- boolean addEntry = true;
- if (entries != null && entries.size() > 0) {
- for (ValuesDelta delta : entries) {
- if (!delta.isDelete() && !isEmpty(delta, kind)) {
- addEntry = false;
- break;
- }
- }
- if (addEntry) {
- for (ValuesDelta delta : entries) {
- delta.markDeleted();
- }
- }
- }
-
- if (addEntry) {
- addEntry = adjustType(entry, entries, kind);
- }
-
- if (addEntry) {
- state.addEntry(entry);
- } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType)){
- // Note is most likely to contain large amounts of text
- // that we don't want to drop on the ground.
- for (ValuesDelta delta : entries) {
- if (!isEmpty(delta, kind)) {
- delta.put(Note.NOTE, delta.getAsString(Note.NOTE) + "\n"
- + values.getAsString(Note.NOTE));
- break;
- }
- }
- } else {
- Log.e(TAG, "Will not override mimetype " + mimeType + ". Ignoring: "
- + values);
- }
- }
- }
- }
-
- /**
- * Checks if the data kind allows addition of another entry (e.g. Exchange only
- * supports two "work" phone numbers). If not, tries to switch to one of the
- * unused types. If successful, returns true.
- */
- private static boolean adjustType(
- ValuesDelta entry, ArrayList<ValuesDelta> entries, DataKind kind) {
- if (kind.typeColumn == null || kind.typeList == null || kind.typeList.size() == 0) {
- return true;
- }
-
- Integer typeInteger = entry.getAsInteger(kind.typeColumn);
- int type = typeInteger != null ? typeInteger : kind.typeList.get(0).rawValue;
-
- if (isTypeAllowed(type, entries, kind)) {
- entry.put(kind.typeColumn, type);
- return true;
- }
-
- // Specified type is not allowed - choose the first available type that is allowed
- int size = kind.typeList.size();
- for (int i = 0; i < size; i++) {
- EditType editType = kind.typeList.get(i);
- if (isTypeAllowed(editType.rawValue, entries, kind)) {
- entry.put(kind.typeColumn, editType.rawValue);
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Checks if a new entry of the specified type can be added to the raw
- * contact. For example, Exchange only supports two "work" phone numbers, so
- * addition of a third would not be allowed.
- */
- private static boolean isTypeAllowed(int type, ArrayList<ValuesDelta> entries, DataKind kind) {
- int max = 0;
- int size = kind.typeList.size();
- for (int i = 0; i < size; i++) {
- EditType editType = kind.typeList.get(i);
- if (editType.rawValue == type) {
- max = editType.specificMax;
- break;
- }
- }
-
- if (max == 0) {
- // This type is not allowed at all
- return false;
- }
-
- if (max == -1) {
- // Unlimited instances of this type are allowed
- return true;
- }
-
- return getEntryCountByType(entries, kind.typeColumn, type) < max;
- }
-
- /**
- * Counts occurrences of the specified type in the supplied entry list.
- *
- * @return The count of occurrences of the type in the entry list. 0 if entries is
- * {@literal null}
- */
- private static int getEntryCountByType(ArrayList<ValuesDelta> entries, String typeColumn,
- int type) {
- int count = 0;
- if (entries != null) {
- for (ValuesDelta entry : entries) {
- Integer typeInteger = entry.getAsInteger(typeColumn);
- if (typeInteger != null && typeInteger == type) {
- count++;
- }
- }
- }
- return count;
- }
-
- /**
- * Attempt to parse legacy {@link Insert#IM_PROTOCOL} values, replacing them
- * with updated values.
- */
- @SuppressWarnings("deprecation")
- private static void fixupLegacyImType(Bundle bundle) {
- final String encodedString = bundle.getString(Insert.IM_PROTOCOL);
- if (encodedString == null) return;
-
- try {
- final Object protocol = android.provider.Contacts.ContactMethods
- .decodeImProtocol(encodedString);
- if (protocol instanceof Integer) {
- bundle.putInt(Insert.IM_PROTOCOL, (Integer)protocol);
- } else {
- bundle.putString(Insert.IM_PROTOCOL, (String)protocol);
- }
- } catch (IllegalArgumentException e) {
- // Ignore exception when legacy parser fails
- }
- }
-
- /**
- * Parse a specific entry from the given {@link Bundle} and insert into the
- * given {@link RawContactDelta}. Silently skips the insert when missing value
- * or no valid {@link EditType} found.
- *
- * @param typeExtra {@link Bundle} key that holds the incoming
- * {@link EditType#rawValue} value.
- * @param valueExtra {@link Bundle} key that holds the incoming value.
- * @param valueColumn Column to write value into {@link ValuesDelta}.
- */
- public static ValuesDelta parseExtras(RawContactDelta state, DataKind kind, Bundle extras,
- String typeExtra, String valueExtra, String valueColumn) {
- final CharSequence value = extras.getCharSequence(valueExtra);
-
- // Bail early if account type doesn't handle this MIME type
- if (kind == null) return null;
-
- // Bail when can't insert type, or value missing
- final boolean canInsert = RawContactModifier.canInsert(state, kind);
- final boolean validValue = (value != null && TextUtils.isGraphic(value));
- if (!validValue || !canInsert) return null;
-
- // Find exact type when requested, otherwise best available type
- final boolean hasType = extras.containsKey(typeExtra);
- final int typeValue = extras.getInt(typeExtra, hasType ? BaseTypes.TYPE_CUSTOM
- : Integer.MIN_VALUE);
- final EditType editType = RawContactModifier.getBestValidType(state, kind, true, typeValue);
-
- // Create data row and fill with value
- final ValuesDelta child = RawContactModifier.insertChild(state, kind, editType);
- child.put(valueColumn, value.toString());
-
- if (editType != null && editType.customColumn != null) {
- // Write down label when custom type picked
- final String customType = extras.getString(typeExtra);
- child.put(editType.customColumn, customType);
- }
-
- return child;
- }
-
- /**
- * Generic mime types with type support (e.g. TYPE_HOME).
- * Here, "type support" means if the data kind has CommonColumns#TYPE or not. Data kinds which
- * have their own migrate methods aren't listed here.
- */
- private static final Set<String> sGenericMimeTypesWithTypeSupport = new HashSet<String>(
- Arrays.asList(Phone.CONTENT_ITEM_TYPE,
- Email.CONTENT_ITEM_TYPE,
- Im.CONTENT_ITEM_TYPE,
- Nickname.CONTENT_ITEM_TYPE,
- Website.CONTENT_ITEM_TYPE,
- Relation.CONTENT_ITEM_TYPE,
- SipAddress.CONTENT_ITEM_TYPE));
- private static final Set<String> sGenericMimeTypesWithoutTypeSupport = new HashSet<String>(
- Arrays.asList(Organization.CONTENT_ITEM_TYPE,
- Note.CONTENT_ITEM_TYPE,
- Photo.CONTENT_ITEM_TYPE,
- GroupMembership.CONTENT_ITEM_TYPE));
- // CommonColumns.TYPE cannot be accessed as it is protected interface, so use
- // Phone.TYPE instead.
- private static final String COLUMN_FOR_TYPE = Phone.TYPE;
- private static final String COLUMN_FOR_LABEL = Phone.LABEL;
- private static final int TYPE_CUSTOM = Phone.TYPE_CUSTOM;
-
- /**
- * Migrates old RawContactDelta to newly created one with a new restriction supplied from
- * newAccountType.
- *
- * This is only for account switch during account creation (which must be insert operation).
- */
- public static void migrateStateForNewContact(Context context,
- RawContactDelta oldState, RawContactDelta newState,
- AccountType oldAccountType, AccountType newAccountType) {
- if (newAccountType == oldAccountType) {
- // Just copying all data in oldState isn't enough, but we can still rely on a lot of
- // shortcuts.
- for (DataKind kind : newAccountType.getSortedDataKinds()) {
- final String mimeType = kind.mimeType;
- // The fields with short/long form capability must be treated properly.
- if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
- migrateStructuredName(context, oldState, newState, kind);
- } else {
- List<ValuesDelta> entryList = oldState.getMimeEntries(mimeType);
- if (entryList != null && !entryList.isEmpty()) {
- for (ValuesDelta entry : entryList) {
- ContentValues values = entry.getAfter();
- if (values != null) {
- newState.addEntry(ValuesDelta.fromAfter(values));
- }
- }
- }
- }
- }
- } else {
- // Migrate data supported by the new account type.
- // All the other data inside oldState are silently dropped.
- for (DataKind kind : newAccountType.getSortedDataKinds()) {
- if (!kind.editable) continue;
- final String mimeType = kind.mimeType;
- if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
- || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
- // Ignore pseudo data.
- continue;
- } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
- migrateStructuredName(context, oldState, newState, kind);
- } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
- migratePostal(oldState, newState, kind);
- } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType)) {
- migrateEvent(oldState, newState, kind, null /* default Year */);
- } else if (sGenericMimeTypesWithoutTypeSupport.contains(mimeType)) {
- migrateGenericWithoutTypeColumn(oldState, newState, kind);
- } else if (sGenericMimeTypesWithTypeSupport.contains(mimeType)) {
- migrateGenericWithTypeColumn(oldState, newState, kind);
- } else {
- throw new IllegalStateException("Unexpected editable mime-type: " + mimeType);
- }
- }
- }
- }
-
- /**
- * Checks {@link DataKind#isList} and {@link DataKind#typeOverallMax}, and restricts
- * the number of entries (ValuesDelta) inside newState.
- */
- private static ArrayList<ValuesDelta> ensureEntryMaxSize(RawContactDelta newState,
- DataKind kind, ArrayList<ValuesDelta> mimeEntries) {
- if (mimeEntries == null) {
- return null;
- }
-
- final int typeOverallMax = kind.typeOverallMax;
- if (typeOverallMax >= 0 && (mimeEntries.size() > typeOverallMax)) {
- ArrayList<ValuesDelta> newMimeEntries = new ArrayList<ValuesDelta>(typeOverallMax);
- for (int i = 0; i < typeOverallMax; i++) {
- newMimeEntries.add(mimeEntries.get(i));
- }
- mimeEntries = newMimeEntries;
- }
- return mimeEntries;
- }
-
- /** @hide Public only for testing. */
- public static void migrateStructuredName(
- Context context, RawContactDelta oldState, RawContactDelta newState,
- DataKind newDataKind) {
- final ContentValues values =
- oldState.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE).getAfter();
- if (values == null) {
- return;
- }
-
- boolean supportDisplayName = false;
- boolean supportPhoneticFullName = false;
- boolean supportPhoneticFamilyName = false;
- boolean supportPhoneticMiddleName = false;
- boolean supportPhoneticGivenName = false;
- for (EditField editField : newDataKind.fieldList) {
- if (StructuredName.DISPLAY_NAME.equals(editField.column)) {
- supportDisplayName = true;
- }
- if (DataKind.PSEUDO_COLUMN_PHONETIC_NAME.equals(editField.column)) {
- supportPhoneticFullName = true;
- }
- if (StructuredName.PHONETIC_FAMILY_NAME.equals(editField.column)) {
- supportPhoneticFamilyName = true;
- }
- if (StructuredName.PHONETIC_MIDDLE_NAME.equals(editField.column)) {
- supportPhoneticMiddleName = true;
- }
- if (StructuredName.PHONETIC_GIVEN_NAME.equals(editField.column)) {
- supportPhoneticGivenName = true;
- }
- }
-
- // DISPLAY_NAME <-> PREFIX, GIVEN_NAME, MIDDLE_NAME, FAMILY_NAME, SUFFIX
- final String displayName = values.getAsString(StructuredName.DISPLAY_NAME);
- if (!TextUtils.isEmpty(displayName)) {
- if (!supportDisplayName) {
- // Old data has a display name, while the new account doesn't allow it.
- NameConverter.displayNameToStructuredName(context, displayName, values);
-
- // We don't want to migrate unseen data which may confuse users after the creation.
- values.remove(StructuredName.DISPLAY_NAME);
- }
- } else {
- if (supportDisplayName) {
- // Old data does not have display name, while the new account requires it.
- values.put(StructuredName.DISPLAY_NAME,
- NameConverter.structuredNameToDisplayName(context, values));
- for (String field : NameConverter.STRUCTURED_NAME_FIELDS) {
- values.remove(field);
- }
- }
- }
-
- // Phonetic (full) name <-> PHONETIC_FAMILY_NAME, PHONETIC_MIDDLE_NAME, PHONETIC_GIVEN_NAME
- final String phoneticFullName = values.getAsString(DataKind.PSEUDO_COLUMN_PHONETIC_NAME);
- if (!TextUtils.isEmpty(phoneticFullName)) {
- if (!supportPhoneticFullName) {
- // Old data has a phonetic (full) name, while the new account doesn't allow it.
- final StructuredNameDataItem tmpItem =
- PhoneticNameEditorView.parsePhoneticName(phoneticFullName, null);
- values.remove(DataKind.PSEUDO_COLUMN_PHONETIC_NAME);
- if (supportPhoneticFamilyName) {
- values.put(StructuredName.PHONETIC_FAMILY_NAME,
- tmpItem.getPhoneticFamilyName());
- } else {
- values.remove(StructuredName.PHONETIC_FAMILY_NAME);
- }
- if (supportPhoneticMiddleName) {
- values.put(StructuredName.PHONETIC_MIDDLE_NAME,
- tmpItem.getPhoneticMiddleName());
- } else {
- values.remove(StructuredName.PHONETIC_MIDDLE_NAME);
- }
- if (supportPhoneticGivenName) {
- values.put(StructuredName.PHONETIC_GIVEN_NAME,
- tmpItem.getPhoneticGivenName());
- } else {
- values.remove(StructuredName.PHONETIC_GIVEN_NAME);
- }
- }
- } else {
- if (supportPhoneticFullName) {
- // Old data does not have a phonetic (full) name, while the new account requires it.
- values.put(DataKind.PSEUDO_COLUMN_PHONETIC_NAME,
- PhoneticNameEditorView.buildPhoneticName(
- values.getAsString(StructuredName.PHONETIC_FAMILY_NAME),
- values.getAsString(StructuredName.PHONETIC_MIDDLE_NAME),
- values.getAsString(StructuredName.PHONETIC_GIVEN_NAME)));
- }
- if (!supportPhoneticFamilyName) {
- values.remove(StructuredName.PHONETIC_FAMILY_NAME);
- }
- if (!supportPhoneticMiddleName) {
- values.remove(StructuredName.PHONETIC_MIDDLE_NAME);
- }
- if (!supportPhoneticGivenName) {
- values.remove(StructuredName.PHONETIC_GIVEN_NAME);
- }
- }
-
- newState.addEntry(ValuesDelta.fromAfter(values));
- }
-
- /** @hide Public only for testing. */
- public static void migratePostal(RawContactDelta oldState, RawContactDelta newState,
- DataKind newDataKind) {
- final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind,
- oldState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE));
- if (mimeEntries == null || mimeEntries.isEmpty()) {
- return;
- }
-
- boolean supportFormattedAddress = false;
- boolean supportStreet = false;
- final String firstColumn = newDataKind.fieldList.get(0).column;
- for (EditField editField : newDataKind.fieldList) {
- if (StructuredPostal.FORMATTED_ADDRESS.equals(editField.column)) {
- supportFormattedAddress = true;
- }
- if (StructuredPostal.STREET.equals(editField.column)) {
- supportStreet = true;
- }
- }
-
- final Set<Integer> supportedTypes = new HashSet<Integer>();
- if (newDataKind.typeList != null && !newDataKind.typeList.isEmpty()) {
- for (EditType editType : newDataKind.typeList) {
- supportedTypes.add(editType.rawValue);
- }
- }
-
- for (ValuesDelta entry : mimeEntries) {
- final ContentValues values = entry.getAfter();
- if (values == null) {
- continue;
- }
- final Integer oldType = values.getAsInteger(StructuredPostal.TYPE);
- if (!supportedTypes.contains(oldType)) {
- int defaultType;
- if (newDataKind.defaultValues != null) {
- defaultType = newDataKind.defaultValues.getAsInteger(StructuredPostal.TYPE);
- } else {
- defaultType = newDataKind.typeList.get(0).rawValue;
- }
- values.put(StructuredPostal.TYPE, defaultType);
- if (oldType != null && oldType == StructuredPostal.TYPE_CUSTOM) {
- values.remove(StructuredPostal.LABEL);
- }
- }
-
- final String formattedAddress = values.getAsString(StructuredPostal.FORMATTED_ADDRESS);
- if (!TextUtils.isEmpty(formattedAddress)) {
- if (!supportFormattedAddress) {
- // Old data has a formatted address, while the new account doesn't allow it.
- values.remove(StructuredPostal.FORMATTED_ADDRESS);
-
- // Unlike StructuredName we don't have logic to split it, so first
- // try to use street field and. If the new account doesn't have one,
- // then select first one anyway.
- if (supportStreet) {
- values.put(StructuredPostal.STREET, formattedAddress);
- } else {
- values.put(firstColumn, formattedAddress);
- }
- }
- } else {
- if (supportFormattedAddress) {
- // Old data does not have formatted address, while the new account requires it.
- // Unlike StructuredName we don't have logic to join multiple address values.
- // Use poor join heuristics for now.
- String[] structuredData;
- final boolean useJapaneseOrder =
- Locale.JAPANESE.getLanguage().equals(Locale.getDefault().getLanguage());
- if (useJapaneseOrder) {
- structuredData = new String[] {
- values.getAsString(StructuredPostal.COUNTRY),
- values.getAsString(StructuredPostal.POSTCODE),
- values.getAsString(StructuredPostal.REGION),
- values.getAsString(StructuredPostal.CITY),
- values.getAsString(StructuredPostal.NEIGHBORHOOD),
- values.getAsString(StructuredPostal.STREET),
- values.getAsString(StructuredPostal.POBOX) };
- } else {
- structuredData = new String[] {
- values.getAsString(StructuredPostal.POBOX),
- values.getAsString(StructuredPostal.STREET),
- values.getAsString(StructuredPostal.NEIGHBORHOOD),
- values.getAsString(StructuredPostal.CITY),
- values.getAsString(StructuredPostal.REGION),
- values.getAsString(StructuredPostal.POSTCODE),
- values.getAsString(StructuredPostal.COUNTRY) };
- }
- final StringBuilder builder = new StringBuilder();
- for (String elem : structuredData) {
- if (!TextUtils.isEmpty(elem)) {
- builder.append(elem + "\n");
- }
- }
- values.put(StructuredPostal.FORMATTED_ADDRESS, builder.toString());
-
- values.remove(StructuredPostal.POBOX);
- values.remove(StructuredPostal.STREET);
- values.remove(StructuredPostal.NEIGHBORHOOD);
- values.remove(StructuredPostal.CITY);
- values.remove(StructuredPostal.REGION);
- values.remove(StructuredPostal.POSTCODE);
- values.remove(StructuredPostal.COUNTRY);
- }
- }
-
- newState.addEntry(ValuesDelta.fromAfter(values));
- }
- }
-
- /** @hide Public only for testing. */
- public static void migrateEvent(RawContactDelta oldState, RawContactDelta newState,
- DataKind newDataKind, Integer defaultYear) {
- final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind,
- oldState.getMimeEntries(Event.CONTENT_ITEM_TYPE));
- if (mimeEntries == null || mimeEntries.isEmpty()) {
- return;
- }
-
- final SparseArray<EventEditType> allowedTypes = new SparseArray<EventEditType>();
- for (EditType editType : newDataKind.typeList) {
- allowedTypes.put(editType.rawValue, (EventEditType) editType);
- }
- for (ValuesDelta entry : mimeEntries) {
- final ContentValues values = entry.getAfter();
- if (values == null) {
- continue;
- }
- final String dateString = values.getAsString(Event.START_DATE);
- final Integer type = values.getAsInteger(Event.TYPE);
- if (type != null && (allowedTypes.indexOfKey(type) >= 0)
- && !TextUtils.isEmpty(dateString)) {
- EventEditType suitableType = allowedTypes.get(type);
-
- final ParsePosition position = new ParsePosition(0);
- boolean yearOptional = false;
- Date date = CommonDateUtils.DATE_AND_TIME_FORMAT.parse(dateString, position);
- if (date == null) {
- yearOptional = true;
- date = CommonDateUtils.NO_YEAR_DATE_FORMAT.parse(dateString, position);
- }
- if (date != null) {
- if (yearOptional && !suitableType.isYearOptional()) {
- // The new EditType doesn't allow optional year. Supply default.
- final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE,
- Locale.US);
- if (defaultYear == null) {
- defaultYear = calendar.get(Calendar.YEAR);
- }
- calendar.setTime(date);
- final int month = calendar.get(Calendar.MONTH);
- final int day = calendar.get(Calendar.DAY_OF_MONTH);
- // Exchange requires 8:00 for birthdays
- calendar.set(defaultYear, month, day,
- EventFieldEditorView.getDefaultHourForBirthday(), 0, 0);
- values.put(Event.START_DATE,
- CommonDateUtils.FULL_DATE_FORMAT.format(calendar.getTime()));
- }
- }
- newState.addEntry(ValuesDelta.fromAfter(values));
- } else {
- // Just drop it.
- }
- }
- }
-
- /** @hide Public only for testing. */
- public static void migrateGenericWithoutTypeColumn(
- RawContactDelta oldState, RawContactDelta newState, DataKind newDataKind) {
- final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind,
- oldState.getMimeEntries(newDataKind.mimeType));
- if (mimeEntries == null || mimeEntries.isEmpty()) {
- return;
- }
-
- for (ValuesDelta entry : mimeEntries) {
- ContentValues values = entry.getAfter();
- if (values != null) {
- newState.addEntry(ValuesDelta.fromAfter(values));
- }
- }
- }
-
- /** @hide Public only for testing. */
- public static void migrateGenericWithTypeColumn(
- RawContactDelta oldState, RawContactDelta newState, DataKind newDataKind) {
- final ArrayList<ValuesDelta> mimeEntries = oldState.getMimeEntries(newDataKind.mimeType);
- if (mimeEntries == null || mimeEntries.isEmpty()) {
- return;
- }
-
- // Note that type specified with the old account may be invalid with the new account, while
- // we want to preserve its data as much as possible. e.g. if a user typed a phone number
- // with a type which is valid with an old account but not with a new account, the user
- // probably wants to have the number with default type, rather than seeing complete data
- // loss.
- //
- // Specifically, this method works as follows:
- // 1. detect defaultType
- // 2. prepare constants & variables for iteration
- // 3. iterate over mimeEntries:
- // 3.1 stop iteration if total number of mimeEntries reached typeOverallMax specified in
- // DataKind
- // 3.2 replace unallowed types with defaultType
- // 3.3 check if the number of entries is below specificMax specified in AccountType
-
- // Here, defaultType can be supplied in two ways
- // - via kind.defaultValues
- // - via kind.typeList.get(0).rawValue
- Integer defaultType = null;
- if (newDataKind.defaultValues != null) {
- defaultType = newDataKind.defaultValues.getAsInteger(COLUMN_FOR_TYPE);
- }
- final Set<Integer> allowedTypes = new HashSet<Integer>();
- // key: type, value: the number of entries allowed for the type (specificMax)
- final SparseIntArray typeSpecificMaxMap = new SparseIntArray();
- if (defaultType != null) {
- allowedTypes.add(defaultType);
- typeSpecificMaxMap.put(defaultType, -1);
- }
- // Note: typeList may be used in different purposes when defaultValues are specified.
- // Especially in IM, typeList contains available protocols (e.g. PROTOCOL_GOOGLE_TALK)
- // instead of "types" which we want to treate here (e.g. TYPE_HOME). So we don't add
- // anything other than defaultType into allowedTypes and typeSpecificMapMax.
- if (!Im.CONTENT_ITEM_TYPE.equals(newDataKind.mimeType) &&
- newDataKind.typeList != null && !newDataKind.typeList.isEmpty()) {
- for (EditType editType : newDataKind.typeList) {
- allowedTypes.add(editType.rawValue);
- typeSpecificMaxMap.put(editType.rawValue, editType.specificMax);
- }
- if (defaultType == null) {
- defaultType = newDataKind.typeList.get(0).rawValue;
- }
- }
-
- if (defaultType == null) {
- Log.w(TAG, "Default type isn't available for mimetype " + newDataKind.mimeType);
- }
-
- final int typeOverallMax = newDataKind.typeOverallMax;
-
- // key: type, value: the number of current entries.
- final SparseIntArray currentEntryCount = new SparseIntArray();
- int totalCount = 0;
-
- for (ValuesDelta entry : mimeEntries) {
- if (typeOverallMax != -1 && totalCount >= typeOverallMax) {
- break;
- }
-
- final ContentValues values = entry.getAfter();
- if (values == null) {
- continue;
- }
-
- final Integer oldType = entry.getAsInteger(COLUMN_FOR_TYPE);
- final Integer typeForNewAccount;
- if (!allowedTypes.contains(oldType)) {
- // The new account doesn't support the type.
- if (defaultType != null) {
- typeForNewAccount = defaultType.intValue();
- values.put(COLUMN_FOR_TYPE, defaultType.intValue());
- if (oldType != null && oldType == TYPE_CUSTOM) {
- values.remove(COLUMN_FOR_LABEL);
- }
- } else {
- typeForNewAccount = null;
- values.remove(COLUMN_FOR_TYPE);
- }
- } else {
- typeForNewAccount = oldType;
- }
- if (typeForNewAccount != null) {
- final int specificMax = typeSpecificMaxMap.get(typeForNewAccount, 0);
- if (specificMax >= 0) {
- final int currentCount = currentEntryCount.get(typeForNewAccount, 0);
- if (currentCount >= specificMax) {
- continue;
- }
- currentEntryCount.put(typeForNewAccount, currentCount + 1);
- }
- }
- newState.addEntry(ValuesDelta.fromAfter(values));
- totalCount++;
- }
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/DataItem.java b/src/com/android/contacts/model/dataitem/DataItem.java
deleted file mode 100644
index 36f3cb2..0000000
--- a/src/com/android/contacts/model/dataitem/DataItem.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.Identity;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-import android.provider.ContactsContract.CommonDataKinds.SipAddress;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.provider.ContactsContract.Contacts.Data;
-
-import com.android.contacts.common.model.dataitem.DataKind;
-
-/**
- * This is the base class for data items, which represents a row from the Data table.
- */
-public class DataItem {
-
- private final ContentValues mContentValues;
-
- protected DataItem(ContentValues values) {
- mContentValues = values;
- }
-
- /**
- * Factory for creating subclasses of DataItem objects based on the mimetype in the
- * content values. Raw contact is the raw contact that this data item is associated with.
- */
- public static DataItem createFrom(ContentValues values) {
- final String mimeType = values.getAsString(Data.MIMETYPE);
- if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new GroupMembershipDataItem(values);
- } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new StructuredNameDataItem(values);
- } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new PhoneDataItem(values);
- } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new EmailDataItem(values);
- } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new StructuredPostalDataItem(values);
- } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new ImDataItem(values);
- } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new OrganizationDataItem(values);
- } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new NicknameDataItem(values);
- } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new NoteDataItem(values);
- } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new WebsiteDataItem(values);
- } else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new SipAddressDataItem(values);
- } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new EventDataItem(values);
- } else if (Relation.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new RelationDataItem(values);
- } else if (Identity.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new IdentityDataItem(values);
- } else if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return new PhotoDataItem(values);
- }
-
- // generic
- return new DataItem(values);
- }
-
- public ContentValues getContentValues() {
- return mContentValues;
- }
-
- public void setRawContactId(long rawContactId) {
- mContentValues.put(Data.RAW_CONTACT_ID, rawContactId);
- }
-
- /**
- * Returns the data id.
- */
- public long getId() {
- return mContentValues.getAsLong(Data._ID);
- }
-
- /**
- * Returns the mimetype of the data.
- */
- public String getMimeType() {
- return mContentValues.getAsString(Data.MIMETYPE);
- }
-
- public void setMimeType(String mimeType) {
- mContentValues.put(Data.MIMETYPE, mimeType);
- }
-
- public boolean isPrimary() {
- Integer primary = mContentValues.getAsInteger(Data.IS_PRIMARY);
- return primary != null && primary != 0;
- }
-
- public boolean isSuperPrimary() {
- Integer superPrimary = mContentValues.getAsInteger(Data.IS_SUPER_PRIMARY);
- return superPrimary != null && superPrimary != 0;
- }
-
- public boolean hasKindTypeColumn(DataKind kind) {
- final String key = kind.typeColumn;
- return key != null && mContentValues.containsKey(key) &&
- mContentValues.getAsInteger(key) != null;
- }
-
- public int getKindTypeColumn(DataKind kind) {
- final String key = kind.typeColumn;
- return mContentValues.getAsInteger(key);
- }
-
- /**
- * This builds the data string depending on the type of data item by using the generic
- * DataKind object underneath.
- */
- public String buildDataString(Context context, DataKind kind) {
- if (kind.actionBody == null) {
- return null;
- }
- CharSequence actionBody = kind.actionBody.inflateUsing(context, mContentValues);
- return actionBody == null ? null : actionBody.toString();
- }
-
- /**
- * This builds the data string(intended for display) depending on the type of data item. It
- * returns the same value as {@link #buildDataString} by default, but certain data items can
- * override it to provide their version of formatted data strings.
- *
- * @return Data string representing the data item, possibly formatted for display
- */
- public String buildDataStringForDisplay(Context context, DataKind kind) {
- return buildDataString(context, kind);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/EmailDataItem.java b/src/com/android/contacts/model/dataitem/EmailDataItem.java
deleted file mode 100644
index 77ad126..0000000
--- a/src/com/android/contacts/model/dataitem/EmailDataItem.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-
-/**
- * Represents an email data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Email}.
- */
-public class EmailDataItem extends DataItem {
-
- /* package */ EmailDataItem(ContentValues values) {
- super(values);
- }
-
- public String getAddress() {
- return getContentValues().getAsString(Email.ADDRESS);
- }
-
- public String getDisplayName() {
- return getContentValues().getAsString(Email.DISPLAY_NAME);
- }
-
- public String getData() {
- return getContentValues().getAsString(Email.DATA);
- }
-
- public String getLabel() {
- return getContentValues().getAsString(Email.LABEL);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/EventDataItem.java b/src/com/android/contacts/model/dataitem/EventDataItem.java
deleted file mode 100644
index 9820c8f..0000000
--- a/src/com/android/contacts/model/dataitem/EventDataItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-
-/**
- * Represents an event data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Event}.
- */
-public class EventDataItem extends DataItem {
-
- /* package */ EventDataItem(ContentValues values) {
- super(values);
- }
-
- public String getStartDate() {
- return getContentValues().getAsString(Event.START_DATE);
- }
-
- public String getLabel() {
- return getContentValues().getAsString(Event.LABEL);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/GroupMembershipDataItem.java b/src/com/android/contacts/model/dataitem/GroupMembershipDataItem.java
deleted file mode 100644
index 00558d0..0000000
--- a/src/com/android/contacts/model/dataitem/GroupMembershipDataItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-
-/**
- * Represents a group memebership data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.GroupMembership}.
- */
-public class GroupMembershipDataItem extends DataItem {
-
- /* package */ GroupMembershipDataItem(ContentValues values) {
- super(values);
- }
-
- public Long getGroupRowId() {
- return getContentValues().getAsLong(GroupMembership.GROUP_ROW_ID);
- }
-
- public String getGroupSourceId() {
- return getContentValues().getAsString(GroupMembership.GROUP_SOURCE_ID);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/IdentityDataItem.java b/src/com/android/contacts/model/dataitem/IdentityDataItem.java
deleted file mode 100644
index 045867a..0000000
--- a/src/com/android/contacts/model/dataitem/IdentityDataItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Identity;
-
-/**
- * Represents an identity data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Identity}.
- */
-public class IdentityDataItem extends DataItem {
-
- /* package */ IdentityDataItem(ContentValues values) {
- super(values);
- }
-
- public String getIdentity() {
- return getContentValues().getAsString(Identity.IDENTITY);
- }
-
- public String getNamespace() {
- return getContentValues().getAsString(Identity.NAMESPACE);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/ImDataItem.java b/src/com/android/contacts/model/dataitem/ImDataItem.java
deleted file mode 100644
index 2513b57..0000000
--- a/src/com/android/contacts/model/dataitem/ImDataItem.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-
-/**
- * Represents an IM data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Im}.
- */
-public class ImDataItem extends DataItem {
-
- private final boolean mCreatedFromEmail;
-
- /* package */ ImDataItem(ContentValues values) {
- super(values);
- mCreatedFromEmail = false;
- }
-
- private ImDataItem(ContentValues values, boolean createdFromEmail) {
- super(values);
- mCreatedFromEmail = createdFromEmail;
- }
-
- public static ImDataItem createFromEmail(EmailDataItem item) {
- ImDataItem im = new ImDataItem(new ContentValues(item.getContentValues()), true);
- im.setMimeType(Im.CONTENT_ITEM_TYPE);
- return im;
- }
-
- public String getData() {
- if (mCreatedFromEmail) {
- return getContentValues().getAsString(Email.DATA);
- } else {
- return getContentValues().getAsString(Im.DATA);
- }
- }
-
- public String getLabel() {
- return getContentValues().getAsString(Im.LABEL);
- }
-
- /**
- * Values are one of Im.PROTOCOL_
- */
- public Integer getProtocol() {
- return getContentValues().getAsInteger(Im.PROTOCOL);
- }
-
- public boolean isProtocolValid() {
- return getProtocol() != null;
- }
-
- public String getCustomProtocol() {
- return getContentValues().getAsString(Im.CUSTOM_PROTOCOL);
- }
-
- public int getChatCapability() {
- Integer result = getContentValues().getAsInteger(Im.CHAT_CAPABILITY);
- return result == null ? 0 : result;
- }
-
- public boolean isCreatedFromEmail() {
- return mCreatedFromEmail;
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/NicknameDataItem.java b/src/com/android/contacts/model/dataitem/NicknameDataItem.java
deleted file mode 100644
index 2d44751..0000000
--- a/src/com/android/contacts/model/dataitem/NicknameDataItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
-
-/**
- * Represents a nickname data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Nickname}.
- */
-public class NicknameDataItem extends DataItem {
-
- public NicknameDataItem(ContentValues values) {
- super(values);
- }
-
- public String getName() {
- return getContentValues().getAsString(Nickname.NAME);
- }
-
- public String getLabel() {
- return getContentValues().getAsString(Nickname.LABEL);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/NoteDataItem.java b/src/com/android/contacts/model/dataitem/NoteDataItem.java
deleted file mode 100644
index 9a572cb..0000000
--- a/src/com/android/contacts/model/dataitem/NoteDataItem.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Note;
-
-/**
- * Represents a note data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Note}.
- */
-public class NoteDataItem extends DataItem {
-
- /* package */ NoteDataItem(ContentValues values) {
- super(values);
- }
-
- public String getNote() {
- return getContentValues().getAsString(Note.NOTE);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/OrganizationDataItem.java b/src/com/android/contacts/model/dataitem/OrganizationDataItem.java
deleted file mode 100644
index e5b142e..0000000
--- a/src/com/android/contacts/model/dataitem/OrganizationDataItem.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-
-/**
- * Represents an organization data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Organization}.
- */
-public class OrganizationDataItem extends DataItem {
-
- /* package */ OrganizationDataItem(ContentValues values) {
- super(values);
- }
-
- public String getCompany() {
- return getContentValues().getAsString(Organization.COMPANY);
- }
-
- public String getLabel() {
- return getContentValues().getAsString(Organization.LABEL);
- }
-
- public String getTitle() {
- return getContentValues().getAsString(Organization.TITLE);
- }
-
- public String getDepartment() {
- return getContentValues().getAsString(Organization.DEPARTMENT);
- }
-
- public String getJobDescription() {
- return getContentValues().getAsString(Organization.JOB_DESCRIPTION);
- }
-
- public String getSymbol() {
- return getContentValues().getAsString(Organization.SYMBOL);
- }
-
- public String getPhoneticName() {
- return getContentValues().getAsString(Organization.PHONETIC_NAME);
- }
-
- public String getOfficeLocation() {
- return getContentValues().getAsString(Organization.OFFICE_LOCATION);
- }
-
- public String getPhoneticNameStyle() {
- return getContentValues().getAsString(Organization.PHONETIC_NAME_STYLE);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/PhoneDataItem.java b/src/com/android/contacts/model/dataitem/PhoneDataItem.java
deleted file mode 100644
index 9196369..0000000
--- a/src/com/android/contacts/model/dataitem/PhoneDataItem.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.telephony.PhoneNumberUtils;
-
-import com.android.contacts.common.model.dataitem.DataKind;
-
-/**
- * Represents a phone data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Phone}.
- */
-public class PhoneDataItem extends DataItem {
-
- public static final String KEY_FORMATTED_PHONE_NUMBER = "formattedPhoneNumber";
-
- /* package */ PhoneDataItem(ContentValues values) {
- super(values);
- }
-
- public String getNumber() {
- return getContentValues().getAsString(Phone.NUMBER);
- }
-
- /**
- * Returns the normalized phone number in E164 format.
- */
- public String getNormalizedNumber() {
- return getContentValues().getAsString(Phone.NORMALIZED_NUMBER);
- }
-
- public String getFormattedPhoneNumber() {
- return getContentValues().getAsString(KEY_FORMATTED_PHONE_NUMBER);
- }
-
- public String getLabel() {
- return getContentValues().getAsString(Phone.LABEL);
- }
-
- public void computeFormattedPhoneNumber(String defaultCountryIso) {
- final String phoneNumber = getNumber();
- if (phoneNumber != null) {
- final String formattedPhoneNumber = PhoneNumberUtils.formatNumber(phoneNumber,
- getNormalizedNumber(), defaultCountryIso);
- getContentValues().put(KEY_FORMATTED_PHONE_NUMBER, formattedPhoneNumber);
- }
- }
-
- /**
- * Returns the formatted phone number (if already computed using {@link
- * #computeFormattedPhoneNumber}). Otherwise this method returns the unformatted phone number.
- */
- @Override
- public String buildDataStringForDisplay(Context context, DataKind kind) {
- final String formatted = getFormattedPhoneNumber();
- if (formatted != null) {
- return formatted;
- } else {
- return getNumber();
- }
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/PhotoDataItem.java b/src/com/android/contacts/model/dataitem/PhotoDataItem.java
deleted file mode 100644
index 2ba13fb..0000000
--- a/src/com/android/contacts/model/dataitem/PhotoDataItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts.Photo;
-
-/**
- * Represents a photo data item, wrapping the columns in
- * {@link ContactsContract.Contacts.Photo}.
- */
-public class PhotoDataItem extends DataItem {
-
- /* package */ PhotoDataItem(ContentValues values) {
- super(values);
- }
-
- public Long getPhotoFileId() {
- return getContentValues().getAsLong(Photo.PHOTO_FILE_ID);
- }
-
- public byte[] getPhoto() {
- return getContentValues().getAsByteArray(Photo.PHOTO);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/RelationDataItem.java b/src/com/android/contacts/model/dataitem/RelationDataItem.java
deleted file mode 100644
index 4e11ecb..0000000
--- a/src/com/android/contacts/model/dataitem/RelationDataItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Relation;
-
-/**
- * Represents a relation data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Relation}.
- */
-public class RelationDataItem extends DataItem {
-
- /* package */ RelationDataItem(ContentValues values) {
- super(values);
- }
-
- public String getName() {
- return getContentValues().getAsString(Relation.NAME);
- }
-
- public String getLabel() {
- return getContentValues().getAsString(Relation.LABEL);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/SipAddressDataItem.java b/src/com/android/contacts/model/dataitem/SipAddressDataItem.java
deleted file mode 100644
index 45ebeee..0000000
--- a/src/com/android/contacts/model/dataitem/SipAddressDataItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.SipAddress;
-
-/**
- * Represents a sip address data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.SipAddress}.
- */
-public class SipAddressDataItem extends DataItem {
-
- /* package */ SipAddressDataItem(ContentValues values) {
- super(values);
- }
-
- public String getSipAddress() {
- return getContentValues().getAsString(SipAddress.SIP_ADDRESS);
- }
-
- public String getLabel() {
- return getContentValues().getAsString(SipAddress.LABEL);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/StructuredNameDataItem.java b/src/com/android/contacts/model/dataitem/StructuredNameDataItem.java
deleted file mode 100644
index 7d1a44d..0000000
--- a/src/com/android/contacts/model/dataitem/StructuredNameDataItem.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.Contacts.Data;
-
-/**
- * Represents a structured name data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.StructuredName}.
- */
-public class StructuredNameDataItem extends DataItem {
-
- public StructuredNameDataItem() {
- super(new ContentValues());
- getContentValues().put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
- }
-
- /* package */ StructuredNameDataItem(ContentValues values) {
- super(values);
- }
-
- public String getDisplayName() {
- return getContentValues().getAsString(StructuredName.DISPLAY_NAME);
- }
-
- public void setDisplayName(String name) {
- getContentValues().put(StructuredName.DISPLAY_NAME, name);
- }
-
- public String getGivenName() {
- return getContentValues().getAsString(StructuredName.GIVEN_NAME);
- }
-
- public String getFamilyName() {
- return getContentValues().getAsString(StructuredName.FAMILY_NAME);
- }
-
- public String getPrefix() {
- return getContentValues().getAsString(StructuredName.PREFIX);
- }
-
- public String getMiddleName() {
- return getContentValues().getAsString(StructuredName.MIDDLE_NAME);
- }
-
- public String getSuffix() {
- return getContentValues().getAsString(StructuredName.SUFFIX);
- }
-
- public String getPhoneticGivenName() {
- return getContentValues().getAsString(StructuredName.PHONETIC_GIVEN_NAME);
- }
-
- public String getPhoneticMiddleName() {
- return getContentValues().getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
- }
-
- public String getPhoneticFamilyName() {
- return getContentValues().getAsString(StructuredName.PHONETIC_FAMILY_NAME);
- }
-
- public String getFullNameStyle() {
- return getContentValues().getAsString(StructuredName.FULL_NAME_STYLE);
- }
-
- public String getPhoneticNameStyle() {
- return getContentValues().getAsString(StructuredName.PHONETIC_NAME_STYLE);
- }
-
- public void setPhoneticFamilyName(String name) {
- getContentValues().put(StructuredName.PHONETIC_FAMILY_NAME, name);
- }
-
- public void setPhoneticMiddleName(String name) {
- getContentValues().put(StructuredName.PHONETIC_MIDDLE_NAME, name);
- }
-
- public void setPhoneticGivenName(String name) {
- getContentValues().put(StructuredName.PHONETIC_GIVEN_NAME, name);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/StructuredPostalDataItem.java b/src/com/android/contacts/model/dataitem/StructuredPostalDataItem.java
deleted file mode 100644
index cf46c07..0000000
--- a/src/com/android/contacts/model/dataitem/StructuredPostalDataItem.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-
-/**
- * Represents a structured postal data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.StructuredPostal}.
- */
-public class StructuredPostalDataItem extends DataItem {
-
- /* package */ StructuredPostalDataItem(ContentValues values) {
- super(values);
- }
-
- public String getFormattedAddress() {
- return getContentValues().getAsString(StructuredPostal.FORMATTED_ADDRESS);
- }
-
- public String getLabel() {
- return getContentValues().getAsString(StructuredPostal.LABEL);
- }
-
- public String getStreet() {
- return getContentValues().getAsString(StructuredPostal.STREET);
- }
-
- public String getPOBox() {
- return getContentValues().getAsString(StructuredPostal.POBOX);
- }
-
- public String getNeighborhood() {
- return getContentValues().getAsString(StructuredPostal.NEIGHBORHOOD);
- }
-
- public String getCity() {
- return getContentValues().getAsString(StructuredPostal.CITY);
- }
-
- public String getRegion() {
- return getContentValues().getAsString(StructuredPostal.REGION);
- }
-
- public String getPostcode() {
- return getContentValues().getAsString(StructuredPostal.POSTCODE);
- }
-
- public String getCountry() {
- return getContentValues().getAsString(StructuredPostal.COUNTRY);
- }
-}
diff --git a/src/com/android/contacts/model/dataitem/WebsiteDataItem.java b/src/com/android/contacts/model/dataitem/WebsiteDataItem.java
deleted file mode 100644
index 4439be7..0000000
--- a/src/com/android/contacts/model/dataitem/WebsiteDataItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 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.model.dataitem;
-
-import android.content.ContentValues;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Website;
-
-/**
- * Represents a website data item, wrapping the columns in
- * {@link ContactsContract.CommonDataKinds.Website}.
- */
-public class WebsiteDataItem extends DataItem {
-
- /* package */ WebsiteDataItem(ContentValues values) {
- super(values);
- }
-
- public String getUrl() {
- return getContentValues().getAsString(Website.URL);
- }
-
- public String getLabel() {
- return getContentValues().getAsString(Website.LABEL);
- }
-}
diff --git a/src/com/android/contacts/quickcontact/DataAction.java b/src/com/android/contacts/quickcontact/DataAction.java
index 0e3495c..e29b3ef 100644
--- a/src/com/android/contacts/quickcontact/DataAction.java
+++ b/src/com/android/contacts/quickcontact/DataAction.java
@@ -30,18 +30,18 @@
import android.util.Log;
import com.android.contacts.common.CallUtil;
-import com.android.contacts.ContactsUtils;
+import com.android.contacts.common.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.common.MoreContactUtils;
import com.android.contacts.common.model.account.AccountType.EditType;
-import com.android.contacts.model.dataitem.DataItem;
+import com.android.contacts.common.model.dataitem.DataItem;
import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.model.dataitem.EmailDataItem;
-import com.android.contacts.model.dataitem.ImDataItem;
-import com.android.contacts.model.dataitem.PhoneDataItem;
-import com.android.contacts.model.dataitem.SipAddressDataItem;
-import com.android.contacts.model.dataitem.StructuredPostalDataItem;
-import com.android.contacts.model.dataitem.WebsiteDataItem;
+import com.android.contacts.common.model.dataitem.EmailDataItem;
+import com.android.contacts.common.model.dataitem.ImDataItem;
+import com.android.contacts.common.model.dataitem.PhoneDataItem;
+import com.android.contacts.common.model.dataitem.SipAddressDataItem;
+import com.android.contacts.common.model.dataitem.StructuredPostalDataItem;
+import com.android.contacts.common.model.dataitem.WebsiteDataItem;
import com.android.contacts.util.PhoneCapabilityTester;
import com.android.contacts.util.StructuredPostalUtils;
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index c7d6e51..0ff7a8d 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -63,17 +63,17 @@
import com.android.contacts.common.Collapser;
import com.android.contacts.R;
import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.model.Contact;
-import com.android.contacts.model.ContactLoader;
-import com.android.contacts.model.RawContact;
+import com.android.contacts.common.model.Contact;
+import com.android.contacts.common.model.ContactLoader;
+import com.android.contacts.common.model.RawContact;
import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.model.dataitem.DataItem;
+import com.android.contacts.common.model.dataitem.DataItem;
import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.model.dataitem.EmailDataItem;
-import com.android.contacts.model.dataitem.ImDataItem;
+import com.android.contacts.common.model.dataitem.EmailDataItem;
+import com.android.contacts.common.model.dataitem.ImDataItem;
import com.android.contacts.common.util.Constants;
+import com.android.contacts.common.util.DataStatus;
import com.android.contacts.common.util.UriUtils;
-import com.android.contacts.util.DataStatus;
import com.android.contacts.util.ImageViewDrawableSetter;
import com.android.contacts.util.SchedulingUtils;
import com.android.contacts.common.util.StopWatch;
diff --git a/src/com/android/contacts/test/InjectedServices.java b/src/com/android/contacts/test/InjectedServices.java
deleted file mode 100644
index 4dd955f..0000000
--- a/src/com/android/contacts/test/InjectedServices.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 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.test;
-
-import android.content.ContentResolver;
-import android.content.SharedPreferences;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Maps;
-
-import java.util.HashMap;
-
-/**
- * A mechanism for providing alternative (mock) services to the application
- * while running tests. Activities, Services and the Application should check
- * with this class to see if a particular service has been overridden.
- */
-public class InjectedServices {
-
- private ContentResolver mContentResolver;
- private SharedPreferences mSharedPreferences;
- private HashMap<String, Object> mSystemServices;
-
- @VisibleForTesting
- public void setContentResolver(ContentResolver contentResolver) {
- this.mContentResolver = contentResolver;
- }
-
- public ContentResolver getContentResolver() {
- return mContentResolver;
- }
-
- @VisibleForTesting
- public void setSharedPreferences(SharedPreferences sharedPreferences) {
- this.mSharedPreferences = sharedPreferences;
- }
-
- public SharedPreferences getSharedPreferences() {
- return mSharedPreferences;
- }
-
- @VisibleForTesting
- public void setSystemService(String name, Object service) {
- if (mSystemServices == null) {
- mSystemServices = Maps.newHashMap();
- }
-
- mSystemServices.put(name, service);
- }
-
- public Object getSystemService(String name) {
- if (mSystemServices != null) {
- return mSystemServices.get(name);
- }
- return null;
- }
-}
diff --git a/src/com/android/contacts/util/ContactBadgeUtil.java b/src/com/android/contacts/util/ContactBadgeUtil.java
index fa1a60c..82a6820 100644
--- a/src/com/android/contacts/util/ContactBadgeUtil.java
+++ b/src/com/android/contacts/util/ContactBadgeUtil.java
@@ -27,6 +27,7 @@
import android.util.Log;
import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.R;
/**
diff --git a/src/com/android/contacts/util/ContactLoaderUtils.java b/src/com/android/contacts/util/ContactLoaderUtils.java
deleted file mode 100644
index 91c683f..0000000
--- a/src/com/android/contacts/util/ContactLoaderUtils.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2011 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.util;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.net.Uri;
-import android.provider.Contacts;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.RawContacts;
-
-/**
- * Utility methods for the {@link ContactLoader}.
- */
-public final class ContactLoaderUtils {
-
- /** Static helper, not instantiable. */
- private ContactLoaderUtils() {}
-
- /**
- * Transforms the given Uri and returns a Lookup-Uri that represents the contact.
- * For legacy contacts, a raw-contact lookup is performed. An {@link IllegalArgumentException}
- * can be thrown if the URI is null or the authority is not recognized.
- *
- * Do not call from the UI thread.
- */
- @SuppressWarnings("deprecation")
- public static Uri ensureIsContactUri(final ContentResolver resolver, final Uri uri)
- throws IllegalArgumentException {
- if (uri == null) throw new IllegalArgumentException("uri must not be null");
-
- final String authority = uri.getAuthority();
-
- // Current Style Uri?
- if (ContactsContract.AUTHORITY.equals(authority)) {
- final String type = resolver.getType(uri);
- // Contact-Uri? Good, return it
- if (ContactsContract.Contacts.CONTENT_ITEM_TYPE.equals(type)) {
- return uri;
- }
-
- // RawContact-Uri? Transform it to ContactUri
- if (RawContacts.CONTENT_ITEM_TYPE.equals(type)) {
- final long rawContactId = ContentUris.parseId(uri);
- return RawContacts.getContactLookupUri(resolver,
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
- }
-
- // Anything else? We don't know what this is
- throw new IllegalArgumentException("uri format is unknown");
- }
-
- // Legacy Style? Convert to RawContact
- final String OBSOLETE_AUTHORITY = Contacts.AUTHORITY;
- if (OBSOLETE_AUTHORITY.equals(authority)) {
- // Legacy Format. Convert to RawContact-Uri and then lookup the contact
- final long rawContactId = ContentUris.parseId(uri);
- return RawContacts.getContactLookupUri(resolver,
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
- }
-
- throw new IllegalArgumentException("uri authority is unknown");
- }
-}
diff --git a/src/com/android/contacts/util/DataStatus.java b/src/com/android/contacts/util/DataStatus.java
deleted file mode 100644
index f267615..0000000
--- a/src/com/android/contacts/util/DataStatus.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2009 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.util;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.graphics.drawable.Drawable;
-import android.provider.ContactsContract.Data;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-
-import com.android.contacts.R;
-
-/**
- * Storage for a social status update. Holds a single update, but can use
- * {@link #possibleUpdate(Cursor)} to consider updating when a better status
- * exists. Statuses with timestamps, or with newer timestamps win.
- */
-public class DataStatus {
- private int mPresence = -1;
- private String mStatus = null;
- private long mTimestamp = -1;
-
- private String mResPackage = null;
- private int mIconRes = -1;
- private int mLabelRes = -1;
-
- public DataStatus() {
- }
-
- public DataStatus(Cursor cursor) {
- // When creating from cursor row, fill normally
- fromCursor(cursor);
- }
-
- /**
- * Attempt updating this {@link DataStatus} based on values at the
- * current row of the given {@link Cursor}.
- */
- public void possibleUpdate(Cursor cursor) {
- final boolean hasStatus = !isNull(cursor, Data.STATUS);
- final boolean hasTimestamp = !isNull(cursor, Data.STATUS_TIMESTAMP);
-
- // Bail early when not valid status, or when previous status was
- // found and we can't compare this one.
- if (!hasStatus) return;
- if (isValid() && !hasTimestamp) return;
-
- if (hasTimestamp) {
- // Compare timestamps and bail if older status
- final long newTimestamp = getLong(cursor, Data.STATUS_TIMESTAMP, -1);
- if (newTimestamp < mTimestamp) return;
-
- mTimestamp = newTimestamp;
- }
-
- // Fill in remaining details from cursor
- fromCursor(cursor);
- }
-
- private void fromCursor(Cursor cursor) {
- mPresence = getInt(cursor, Data.PRESENCE, -1);
- mStatus = getString(cursor, Data.STATUS);
- mTimestamp = getLong(cursor, Data.STATUS_TIMESTAMP, -1);
- mResPackage = getString(cursor, Data.STATUS_RES_PACKAGE);
- mIconRes = getInt(cursor, Data.STATUS_ICON, -1);
- mLabelRes = getInt(cursor, Data.STATUS_LABEL, -1);
- }
-
- public boolean isValid() {
- return !TextUtils.isEmpty(mStatus);
- }
-
- public int getPresence() {
- return mPresence;
- }
-
- public CharSequence getStatus() {
- return mStatus;
- }
-
- public long getTimestamp() {
- return mTimestamp;
- }
-
- /**
- * Build any timestamp and label into a single string.
- */
- public CharSequence getTimestampLabel(Context context) {
- final PackageManager pm = context.getPackageManager();
-
- // Use local package for resources when none requested
- if (mResPackage == null) mResPackage = context.getPackageName();
-
- final boolean validTimestamp = mTimestamp > 0;
- final boolean validLabel = mResPackage != null && mLabelRes != -1;
-
- final CharSequence timeClause = validTimestamp ? DateUtils.getRelativeTimeSpanString(
- mTimestamp, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,
- DateUtils.FORMAT_ABBREV_RELATIVE) : null;
- final CharSequence labelClause = validLabel ? pm.getText(mResPackage, mLabelRes,
- null) : null;
-
- if (validTimestamp && validLabel) {
- return context.getString(
- R.string.contact_status_update_attribution_with_date,
- timeClause, labelClause);
- } else if (validLabel) {
- return context.getString(
- R.string.contact_status_update_attribution,
- labelClause);
- } else if (validTimestamp) {
- return timeClause;
- } else {
- return null;
- }
- }
-
- public Drawable getIcon(Context context) {
- final PackageManager pm = context.getPackageManager();
-
- // Use local package for resources when none requested
- if (mResPackage == null) mResPackage = context.getPackageName();
-
- final boolean validIcon = mResPackage != null && mIconRes != -1;
- return validIcon ? pm.getDrawable(mResPackage, mIconRes, null) : null;
- }
-
- private static String getString(Cursor cursor, String columnName) {
- return cursor.getString(cursor.getColumnIndex(columnName));
- }
-
- private static int getInt(Cursor cursor, String columnName) {
- return cursor.getInt(cursor.getColumnIndex(columnName));
- }
-
- private static int getInt(Cursor cursor, String columnName, int missingValue) {
- final int columnIndex = cursor.getColumnIndex(columnName);
- return cursor.isNull(columnIndex) ? missingValue : cursor.getInt(columnIndex);
- }
-
- private static long getLong(Cursor cursor, String columnName, long missingValue) {
- final int columnIndex = cursor.getColumnIndex(columnName);
- return cursor.isNull(columnIndex) ? missingValue : cursor.getLong(columnIndex);
- }
-
- private static boolean isNull(Cursor cursor, String columnName) {
- return cursor.isNull(cursor.getColumnIndex(columnName));
- }
-}
diff --git a/src/com/android/contacts/util/DateUtils.java b/src/com/android/contacts/util/DateUtils.java
deleted file mode 100644
index e20aadf..0000000
--- a/src/com/android/contacts/util/DateUtils.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2010 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.util;
-
-import android.content.Context;
-import android.text.format.DateFormat;
-
-import com.android.contacts.common.util.CommonDateUtils;
-
-import java.text.ParsePosition;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/**
- * Utility methods for processing dates.
- */
-public class DateUtils {
- public static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("UTC");
-
- /**
- * When parsing a date without a year, the system assumes 1970, which wasn't a leap-year.
- * Let's add a one-off hack for that day of the year
- */
- public static final String NO_YEAR_DATE_FEB29TH = "--02-29";
-
- // Variations of ISO 8601 date format. Do not change the order - it does affect the
- // result in ambiguous cases.
- private static final SimpleDateFormat[] DATE_FORMATS = {
- CommonDateUtils.FULL_DATE_FORMAT,
- CommonDateUtils.DATE_AND_TIME_FORMAT,
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.US),
- new SimpleDateFormat("yyyyMMdd", Locale.US),
- new SimpleDateFormat("yyyyMMdd'T'HHmmssSSS'Z'", Locale.US),
- new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US),
- new SimpleDateFormat("yyyyMMdd'T'HHmm'Z'", Locale.US),
- };
-
- static {
- for (SimpleDateFormat format : DATE_FORMATS) {
- format.setLenient(true);
- format.setTimeZone(UTC_TIMEZONE);
- }
- CommonDateUtils.NO_YEAR_DATE_FORMAT.setTimeZone(UTC_TIMEZONE);
- }
-
- /**
- * Parses the supplied string to see if it looks like a date.
- *
- * @param string The string representation of the provided date
- * @param mustContainYear If true, the string is parsed as a date containing a year. If false,
- * the string is parsed into a valid date even if the year field is missing.
- * @return A Calendar object corresponding to the date if the string is successfully parsed.
- * If not, null is returned.
- */
- public static Calendar parseDate(String string, boolean mustContainYear) {
- ParsePosition parsePosition = new ParsePosition(0);
- Date date;
- if (!mustContainYear) {
- final boolean noYearParsed;
- // Unfortunately, we can't parse Feb 29th correctly, so let's handle this day seperately
- if (NO_YEAR_DATE_FEB29TH.equals(string)) {
- return getUtcDate(0, Calendar.FEBRUARY, 29);
- } else {
- synchronized (CommonDateUtils.NO_YEAR_DATE_FORMAT) {
- date = CommonDateUtils.NO_YEAR_DATE_FORMAT.parse(string, parsePosition);
- }
- noYearParsed = parsePosition.getIndex() == string.length();
- }
-
- if (noYearParsed) {
- return getUtcDate(date, true);
- }
- }
- for (int i = 0; i < DATE_FORMATS.length; i++) {
- SimpleDateFormat f = DATE_FORMATS[i];
- synchronized (f) {
- parsePosition.setIndex(0);
- date = f.parse(string, parsePosition);
- if (parsePosition.getIndex() == string.length()) {
- return getUtcDate(date, false);
- }
- }
- }
- return null;
- }
-
- private static final Calendar getUtcDate(Date date, boolean noYear) {
- final Calendar calendar = Calendar.getInstance(UTC_TIMEZONE, Locale.US);
- calendar.setTime(date);
- if (noYear) {
- calendar.set(Calendar.YEAR, 0);
- }
- return calendar;
- }
-
- private static final Calendar getUtcDate(int year, int month, int dayOfMonth) {
- final Calendar calendar = Calendar.getInstance(UTC_TIMEZONE, Locale.US);
- calendar.clear();
- calendar.set(Calendar.YEAR, year);
- calendar.set(Calendar.MONTH, month);
- calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
- return calendar;
- }
-
- public static boolean isYearSet(Calendar cal) {
- // use the Calendar.YEAR field to track whether or not the year is set instead of
- // Calendar.isSet() because doing Calendar.get() causes Calendar.isSet() to become
- // true irregardless of what the previous value was
- return cal.get(Calendar.YEAR) > 1;
- }
-
- /**
- * Same as {@link #formatDate(Context context, String string, boolean longForm)}, with
- * longForm set to {@code true} by default.
- *
- * @param context Valid context
- * @param string String representation of a date to parse
- * @return Returns the same date in a cleaned up format. If the supplied string does not look
- * like a date, return it unchanged.
- */
-
- public static String formatDate(Context context, String string) {
- return formatDate(context, string, true);
- }
-
- /**
- * Parses the supplied string to see if it looks like a date.
- *
- * @param context Valid context
- * @param string String representation of a date to parse
- * @param longForm If true, return the date formatted into its long string representation.
- * If false, return the date formatted using its short form representation (i.e. 12/11/2012)
- * @return Returns the same date in a cleaned up format. If the supplied string does not look
- * like a date, return it unchanged.
- */
- public static String formatDate(Context context, String string, boolean longForm) {
- if (string == null) {
- return null;
- }
-
- string = string.trim();
- if (string.length() == 0) {
- return string;
- }
- final Calendar cal = parseDate(string, false);
-
- // we weren't able to parse the string successfully so just return it unchanged
- if (cal == null) {
- return string;
- }
-
- final boolean isYearSet = isYearSet(cal);
- final java.text.DateFormat outFormat;
- if (!isYearSet) {
- outFormat = getLocalizedDateFormatWithoutYear(context);
- } else {
- outFormat =
- longForm ? DateFormat.getLongDateFormat(context) :
- DateFormat.getDateFormat(context);
- }
- synchronized (outFormat) {
- outFormat.setTimeZone(UTC_TIMEZONE);
- return outFormat.format(cal.getTime());
- }
- }
-
- public static boolean isMonthBeforeDay(Context context) {
- char[] dateFormatOrder = DateFormat.getDateFormatOrder(context);
- for (int i = 0; i < dateFormatOrder.length; i++) {
- if (dateFormatOrder[i] == DateFormat.DATE) {
- return false;
- }
- if (dateFormatOrder[i] == DateFormat.MONTH) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns a SimpleDateFormat object without the year fields by using a regular expression
- * to eliminate the year in the string pattern. In the rare occurence that the resulting
- * pattern cannot be reconverted into a SimpleDateFormat, it uses the provided context to
- * determine whether the month field should be displayed before the day field, and returns
- * either "MMMM dd" or "dd MMMM" converted into a SimpleDateFormat.
- */
- public static java.text.DateFormat getLocalizedDateFormatWithoutYear(Context context) {
- final String pattern = ((SimpleDateFormat) SimpleDateFormat.getDateInstance(
- java.text.DateFormat.LONG)).toPattern();
- // Determine the correct regex pattern for year.
- // Special case handling for Spanish locale by checking for "de"
- final String yearPattern = pattern.contains(
- "de") ? "[^Mm]*[Yy]+[^Mm]*" : "[^DdMm]*[Yy]+[^DdMm]*";
- try {
- // Eliminate the substring in pattern that matches the format for that of year
- return new SimpleDateFormat(pattern.replaceAll(yearPattern, ""));
- } catch (IllegalArgumentException e) {
- return new SimpleDateFormat(
- DateUtils.isMonthBeforeDay(context) ? "MMMM dd" : "dd MMMM");
- }
- }
-
- /**
- * Given a calendar (possibly containing only a day of the year), returns the earliest possible
- * anniversary of the date that is equal to or after the current point in time if the date
- * does not contain a year, or the date converted to the local time zone (if the date contains
- * a year.
- *
- * @param target The date we wish to convert(in the UTC time zone).
- * @return If date does not contain a year (year < 1900), returns the next earliest anniversary
- * that is after the current point in time (in the local time zone). Otherwise, returns the
- * adjusted Date in the local time zone.
- */
- public static Date getNextAnnualDate(Calendar target) {
- final Calendar today = Calendar.getInstance();
- today.setTime(new Date());
-
- // Round the current time to the exact start of today so that when we compare
- // today against the target date, both dates are set to exactly 0000H.
- today.set(Calendar.HOUR_OF_DAY, 0);
- today.set(Calendar.MINUTE, 0);
- today.set(Calendar.SECOND, 0);
- today.set(Calendar.MILLISECOND, 0);
-
- final boolean isYearSet = isYearSet(target);
- final int targetYear = target.get(Calendar.YEAR);
- final int targetMonth = target.get(Calendar.MONTH);
- final int targetDay = target.get(Calendar.DAY_OF_MONTH);
- final boolean isFeb29 = (targetMonth == Calendar.FEBRUARY && targetDay == 29);
- final GregorianCalendar anniversary = new GregorianCalendar();
- // Convert from the UTC date to the local date. Set the year to today's year if the
- // there is no provided year (targetYear < 1900)
- anniversary.set(!isYearSet ? today.get(Calendar.YEAR) : targetYear,
- targetMonth, targetDay);
- // If the anniversary's date is before the start of today and there is no year set,
- // increment the year by 1 so that the returned date is always equal to or greater than
- // today. If the day is a leap year, keep going until we get the next leap year anniversary
- // Otherwise if there is already a year set, simply return the exact date.
- if (!isYearSet) {
- int anniversaryYear = today.get(Calendar.YEAR);
- if (anniversary.before(today) ||
- (isFeb29 && !anniversary.isLeapYear(anniversaryYear))) {
- // If the target date is not Feb 29, then set the anniversary to the next year.
- // Otherwise, keep going until we find the next leap year (this is not guaranteed
- // to be in 4 years time).
- do {
- anniversaryYear +=1;
- } while (isFeb29 && !anniversary.isLeapYear(anniversaryYear));
- anniversary.set(anniversaryYear, targetMonth, targetDay);
- }
- }
- return anniversary.getTime();
- }
-}
diff --git a/src/com/android/contacts/util/HtmlUtils.java b/src/com/android/contacts/util/HtmlUtils.java
index cea300e..edcda13 100644
--- a/src/com/android/contacts/util/HtmlUtils.java
+++ b/src/com/android/contacts/util/HtmlUtils.java
@@ -35,6 +35,7 @@
* Specifically, it adjusts the color and padding of the vertical
* stripe on block quotes and alignment of inlined images.
*/
+@VisibleForTesting
public class HtmlUtils {
/**
diff --git a/src/com/android/contacts/util/ImageViewDrawableSetter.java b/src/com/android/contacts/util/ImageViewDrawableSetter.java
index 91ecd61..a189f58 100644
--- a/src/com/android/contacts/util/ImageViewDrawableSetter.java
+++ b/src/com/android/contacts/util/ImageViewDrawableSetter.java
@@ -27,7 +27,7 @@
import android.widget.ImageView;
import com.android.contacts.common.ContactPhotoManager;
-import com.android.contacts.model.Contact;
+import com.android.contacts.common.model.Contact;
import java.util.Arrays;
diff --git a/src/com/android/contacts/util/NameConverter.java b/src/com/android/contacts/util/NameConverter.java
deleted file mode 100644
index 9853821..0000000
--- a/src/com/android/contacts/util/NameConverter.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2011 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.util;
-
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.net.Uri.Builder;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.text.TextUtils;
-
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * Utility class for converting between a display name and structured name (and vice-versa), via
- * calls to the contact provider.
- */
-public class NameConverter {
-
- /**
- * The array of fields that comprise a structured name.
- */
- public static final String[] STRUCTURED_NAME_FIELDS = new String[] {
- StructuredName.PREFIX,
- StructuredName.GIVEN_NAME,
- StructuredName.MIDDLE_NAME,
- StructuredName.FAMILY_NAME,
- StructuredName.SUFFIX
- };
-
- /**
- * Converts the given structured name (provided as a map from {@link StructuredName} fields to
- * corresponding values) into a display name string.
- * <p>
- * Note that this operates via a call back to the ContactProvider, but it does not access the
- * database, so it should be safe to call from the UI thread. See
- * ContactsProvider2.completeName() for the underlying method call.
- * @param context Activity context.
- * @param structuredName The structured name map to convert.
- * @return The display name computed from the structured name map.
- */
- public static String structuredNameToDisplayName(Context context,
- Map<String, String> structuredName) {
- Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name");
- for (String key : STRUCTURED_NAME_FIELDS) {
- if (structuredName.containsKey(key)) {
- appendQueryParameter(builder, key, structuredName.get(key));
- }
- }
- return fetchDisplayName(context, builder.build());
- }
-
- /**
- * Converts the given structured name (provided as ContentValues) into a display name string.
- * @param context Activity context.
- * @param values The content values containing values comprising the structured name.
- * @return
- */
- public static String structuredNameToDisplayName(Context context, ContentValues values) {
- Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name");
- for (String key : STRUCTURED_NAME_FIELDS) {
- if (values.containsKey(key)) {
- appendQueryParameter(builder, key, values.getAsString(key));
- }
- }
- return fetchDisplayName(context, builder.build());
- }
-
- /**
- * Helper method for fetching the display name via the given URI.
- */
- private static String fetchDisplayName(Context context, Uri uri) {
- String displayName = null;
- Cursor cursor = context.getContentResolver().query(uri, new String[]{
- StructuredName.DISPLAY_NAME,
- }, null, null, null);
-
- try {
- if (cursor.moveToFirst()) {
- displayName = cursor.getString(0);
- }
- } finally {
- cursor.close();
- }
- return displayName;
- }
-
- /**
- * Converts the given display name string into a structured name (as a map from
- * {@link StructuredName} fields to corresponding values).
- * <p>
- * Note that this operates via a call back to the ContactProvider, but it does not access the
- * database, so it should be safe to call from the UI thread.
- * @param context Activity context.
- * @param displayName The display name to convert.
- * @return The structured name map computed from the display name.
- */
- public static Map<String, String> displayNameToStructuredName(Context context,
- String displayName) {
- Map<String, String> structuredName = new TreeMap<String, String>();
- Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name");
-
- appendQueryParameter(builder, StructuredName.DISPLAY_NAME, displayName);
- Cursor cursor = context.getContentResolver().query(builder.build(), STRUCTURED_NAME_FIELDS,
- null, null, null);
-
- try {
- if (cursor.moveToFirst()) {
- for (int i = 0; i < STRUCTURED_NAME_FIELDS.length; i++) {
- structuredName.put(STRUCTURED_NAME_FIELDS[i], cursor.getString(i));
- }
- }
- } finally {
- cursor.close();
- }
- return structuredName;
- }
-
- /**
- * Converts the given display name string into a structured name (inserting the structured
- * values into a new or existing ContentValues object).
- * <p>
- * Note that this operates via a call back to the ContactProvider, but it does not access the
- * database, so it should be safe to call from the UI thread.
- * @param context Activity context.
- * @param displayName The display name to convert.
- * @param contentValues The content values object to place the structured name values into. If
- * null, a new one will be created and returned.
- * @return The ContentValues object containing the structured name fields derived from the
- * display name.
- */
- public static ContentValues displayNameToStructuredName(Context context, String displayName,
- ContentValues contentValues) {
- if (contentValues == null) {
- contentValues = new ContentValues();
- }
- Map<String, String> mapValues = displayNameToStructuredName(context, displayName);
- for (String key : mapValues.keySet()) {
- contentValues.put(key, mapValues.get(key));
- }
- return contentValues;
- }
-
- private static void appendQueryParameter(Builder builder, String field, String value) {
- if (!TextUtils.isEmpty(value)) {
- builder.appendQueryParameter(field, value);
- }
- }
-}
diff --git a/src/com/android/contacts/util/StreamItemEntry.java b/src/com/android/contacts/util/StreamItemEntry.java
index 2332c0e..e5696a1 100644
--- a/src/com/android/contacts/util/StreamItemEntry.java
+++ b/src/com/android/contacts/util/StreamItemEntry.java
@@ -24,6 +24,8 @@
import com.android.contacts.detail.ContactDetailDisplayUtils;
import com.android.contacts.common.test.NeededForTesting;
+import com.google.common.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -156,6 +158,7 @@
*
* We can't do this automatically in the getters, because it'll require a {@link Context}.
*/
+ @VisibleForTesting
public void decodeHtml(Context context) {
final Html.ImageGetter imageGetter = ContactDetailDisplayUtils.getImageGetter(context);
if (mText != null) {
diff --git a/tests/src/com/android/contacts/ContactsUtilsTests.java b/tests/src/com/android/contacts/ContactsUtilsTests.java
deleted file mode 100644
index e8f05e0..0000000
--- a/tests/src/com/android/contacts/ContactsUtilsTests.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 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;
-
-import android.content.Intent;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.contacts.common.MoreContactUtils;
-
-/**
- * Tests for {@link ContactsUtils}.
- */
-@SmallTest
-public class ContactsUtilsTests extends AndroidTestCase {
-
- public void testIsGraphicNull() throws Exception {
- assertFalse(ContactsUtils.isGraphic(null));
- }
-
- public void testIsGraphicEmpty() throws Exception {
- assertFalse(ContactsUtils.isGraphic(""));
- }
-
- public void testIsGraphicSpaces() throws Exception {
- assertFalse(ContactsUtils.isGraphic(" "));
- }
-
- public void testIsGraphicPunctuation() throws Exception {
- assertTrue(ContactsUtils.isGraphic("."));
- }
-
- public void testAreObjectsEqual() throws Exception {
- assertTrue("null:null", ContactsUtils.areObjectsEqual(null, null));
- assertTrue("1:1", ContactsUtils.areObjectsEqual(1, 1));
-
- assertFalse("null:1", ContactsUtils.areObjectsEqual(null, 1));
- assertFalse("1:null", ContactsUtils.areObjectsEqual(1, null));
- assertFalse("1:2", ContactsUtils.areObjectsEqual(1, 2));
- }
-
- public void testAreIntentActionEqual() throws Exception {
- assertTrue("1", ContactsUtils.areIntentActionEqual(null, null));
- assertTrue("1", ContactsUtils.areIntentActionEqual(new Intent("a"), new Intent("a")));
-
- assertFalse("11", ContactsUtils.areIntentActionEqual(new Intent("a"), null));
- assertFalse("12", ContactsUtils.areIntentActionEqual(null, new Intent("a")));
-
- assertFalse("21", ContactsUtils.areIntentActionEqual(new Intent("a"), new Intent()));
- assertFalse("22", ContactsUtils.areIntentActionEqual(new Intent(), new Intent("b")));
- assertFalse("23", ContactsUtils.areIntentActionEqual(new Intent("a"), new Intent("b")));
- }
-}
diff --git a/tests/src/com/android/contacts/RawContactDeltaListTests.java b/tests/src/com/android/contacts/RawContactDeltaListTests.java
deleted file mode 100644
index 6a75b81..0000000
--- a/tests/src/com/android/contacts/RawContactDeltaListTests.java
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Copyright (C) 2009 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;
-
-import static android.content.ContentProviderOperation.TYPE_ASSERT;
-import static android.content.ContentProviderOperation.TYPE_DELETE;
-import static android.content.ContentProviderOperation.TYPE_INSERT;
-import static android.content.ContentProviderOperation.TYPE_UPDATE;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentValues;
-import android.content.Context;
-import android.net.Uri;
-import android.provider.BaseColumns;
-import android.provider.ContactsContract.AggregationExceptions;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import com.android.contacts.RawContactModifierTests.MockContactsSource;
-import com.android.contacts.model.RawContact;
-import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.model.RawContactDeltaList;
-import com.android.contacts.model.RawContactModifier;
-import com.android.contacts.common.model.account.AccountType;
-import com.google.common.collect.Lists;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-
-/**
- * Tests for {@link RawContactDeltaList} which focus on "diff" operations that should
- * create {@link AggregationExceptions} in certain cases.
- */
-@LargeTest
-public class RawContactDeltaListTests extends AndroidTestCase {
- public static final String TAG = RawContactDeltaListTests.class.getSimpleName();
-
- private static final long CONTACT_FIRST = 1;
- private static final long CONTACT_SECOND = 2;
-
- public static final long CONTACT_BOB = 10;
- public static final long CONTACT_MARY = 11;
-
- public static final long PHONE_RED = 20;
- public static final long PHONE_GREEN = 21;
- public static final long PHONE_BLUE = 22;
-
- public static final long EMAIL_YELLOW = 25;
-
- public static final long VER_FIRST = 100;
- public static final long VER_SECOND = 200;
-
- public static final String TEST_PHONE = "555-1212";
- public static final String TEST_ACCOUNT = "org.example.test";
-
- public RawContactDeltaListTests() {
- super();
- }
-
- @Override
- public void setUp() {
- mContext = getContext();
- }
-
- /**
- * Build a {@link AccountType} that has various odd constraints for
- * testing purposes.
- */
- protected AccountType getAccountType() {
- return new MockContactsSource();
- }
-
- static ContentValues getValues(ContentProviderOperation operation)
- throws NoSuchFieldException, IllegalAccessException {
- final Field field = ContentProviderOperation.class.getDeclaredField("mValues");
- field.setAccessible(true);
- return (ContentValues) field.get(operation);
- }
-
- static RawContactDelta getUpdate(Context context, long rawContactId) {
- final RawContact before = RawContactDeltaTests.getRawContact(context, rawContactId,
- RawContactDeltaTests.TEST_PHONE_ID);
- return RawContactDelta.fromBefore(before);
- }
-
- static RawContactDelta getInsert() {
- final ContentValues after = new ContentValues();
- after.put(RawContacts.ACCOUNT_NAME, RawContactDeltaTests.TEST_ACCOUNT_NAME);
- after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
-
- final ValuesDelta values = ValuesDelta.fromAfter(after);
- return new RawContactDelta(values);
- }
-
- static RawContactDeltaList buildSet(RawContactDelta... deltas) {
- final RawContactDeltaList set = new RawContactDeltaList();
- Collections.addAll(set, deltas);
- return set;
- }
-
- static RawContactDelta buildBeforeEntity(Context context, long rawContactId, long version,
- ContentValues... entries) {
- // Build an existing contact read from database
- final ContentValues contact = new ContentValues();
- contact.put(RawContacts.VERSION, version);
- contact.put(RawContacts._ID, rawContactId);
- final RawContact before = new RawContact(contact);
- for (ContentValues entry : entries) {
- before.addDataItemValues(entry);
- }
- return RawContactDelta.fromBefore(before);
- }
-
- static RawContactDelta buildAfterEntity(ContentValues... entries) {
- // Build an existing contact read from database
- final ContentValues contact = new ContentValues();
- contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT);
- final RawContactDelta after = new RawContactDelta(ValuesDelta.fromAfter(contact));
- for (ContentValues entry : entries) {
- after.addEntry(ValuesDelta.fromAfter(entry));
- }
- return after;
- }
-
- static ContentValues buildPhone(long phoneId) {
- return buildPhone(phoneId, Long.toString(phoneId));
- }
-
- static ContentValues buildPhone(long phoneId, String value) {
- final ContentValues values = new ContentValues();
- values.put(Data._ID, phoneId);
- values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- values.put(Phone.NUMBER, value);
- values.put(Phone.TYPE, Phone.TYPE_HOME);
- return values;
- }
-
- static ContentValues buildEmail(long emailId) {
- final ContentValues values = new ContentValues();
- values.put(Data._ID, emailId);
- values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
- values.put(Email.DATA, Long.toString(emailId));
- values.put(Email.TYPE, Email.TYPE_HOME);
- return values;
- }
-
- static void insertPhone(RawContactDeltaList set, long rawContactId, ContentValues values) {
- final RawContactDelta match = set.getByRawContactId(rawContactId);
- match.addEntry(ValuesDelta.fromAfter(values));
- }
-
- static ValuesDelta getPhone(RawContactDeltaList set, long rawContactId, long dataId) {
- final RawContactDelta match = set.getByRawContactId(rawContactId);
- return match.getEntry(dataId);
- }
-
- static void assertDiffPattern(RawContactDelta delta, ContentProviderOperation... pattern) {
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- delta.buildAssert(diff);
- delta.buildDiff(diff);
- assertDiffPattern(diff, pattern);
- }
-
- static void assertDiffPattern(RawContactDeltaList set, ContentProviderOperation... pattern) {
- assertDiffPattern(set.buildDiff(), pattern);
- }
-
- static void assertDiffPattern(ArrayList<ContentProviderOperation> diff,
- ContentProviderOperation... pattern) {
- assertEquals("Unexpected operations", pattern.length, diff.size());
- for (int i = 0; i < pattern.length; i++) {
- final ContentProviderOperation expected = pattern[i];
- final ContentProviderOperation found = diff.get(i);
-
- assertEquals("Unexpected uri", expected.getUri(), found.getUri());
-
- final String expectedType = getStringForType(expected.getType());
- final String foundType = getStringForType(found.getType());
- assertEquals("Unexpected type", expectedType, foundType);
-
- if (expected.getType() == TYPE_DELETE) continue;
-
- try {
- final ContentValues expectedValues = getValues(expected);
- final ContentValues foundValues = getValues(found);
-
- expectedValues.remove(BaseColumns._ID);
- foundValues.remove(BaseColumns._ID);
-
- assertEquals("Unexpected values", expectedValues, foundValues);
- } catch (NoSuchFieldException e) {
- fail(e.toString());
- } catch (IllegalAccessException e) {
- fail(e.toString());
- }
- }
- }
-
- static String getStringForType(int type) {
- switch (type) {
- case TYPE_ASSERT: return "TYPE_ASSERT";
- case TYPE_INSERT: return "TYPE_INSERT";
- case TYPE_UPDATE: return "TYPE_UPDATE";
- case TYPE_DELETE: return "TYPE_DELETE";
- default: return Integer.toString(type);
- }
- }
-
- static ContentProviderOperation buildAssertVersion(long version) {
- final ContentValues values = new ContentValues();
- values.put(RawContacts.VERSION, version);
- return buildOper(RawContacts.CONTENT_URI, TYPE_ASSERT, values);
- }
-
- static ContentProviderOperation buildAggregationModeUpdate(int mode) {
- final ContentValues values = new ContentValues();
- values.put(RawContacts.AGGREGATION_MODE, mode);
- return buildOper(RawContacts.CONTENT_URI, TYPE_UPDATE, values);
- }
-
- static ContentProviderOperation buildUpdateAggregationSuspended() {
- return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_SUSPENDED);
- }
-
- static ContentProviderOperation buildUpdateAggregationDefault() {
- return buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT);
- }
-
- static ContentProviderOperation buildUpdateAggregationKeepTogether(long rawContactId) {
- final ContentValues values = new ContentValues();
- values.put(AggregationExceptions.RAW_CONTACT_ID1, rawContactId);
- values.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
- return buildOper(AggregationExceptions.CONTENT_URI, TYPE_UPDATE, values);
- }
-
- static ContentValues buildDataInsert(ValuesDelta values, long rawContactId) {
- final ContentValues insertValues = values.getCompleteValues();
- insertValues.put(Data.RAW_CONTACT_ID, rawContactId);
- return insertValues;
- }
-
- static ContentProviderOperation buildDelete(Uri uri) {
- return buildOper(uri, TYPE_DELETE, (ContentValues)null);
- }
-
- static ContentProviderOperation buildOper(Uri uri, int type, ValuesDelta values) {
- return buildOper(uri, type, values.getCompleteValues());
- }
-
- static ContentProviderOperation buildOper(Uri uri, int type, ContentValues values) {
- switch (type) {
- case TYPE_ASSERT:
- return ContentProviderOperation.newAssertQuery(uri).withValues(values).build();
- case TYPE_INSERT:
- return ContentProviderOperation.newInsert(uri).withValues(values).build();
- case TYPE_UPDATE:
- return ContentProviderOperation.newUpdate(uri).withValues(values).build();
- case TYPE_DELETE:
- return ContentProviderOperation.newDelete(uri).build();
- }
- return null;
- }
-
- static Long getVersion(RawContactDeltaList set, Long rawContactId) {
- return set.getByRawContactId(rawContactId).getValues().getAsLong(RawContacts.VERSION);
- }
-
- /**
- * Count number of {@link AggregationExceptions} updates contained in the
- * given list of {@link ContentProviderOperation}.
- */
- static int countExceptionUpdates(ArrayList<ContentProviderOperation> diff) {
- int updateCount = 0;
- for (ContentProviderOperation oper : diff) {
- if (AggregationExceptions.CONTENT_URI.equals(oper.getUri())
- && oper.getType() == ContentProviderOperation.TYPE_UPDATE) {
- updateCount++;
- }
- }
- return updateCount;
- }
-
- public void testInsert() {
- final RawContactDelta insert = getInsert();
- final RawContactDeltaList set = buildSet(insert);
-
- // Inserting single shouldn't create rules
- final ArrayList<ContentProviderOperation> diff = set.buildDiff();
- final int exceptionCount = countExceptionUpdates(diff);
- assertEquals("Unexpected exception updates", 0, exceptionCount);
- }
-
- public void testUpdateUpdate() {
- final RawContactDelta updateFirst = getUpdate(mContext, CONTACT_FIRST);
- final RawContactDelta updateSecond = getUpdate(mContext, CONTACT_SECOND);
- final RawContactDeltaList set = buildSet(updateFirst, updateSecond);
-
- // Updating two existing shouldn't create rules
- final ArrayList<ContentProviderOperation> diff = set.buildDiff();
- final int exceptionCount = countExceptionUpdates(diff);
- assertEquals("Unexpected exception updates", 0, exceptionCount);
- }
-
- public void testUpdateInsert() {
- final RawContactDelta update = getUpdate(mContext, CONTACT_FIRST);
- final RawContactDelta insert = getInsert();
- final RawContactDeltaList set = buildSet(update, insert);
-
- // New insert should only create one rule
- final ArrayList<ContentProviderOperation> diff = set.buildDiff();
- final int exceptionCount = countExceptionUpdates(diff);
- assertEquals("Unexpected exception updates", 1, exceptionCount);
- }
-
- public void testInsertUpdateInsert() {
- final RawContactDelta insertFirst = getInsert();
- final RawContactDelta update = getUpdate(mContext, CONTACT_FIRST);
- final RawContactDelta insertSecond = getInsert();
- final RawContactDeltaList set = buildSet(insertFirst, update, insertSecond);
-
- // Two inserts should create two rules to bind against single existing
- final ArrayList<ContentProviderOperation> diff = set.buildDiff();
- final int exceptionCount = countExceptionUpdates(diff);
- assertEquals("Unexpected exception updates", 2, exceptionCount);
- }
-
- public void testInsertInsertInsert() {
- final RawContactDelta insertFirst = getInsert();
- final RawContactDelta insertSecond = getInsert();
- final RawContactDelta insertThird = getInsert();
- final RawContactDeltaList set = buildSet(insertFirst, insertSecond, insertThird);
-
- // Three new inserts should create only two binding rules
- final ArrayList<ContentProviderOperation> diff = set.buildDiff();
- final int exceptionCount = countExceptionUpdates(diff);
- assertEquals("Unexpected exception updates", 2, exceptionCount);
- }
-
- public void testMergeDataRemoteInsert() {
- final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_FIRST, buildPhone(PHONE_RED)));
- final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
-
- // Merge in second version, verify they match
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertEquals("Unexpected change when merging", second, merged);
- }
-
- public void testMergeDataLocalUpdateRemoteInsert() {
- final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_FIRST, buildPhone(PHONE_RED)));
- final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
-
- // Change the local number to trigger update
- final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
- phone.put(Phone.NUMBER, TEST_PHONE);
-
- assertDiffPattern(first,
- buildAssertVersion(VER_FIRST),
- buildUpdateAggregationSuspended(),
- buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
- buildUpdateAggregationDefault());
-
- // Merge in the second version, verify diff matches
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertDiffPattern(merged,
- buildAssertVersion(VER_SECOND),
- buildUpdateAggregationSuspended(),
- buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
- buildUpdateAggregationDefault());
- }
-
- public void testMergeDataLocalUpdateRemoteDelete() {
- final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_FIRST, buildPhone(PHONE_RED)));
- final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_SECOND, buildPhone(PHONE_GREEN)));
-
- // Change the local number to trigger update
- final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
- phone.put(Phone.NUMBER, TEST_PHONE);
-
- assertDiffPattern(first,
- buildAssertVersion(VER_FIRST),
- buildUpdateAggregationSuspended(),
- buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
- buildUpdateAggregationDefault());
-
- // Merge in the second version, verify that our update changed to
- // insert, since RED was deleted on remote side
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertDiffPattern(merged,
- buildAssertVersion(VER_SECOND),
- buildUpdateAggregationSuspended(),
- buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(phone, CONTACT_BOB)),
- buildUpdateAggregationDefault());
- }
-
- public void testMergeDataLocalDeleteRemoteUpdate() {
- final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_FIRST, buildPhone(PHONE_RED)));
- final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_SECOND, buildPhone(PHONE_RED, TEST_PHONE)));
-
- // Delete phone locally
- final ValuesDelta phone = getPhone(first, CONTACT_BOB, PHONE_RED);
- phone.markDeleted();
-
- assertDiffPattern(first,
- buildAssertVersion(VER_FIRST),
- buildUpdateAggregationSuspended(),
- buildDelete(Data.CONTENT_URI),
- buildUpdateAggregationDefault());
-
- // Merge in the second version, verify that our delete remains
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertDiffPattern(merged,
- buildAssertVersion(VER_SECOND),
- buildUpdateAggregationSuspended(),
- buildDelete(Data.CONTENT_URI),
- buildUpdateAggregationDefault());
- }
-
- public void testMergeDataLocalInsertRemoteInsert() {
- final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_FIRST, buildPhone(PHONE_RED)));
- final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_SECOND, buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
-
- // Insert new phone locally
- final ValuesDelta bluePhone = ValuesDelta.fromAfter(buildPhone(PHONE_BLUE));
- first.getByRawContactId(CONTACT_BOB).addEntry(bluePhone);
- assertDiffPattern(first,
- buildAssertVersion(VER_FIRST),
- buildUpdateAggregationSuspended(),
- buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
- buildUpdateAggregationDefault());
-
- // Merge in the second version, verify that our insert remains
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertDiffPattern(merged,
- buildAssertVersion(VER_SECOND),
- buildUpdateAggregationSuspended(),
- buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bluePhone, CONTACT_BOB)),
- buildUpdateAggregationDefault());
- }
-
- public void testMergeRawContactLocalInsertRemoteInsert() {
- final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_FIRST, buildPhone(PHONE_RED)));
- final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_SECOND, buildPhone(PHONE_RED)), buildBeforeEntity(mContext, CONTACT_MARY,
- VER_SECOND, buildPhone(PHONE_RED)));
-
- // Add new contact locally, should remain insert
- final ContentValues joePhoneInsert = buildPhone(PHONE_BLUE);
- final RawContactDelta joeContact = buildAfterEntity(joePhoneInsert);
- final ContentValues joeContactInsert = joeContact.getValues().getCompleteValues();
- joeContactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
- first.add(joeContact);
- assertDiffPattern(first,
- buildAssertVersion(VER_FIRST),
- buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
- buildOper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
- buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
- buildUpdateAggregationKeepTogether(CONTACT_BOB));
-
- // Merge in the second version, verify that our insert remains
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertDiffPattern(merged,
- buildAssertVersion(VER_SECOND),
- buildAssertVersion(VER_SECOND),
- buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, joeContactInsert),
- buildOper(Data.CONTENT_URI, TYPE_INSERT, joePhoneInsert),
- buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
- buildUpdateAggregationKeepTogether(CONTACT_BOB));
- }
-
- public void testMergeRawContactLocalDeleteRemoteDelete() {
- final RawContactDeltaList first = buildSet(
- buildBeforeEntity(mContext, CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
- buildBeforeEntity(mContext, CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
- final RawContactDeltaList second = buildSet(
- buildBeforeEntity(mContext, CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
-
- // Remove contact locally
- first.getByRawContactId(CONTACT_MARY).markDeleted();
- assertDiffPattern(first,
- buildAssertVersion(VER_FIRST),
- buildAssertVersion(VER_FIRST),
- buildDelete(RawContacts.CONTENT_URI));
-
- // Merge in the second version, verify that our delete isn't needed
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertDiffPattern(merged);
- }
-
- public void testMergeRawContactLocalUpdateRemoteDelete() {
- final RawContactDeltaList first = buildSet(
- buildBeforeEntity(mContext, CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
- buildBeforeEntity(mContext, CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
- final RawContactDeltaList second = buildSet(
- buildBeforeEntity(mContext, CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
-
- // Perform local update
- final ValuesDelta phone = getPhone(first, CONTACT_MARY, PHONE_RED);
- phone.put(Phone.NUMBER, TEST_PHONE);
- assertDiffPattern(first,
- buildAssertVersion(VER_FIRST),
- buildAssertVersion(VER_FIRST),
- buildUpdateAggregationSuspended(),
- buildOper(Data.CONTENT_URI, TYPE_UPDATE, phone.getAfter()),
- buildUpdateAggregationDefault());
-
- final ContentValues phoneInsert = phone.getCompleteValues();
- final ContentValues contactInsert = first.getByRawContactId(CONTACT_MARY).getValues()
- .getCompleteValues();
- contactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
-
- // Merge and verify that update turned into insert
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertDiffPattern(merged,
- buildAssertVersion(VER_SECOND),
- buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, contactInsert),
- buildOper(Data.CONTENT_URI, TYPE_INSERT, phoneInsert),
- buildAggregationModeUpdate(RawContacts.AGGREGATION_MODE_DEFAULT),
- buildUpdateAggregationKeepTogether(CONTACT_BOB));
- }
-
- public void testMergeUsesNewVersion() {
- final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_FIRST, buildPhone(PHONE_RED)));
- final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_SECOND, buildPhone(PHONE_RED)));
-
- assertEquals((Long)VER_FIRST, getVersion(first, CONTACT_BOB));
- assertEquals((Long)VER_SECOND, getVersion(second, CONTACT_BOB));
-
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertEquals((Long)VER_SECOND, getVersion(merged, CONTACT_BOB));
- }
-
- public void testMergeAfterEnsureAndTrim() {
- final RawContactDeltaList first = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_FIRST, buildEmail(EMAIL_YELLOW)));
- final RawContactDeltaList second = buildSet(buildBeforeEntity(mContext, CONTACT_BOB,
- VER_SECOND, buildEmail(EMAIL_YELLOW)));
-
- // Ensure we have at least one phone
- final AccountType source = getAccountType();
- final RawContactDelta bobContact = first.getByRawContactId(CONTACT_BOB);
- RawContactModifier.ensureKindExists(bobContact, source, Phone.CONTENT_ITEM_TYPE);
- final ValuesDelta bobPhone = bobContact.getSuperPrimaryEntry(Phone.CONTENT_ITEM_TYPE, true);
-
- // Make sure the update would insert a row
- assertDiffPattern(first,
- buildAssertVersion(VER_FIRST),
- buildUpdateAggregationSuspended(),
- buildOper(Data.CONTENT_URI, TYPE_INSERT, buildDataInsert(bobPhone, CONTACT_BOB)),
- buildUpdateAggregationDefault());
-
- // Trim values and ensure that we don't insert things
- RawContactModifier.trimEmpty(bobContact, source);
- assertDiffPattern(first);
-
- // Now re-parent the change, which should remain no-op
- final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
- assertDiffPattern(merged);
- }
-}
diff --git a/tests/src/com/android/contacts/RawContactDeltaTests.java b/tests/src/com/android/contacts/RawContactDeltaTests.java
deleted file mode 100644
index dc4eb53..0000000
--- a/tests/src/com/android/contacts/RawContactDeltaTests.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright (C) 2009 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;
-
-import static android.content.ContentProviderOperation.TYPE_ASSERT;
-import static android.content.ContentProviderOperation.TYPE_DELETE;
-import static android.content.ContentProviderOperation.TYPE_INSERT;
-import static android.content.ContentProviderOperation.TYPE_UPDATE;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderOperation.Builder;
-import android.content.ContentValues;
-import android.content.Context;
-import android.os.Parcel;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import com.android.contacts.model.RawContact;
-import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.common.model.ValuesDelta;
-import com.google.common.collect.Lists;
-
-import java.util.ArrayList;
-
-/**
- * Tests for {@link RawContactDelta} and {@link ValuesDelta}. These tests
- * focus on passing changes across {@link Parcel}, and verifying that they
- * correctly build expected "diff" operations.
- */
-@LargeTest
-public class RawContactDeltaTests extends AndroidTestCase {
- public static final String TAG = "EntityDeltaTests";
-
- public static final long TEST_CONTACT_ID = 12;
- public static final long TEST_PHONE_ID = 24;
-
- public static final String TEST_PHONE_NUMBER_1 = "218-555-1111";
- public static final String TEST_PHONE_NUMBER_2 = "218-555-2222";
-
- public static final String TEST_ACCOUNT_NAME = "TEST";
-
- public RawContactDeltaTests() {
- super();
- }
-
- @Override
- public void setUp() {
- mContext = getContext();
- }
-
- public static RawContact getRawContact(Context context, long contactId, long phoneId) {
- // Build an existing contact read from database
- final ContentValues contact = new ContentValues();
- contact.put(RawContacts.VERSION, 43);
- contact.put(RawContacts._ID, contactId);
-
- final ContentValues phone = new ContentValues();
- phone.put(Data._ID, phoneId);
- phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
- phone.put(Phone.TYPE, Phone.TYPE_HOME);
-
- final RawContact before = new RawContact(contact);
- before.addDataItemValues(phone);
- return before;
- }
-
- /**
- * Test that {@link RawContactDelta#mergeAfter(RawContactDelta)} correctly passes
- * any changes through the {@link Parcel} object. This enforces that
- * {@link RawContactDelta} should be identical when serialized against the same
- * "before" {@link RawContact}.
- */
- public void testParcelChangesNone() {
- final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
- final RawContactDelta source = RawContactDelta.fromBefore(before);
- final RawContactDelta dest = RawContactDelta.fromBefore(before);
-
- // Merge modified values and assert they match
- final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
- assertEquals("Unexpected change when merging", source, merged);
- }
-
- public void testParcelChangesInsert() {
- final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
- final RawContactDelta source = RawContactDelta.fromBefore(before);
- final RawContactDelta dest = RawContactDelta.fromBefore(before);
-
- // Add a new row and pass across parcel, should be same
- final ContentValues phone = new ContentValues();
- phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
- phone.put(Phone.TYPE, Phone.TYPE_WORK);
- source.addEntry(ValuesDelta.fromAfter(phone));
-
- // Merge modified values and assert they match
- final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
- assertEquals("Unexpected change when merging", source, merged);
- }
-
- public void testParcelChangesUpdate() {
- // Update existing row and pass across parcel, should be same
- final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
- final RawContactDelta source = RawContactDelta.fromBefore(before);
- final RawContactDelta dest = RawContactDelta.fromBefore(before);
-
- final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
- child.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
-
- // Merge modified values and assert they match
- final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
- assertEquals("Unexpected change when merging", source, merged);
- }
-
- public void testParcelChangesDelete() {
- // Delete a row and pass across parcel, should be same
- final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
- final RawContactDelta source = RawContactDelta.fromBefore(before);
- final RawContactDelta dest = RawContactDelta.fromBefore(before);
-
- final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
- child.markDeleted();
-
- // Merge modified values and assert they match
- final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
- assertEquals("Unexpected change when merging", source, merged);
- }
-
- public void testValuesDiffDelete() {
- final ContentValues before = new ContentValues();
- before.put(Data._ID, TEST_PHONE_ID);
- before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
-
- final ValuesDelta values = ValuesDelta.fromBefore(before);
- values.markDeleted();
-
- // Should produce a delete action
- final Builder builder = values.buildDiff(Data.CONTENT_URI);
- final int type = builder.build().getType();
- assertEquals("Didn't produce delete action", TYPE_DELETE, type);
- }
-
- /**
- * Test that {@link RawContactDelta#buildDiff(ArrayList)} is correctly built for
- * insert, update, and delete cases. This only tests a subset of possible
- * {@link Data} row changes.
- */
- public void testEntityDiffNone() {
- final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
- final RawContactDelta source = RawContactDelta.fromBefore(before);
-
- // Assert that writing unchanged produces few operations
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- source.buildDiff(diff);
-
- assertTrue("Created changes when none needed", (diff.size() == 0));
- }
-
- public void testEntityDiffNoneInsert() {
- final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
- final RawContactDelta source = RawContactDelta.fromBefore(before);
-
- // Insert a new phone number
- final ContentValues phone = new ContentValues();
- phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
- phone.put(Phone.TYPE, Phone.TYPE_WORK);
- source.addEntry(ValuesDelta.fromAfter(phone));
-
- // Assert two operations: insert Data row and enforce version
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- source.buildAssert(diff);
- source.buildDiff(diff);
- assertEquals("Unexpected operations", 4, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Expected version enforcement", TYPE_ASSERT, oper.getType());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(2);
- assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(3);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- }
-
- public void testEntityDiffUpdateInsert() {
- final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
- final RawContactDelta source = RawContactDelta.fromBefore(before);
-
- // Update parent contact values
- source.getValues().put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
-
- // Insert a new phone number
- final ContentValues phone = new ContentValues();
- phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
- phone.put(Phone.TYPE, Phone.TYPE_WORK);
- source.addEntry(ValuesDelta.fromAfter(phone));
-
- // Assert three operations: update Contact, insert Data row, enforce version
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- source.buildAssert(diff);
- source.buildDiff(diff);
- assertEquals("Unexpected operations", 5, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Expected version enforcement", TYPE_ASSERT, oper.getType());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(2);
- assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(3);
- assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(4);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- }
-
- public void testEntityDiffNoneUpdate() {
- final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
- final RawContactDelta source = RawContactDelta.fromBefore(before);
-
- // Update existing phone number
- final ValuesDelta child = source.getEntry(TEST_PHONE_ID);
- child.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
-
- // Assert that version is enforced
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- source.buildAssert(diff);
- source.buildDiff(diff);
- assertEquals("Unexpected operations", 4, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Expected version enforcement", TYPE_ASSERT, oper.getType());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(2);
- assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(3);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- }
-
- public void testEntityDiffDelete() {
- final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
- final RawContactDelta source = RawContactDelta.fromBefore(before);
-
- // Delete entire entity
- source.getValues().markDeleted();
-
- // Assert two operations: delete Contact and enforce version
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- source.buildAssert(diff);
- source.buildDiff(diff);
- assertEquals("Unexpected operations", 2, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Expected version enforcement", TYPE_ASSERT, oper.getType());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- }
-
- public void testEntityDiffInsert() {
- // Insert a RawContact
- final ContentValues after = new ContentValues();
- after.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
- after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
-
- final ValuesDelta values = ValuesDelta.fromAfter(after);
- final RawContactDelta source = new RawContactDelta(values);
-
- // Assert two operations: delete Contact and enforce version
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- source.buildAssert(diff);
- source.buildDiff(diff);
- assertEquals("Unexpected operations", 2, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- }
-
- public void testEntityDiffInsertInsert() {
- // Insert a RawContact
- final ContentValues after = new ContentValues();
- after.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
- after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
-
- final ValuesDelta values = ValuesDelta.fromAfter(after);
- final RawContactDelta source = new RawContactDelta(values);
-
- // Insert a new phone number
- final ContentValues phone = new ContentValues();
- phone.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
- phone.put(Phone.TYPE, Phone.TYPE_WORK);
- source.addEntry(ValuesDelta.fromAfter(phone));
-
- // Assert two operations: delete Contact and enforce version
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- source.buildAssert(diff);
- source.buildDiff(diff);
- assertEquals("Unexpected operations", 3, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
-
- }
- }
-}
diff --git a/tests/src/com/android/contacts/RawContactModifierTests.java b/tests/src/com/android/contacts/RawContactModifierTests.java
deleted file mode 100644
index ce69b55..0000000
--- a/tests/src/com/android/contacts/RawContactModifierTests.java
+++ /dev/null
@@ -1,1235 +0,0 @@
-/*
- * Copyright (C) 2009 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;
-
-import static android.content.ContentProviderOperation.TYPE_DELETE;
-import static android.content.ContentProviderOperation.TYPE_INSERT;
-import static android.content.ContentProviderOperation.TYPE_UPDATE;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentValues;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Event;
-import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.Intents.Insert;
-import android.provider.ContactsContract.RawContacts;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.model.RawContact;
-import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.model.RawContactDeltaList;
-import com.android.contacts.model.RawContactModifier;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountType.EditType;
-import com.android.contacts.common.model.account.ExchangeAccountType;
-import com.android.contacts.common.model.account.GoogleAccountType;
-import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.common.test.mocks.ContactsMockContext;
-import com.android.contacts.tests.mocks.MockAccountTypeManager;
-import com.android.contacts.common.test.mocks.MockContentProvider;
-import com.google.common.collect.Lists;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for {@link RawContactModifier} to verify that {@link AccountType}
- * constraints are being enforced correctly.
- */
-@LargeTest
-public class RawContactModifierTests extends AndroidTestCase {
- public static final String TAG = "EntityModifierTests";
-
- public static final long VER_FIRST = 100;
-
- private static final long TEST_ID = 4;
- private static final String TEST_PHONE = "218-555-1212";
- private static final String TEST_NAME = "Adam Young";
- private static final String TEST_NAME2 = "Breanne Duren";
- private static final String TEST_IM = "example@example.com";
- private static final String TEST_POSTAL = "1600 Amphitheatre Parkway";
-
- private static final String TEST_ACCOUNT_NAME = "unittest@example.com";
- private static final String TEST_ACCOUNT_TYPE = "com.example.unittest";
-
- private static final String EXCHANGE_ACCT_TYPE = "com.android.exchange";
-
- @Override
- public void setUp() {
- mContext = getContext();
- }
-
- public static class MockContactsSource extends AccountType {
-
- MockContactsSource() {
- try {
- this.accountType = TEST_ACCOUNT_TYPE;
-
- final DataKind nameKind = new DataKind(StructuredName.CONTENT_ITEM_TYPE,
- R.string.nameLabelsGroup, -1, true);
- nameKind.typeOverallMax = 1;
- addKind(nameKind);
-
- // Phone allows maximum 2 home, 1 work, and unlimited other, with
- // constraint of 5 numbers maximum.
- final DataKind phoneKind = new DataKind(
- Phone.CONTENT_ITEM_TYPE, -1, 10, true);
-
- phoneKind.typeOverallMax = 5;
- phoneKind.typeColumn = Phone.TYPE;
- phoneKind.typeList = Lists.newArrayList();
- phoneKind.typeList.add(new EditType(Phone.TYPE_HOME, -1).setSpecificMax(2));
- phoneKind.typeList.add(new EditType(Phone.TYPE_WORK, -1).setSpecificMax(1));
- phoneKind.typeList.add(new EditType(Phone.TYPE_FAX_WORK, -1).setSecondary(true));
- phoneKind.typeList.add(new EditType(Phone.TYPE_OTHER, -1));
-
- phoneKind.fieldList = Lists.newArrayList();
- phoneKind.fieldList.add(new EditField(Phone.NUMBER, -1, -1));
- phoneKind.fieldList.add(new EditField(Phone.LABEL, -1, -1));
-
- addKind(phoneKind);
-
- // Email is unlimited
- final DataKind emailKind = new DataKind(Email.CONTENT_ITEM_TYPE, -1, 10, true);
- emailKind.typeOverallMax = -1;
- emailKind.fieldList = Lists.newArrayList();
- emailKind.fieldList.add(new EditField(Email.DATA, -1, -1));
- addKind(emailKind);
-
- // IM is only one
- final DataKind imKind = new DataKind(Im.CONTENT_ITEM_TYPE, -1, 10, true);
- imKind.typeOverallMax = 1;
- imKind.fieldList = Lists.newArrayList();
- imKind.fieldList.add(new EditField(Im.DATA, -1, -1));
- addKind(imKind);
-
- // Organization is only one
- final DataKind orgKind = new DataKind(Organization.CONTENT_ITEM_TYPE, -1, 10, true);
- orgKind.typeOverallMax = 1;
- orgKind.fieldList = Lists.newArrayList();
- orgKind.fieldList.add(new EditField(Organization.COMPANY, -1, -1));
- orgKind.fieldList.add(new EditField(Organization.TITLE, -1, -1));
- addKind(orgKind);
- } catch (DefinitionException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public boolean isGroupMembershipEditable() {
- return false;
- }
-
- @Override
- public boolean areContactsWritable() {
- return true;
- }
- }
-
- /**
- * Build a {@link AccountType} that has various odd constraints for
- * testing purposes.
- */
- protected AccountType getAccountType() {
- return new MockContactsSource();
- }
-
- /**
- * Build {@link AccountTypeManager} instance.
- */
- protected AccountTypeManager getAccountTypes(AccountType... types) {
- return new MockAccountTypeManager(types, null);
- }
-
- /**
- * Build an {@link RawContact} with the requested set of phone numbers.
- */
- protected RawContactDelta getRawContact(Long existingId, ContentValues... entries) {
- final ContentValues contact = new ContentValues();
- if (existingId != null) {
- contact.put(RawContacts._ID, existingId);
- }
- contact.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
- contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE);
-
- final RawContact before = new RawContact(contact);
- for (ContentValues values : entries) {
- before.addDataItemValues(values);
- }
- return RawContactDelta.fromBefore(before);
- }
-
- /**
- * Assert this {@link List} contains the given {@link Object}.
- */
- protected void assertContains(List<?> list, Object object) {
- assertTrue("Missing expected value", list.contains(object));
- }
-
- /**
- * Assert this {@link List} does not contain the given {@link Object}.
- */
- protected void assertNotContains(List<?> list, Object object) {
- assertFalse("Contained unexpected value", list.contains(object));
- }
-
- /**
- * Insert various rows to test
- * {@link RawContactModifier#getValidTypes(RawContactDelta, DataKind, EditType)}
- */
- public void testValidTypes() {
- // Build a source and pull specific types
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
- final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
- final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
-
- List<EditType> validTypes;
-
- // Add first home, first work
- final RawContactDelta state = getRawContact(TEST_ID);
- RawContactModifier.insertChild(state, kindPhone, typeHome);
- RawContactModifier.insertChild(state, kindPhone, typeWork);
-
- // Expecting home, other
- validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
- assertContains(validTypes, typeHome);
- assertNotContains(validTypes, typeWork);
- assertContains(validTypes, typeOther);
-
- // Add second home
- RawContactModifier.insertChild(state, kindPhone, typeHome);
-
- // Expecting other
- validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
- assertNotContains(validTypes, typeHome);
- assertNotContains(validTypes, typeWork);
- assertContains(validTypes, typeOther);
-
- // Add third and fourth home (invalid, but possible)
- RawContactModifier.insertChild(state, kindPhone, typeHome);
- RawContactModifier.insertChild(state, kindPhone, typeHome);
-
- // Expecting none
- validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
- assertNotContains(validTypes, typeHome);
- assertNotContains(validTypes, typeWork);
- assertNotContains(validTypes, typeOther);
- }
-
- /**
- * Test {@link RawContactModifier#canInsert(RawContactDelta, DataKind)} by
- * inserting various rows.
- */
- public void testCanInsert() {
- // Build a source and pull specific types
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
- final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
- final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
-
- // Add first home, first work
- final RawContactDelta state = getRawContact(TEST_ID);
- RawContactModifier.insertChild(state, kindPhone, typeHome);
- RawContactModifier.insertChild(state, kindPhone, typeWork);
- assertTrue("Unable to insert", RawContactModifier.canInsert(state, kindPhone));
-
- // Add two other, which puts us just under "5" overall limit
- RawContactModifier.insertChild(state, kindPhone, typeOther);
- RawContactModifier.insertChild(state, kindPhone, typeOther);
- assertTrue("Unable to insert", RawContactModifier.canInsert(state, kindPhone));
-
- // Add second home, which should push to snug limit
- RawContactModifier.insertChild(state, kindPhone, typeHome);
- assertFalse("Able to insert", RawContactModifier.canInsert(state, kindPhone));
- }
-
- /**
- * Test
- * {@link RawContactModifier#getBestValidType(RawContactDelta, DataKind, boolean, int)}
- * by asserting expected best options in various states.
- */
- public void testBestValidType() {
- // Build a source and pull specific types
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
- final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
- final EditType typeFaxWork = RawContactModifier.getType(kindPhone, Phone.TYPE_FAX_WORK);
- final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
-
- EditType suggested;
-
- // Default suggestion should be home
- final RawContactDelta state = getRawContact(TEST_ID);
- suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
- assertEquals("Unexpected suggestion", typeHome, suggested);
-
- // Add first home, should now suggest work
- RawContactModifier.insertChild(state, kindPhone, typeHome);
- suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
- assertEquals("Unexpected suggestion", typeWork, suggested);
-
- // Add work fax, should still suggest work
- RawContactModifier.insertChild(state, kindPhone, typeFaxWork);
- suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
- assertEquals("Unexpected suggestion", typeWork, suggested);
-
- // Add other, should still suggest work
- RawContactModifier.insertChild(state, kindPhone, typeOther);
- suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
- assertEquals("Unexpected suggestion", typeWork, suggested);
-
- // Add work, now should suggest other
- RawContactModifier.insertChild(state, kindPhone, typeWork);
- suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
- assertEquals("Unexpected suggestion", typeOther, suggested);
- }
-
- public void testIsEmptyEmpty() {
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
-
- // Test entirely empty row
- final ContentValues after = new ContentValues();
- final ValuesDelta values = ValuesDelta.fromAfter(after);
-
- assertTrue("Expected empty", RawContactModifier.isEmpty(values, kindPhone));
- }
-
- public void testIsEmptyDirectFields() {
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Test row that has type values, but core fields are empty
- final RawContactDelta state = getRawContact(TEST_ID);
- final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
-
- assertTrue("Expected empty", RawContactModifier.isEmpty(values, kindPhone));
-
- // Insert some data to trigger non-empty state
- values.put(Phone.NUMBER, TEST_PHONE);
-
- assertFalse("Expected non-empty", RawContactModifier.isEmpty(values, kindPhone));
- }
-
- public void testTrimEmptySingle() {
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Test row that has type values, but core fields are empty
- final RawContactDelta state = getRawContact(TEST_ID);
- RawContactModifier.insertChild(state, kindPhone, typeHome);
-
- // Build diff, expecting insert for data row and update enforcement
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 3, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(2);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
-
- // Trim empty rows and try again, expecting delete of overall contact
- RawContactModifier.trimEmpty(state, source);
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 1, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- }
-
- public void testTrimEmptySpaces() {
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Test row that has type values, but values are spaces
- final RawContactDelta state = RawContactDeltaListTests.buildBeforeEntity(mContext, TEST_ID,
- VER_FIRST);
- final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
- values.put(Phone.NUMBER, " ");
-
- // Build diff, expecting insert for data row and update enforcement
- RawContactDeltaListTests.assertDiffPattern(state,
- RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
- RawContactDeltaListTests.buildUpdateAggregationSuspended(),
- RawContactDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
- RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
- RawContactDeltaListTests.buildUpdateAggregationDefault());
-
- // Trim empty rows and try again, expecting delete of overall contact
- RawContactModifier.trimEmpty(state, source);
- RawContactDeltaListTests.assertDiffPattern(state,
- RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
- RawContactDeltaListTests.buildDelete(RawContacts.CONTENT_URI));
- }
-
- public void testTrimLeaveValid() {
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Test row that has type values with valid number
- final RawContactDelta state = RawContactDeltaListTests.buildBeforeEntity(mContext, TEST_ID,
- VER_FIRST);
- final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
- values.put(Phone.NUMBER, TEST_PHONE);
-
- // Build diff, expecting insert for data row and update enforcement
- RawContactDeltaListTests.assertDiffPattern(state,
- RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
- RawContactDeltaListTests.buildUpdateAggregationSuspended(),
- RawContactDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
- RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
- RawContactDeltaListTests.buildUpdateAggregationDefault());
-
- // Trim empty rows and try again, expecting no differences
- RawContactModifier.trimEmpty(state, source);
- RawContactDeltaListTests.assertDiffPattern(state,
- RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
- RawContactDeltaListTests.buildUpdateAggregationSuspended(),
- RawContactDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
- RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
- RawContactDeltaListTests.buildUpdateAggregationDefault());
- }
-
- public void testTrimEmptyUntouched() {
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Build "before" that has empty row
- final RawContactDelta state = getRawContact(TEST_ID);
- final ContentValues before = new ContentValues();
- before.put(Data._ID, TEST_ID);
- before.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- state.addEntry(ValuesDelta.fromBefore(before));
-
- // Build diff, expecting no changes
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 0, diff.size());
-
- // Try trimming existing empty, which we shouldn't touch
- RawContactModifier.trimEmpty(state, source);
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 0, diff.size());
- }
-
- public void testTrimEmptyAfterUpdate() {
- final AccountType source = getAccountType();
- final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Build "before" that has row with some phone number
- final ContentValues before = new ContentValues();
- before.put(Data._ID, TEST_ID);
- before.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- before.put(kindPhone.typeColumn, typeHome.rawValue);
- before.put(Phone.NUMBER, TEST_PHONE);
- final RawContactDelta state = getRawContact(TEST_ID, before);
-
- // Build diff, expecting no changes
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 0, diff.size());
-
- // Now update row by changing number to empty string, expecting single update
- final ValuesDelta child = state.getEntry(TEST_ID);
- child.put(Phone.NUMBER, "");
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 3, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(2);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
-
- // Now run trim, which should turn that update into delete
- RawContactModifier.trimEmpty(state, source);
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 1, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- }
-
- public void testTrimInsertEmpty() {
- final AccountType accountType = getAccountType();
- final AccountTypeManager accountTypes = getAccountTypes(accountType);
- final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Try creating a contact without any child entries
- final RawContactDelta state = getRawContact(null);
- final RawContactDeltaList set = new RawContactDeltaList();
- set.add(state);
-
-
- // Build diff, expecting single insert
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 2, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
-
- // Trim empty rows and try again, expecting no insert
- RawContactModifier.trimEmpty(set, accountTypes);
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 0, diff.size());
- }
-
- public void testTrimInsertInsert() {
- final AccountType accountType = getAccountType();
- final AccountTypeManager accountTypes = getAccountTypes(accountType);
- final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Try creating a contact with single empty entry
- final RawContactDelta state = getRawContact(null);
- RawContactModifier.insertChild(state, kindPhone, typeHome);
- final RawContactDeltaList set = new RawContactDeltaList();
- set.add(state);
-
- // Build diff, expecting two insert operations
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 3, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
- }
-
- // Trim empty rows and try again, expecting silence
- RawContactModifier.trimEmpty(set, accountTypes);
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 0, diff.size());
- }
-
- public void testTrimUpdateRemain() {
- final AccountType accountType = getAccountType();
- final AccountTypeManager accountTypes = getAccountTypes(accountType);
- final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Build "before" with two phone numbers
- final ContentValues first = new ContentValues();
- first.put(Data._ID, TEST_ID);
- first.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- first.put(kindPhone.typeColumn, typeHome.rawValue);
- first.put(Phone.NUMBER, TEST_PHONE);
-
- final ContentValues second = new ContentValues();
- second.put(Data._ID, TEST_ID);
- second.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- second.put(kindPhone.typeColumn, typeHome.rawValue);
- second.put(Phone.NUMBER, TEST_PHONE);
-
- final RawContactDelta state = getRawContact(TEST_ID, first, second);
- final RawContactDeltaList set = new RawContactDeltaList();
- set.add(state);
-
- // Build diff, expecting no changes
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 0, diff.size());
-
- // Now update row by changing number to empty string, expecting single update
- final ValuesDelta child = state.getEntry(TEST_ID);
- child.put(Phone.NUMBER, "");
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 3, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(2);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
-
- // Now run trim, which should turn that update into delete
- RawContactModifier.trimEmpty(set, accountTypes);
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 3, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(2);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- }
-
- public void testTrimUpdateUpdate() {
- final AccountType accountType = getAccountType();
- final AccountTypeManager accountTypes = getAccountTypes(accountType);
- final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
-
- // Build "before" with two phone numbers
- final ContentValues first = new ContentValues();
- first.put(Data._ID, TEST_ID);
- first.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- first.put(kindPhone.typeColumn, typeHome.rawValue);
- first.put(Phone.NUMBER, TEST_PHONE);
-
- final RawContactDelta state = getRawContact(TEST_ID, first);
- final RawContactDeltaList set = new RawContactDeltaList();
- set.add(state);
-
- // Build diff, expecting no changes
- final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 0, diff.size());
-
- // Now update row by changing number to empty string, expecting single update
- final ValuesDelta child = state.getEntry(TEST_ID);
- child.put(Phone.NUMBER, "");
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 3, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(1);
- assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
- }
- {
- final ContentProviderOperation oper = diff.get(2);
- assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
-
- // Now run trim, which should turn into deleting the whole contact
- RawContactModifier.trimEmpty(set, accountTypes);
- diff.clear();
- state.buildDiff(diff);
- assertEquals("Unexpected operations", 1, diff.size());
- {
- final ContentProviderOperation oper = diff.get(0);
- assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
- assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
- }
- }
-
- public void testParseExtrasExistingName() {
- final AccountType accountType = getAccountType();
-
- // Build "before" name
- final ContentValues first = new ContentValues();
- first.put(Data._ID, TEST_ID);
- first.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
- first.put(StructuredName.GIVEN_NAME, TEST_NAME);
-
- // Parse extras, making sure we keep single name
- final RawContactDelta state = getRawContact(TEST_ID, first);
- final Bundle extras = new Bundle();
- extras.putString(Insert.NAME, TEST_NAME2);
- RawContactModifier.parseExtras(mContext, accountType, state, extras);
-
- final int nameCount = state.getMimeEntriesCount(StructuredName.CONTENT_ITEM_TYPE, true);
- assertEquals("Unexpected names", 1, nameCount);
- }
-
- public void testParseExtrasIgnoreLimit() {
- final AccountType accountType = getAccountType();
-
- // Build "before" IM
- final ContentValues first = new ContentValues();
- first.put(Data._ID, TEST_ID);
- first.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
- first.put(Im.DATA, TEST_IM);
-
- final RawContactDelta state = getRawContact(TEST_ID, first);
- final int beforeCount = state.getMimeEntries(Im.CONTENT_ITEM_TYPE).size();
-
- // We should ignore data that doesn't fit account type rules, since account type
- // only allows single Im
- final Bundle extras = new Bundle();
- extras.putInt(Insert.IM_PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
- extras.putString(Insert.IM_HANDLE, TEST_IM);
- RawContactModifier.parseExtras(mContext, accountType, state, extras);
-
- final int afterCount = state.getMimeEntries(Im.CONTENT_ITEM_TYPE).size();
- assertEquals("Broke account type rules", beforeCount, afterCount);
- }
-
- public void testParseExtrasIgnoreUnhandled() {
- final AccountType accountType = getAccountType();
- final RawContactDelta state = getRawContact(TEST_ID);
-
- // We should silently ignore types unsupported by account type
- final Bundle extras = new Bundle();
- extras.putString(Insert.POSTAL, TEST_POSTAL);
- RawContactModifier.parseExtras(mContext, accountType, state, extras);
-
- assertNull("Broke accoun type rules",
- state.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE));
- }
-
- public void testParseExtrasJobTitle() {
- final AccountType accountType = getAccountType();
- final RawContactDelta state = getRawContact(TEST_ID);
-
- // Make sure that we create partial Organizations
- final Bundle extras = new Bundle();
- extras.putString(Insert.JOB_TITLE, TEST_NAME);
- RawContactModifier.parseExtras(mContext, accountType, state, extras);
-
- final int count = state.getMimeEntries(Organization.CONTENT_ITEM_TYPE).size();
- assertEquals("Expected to create organization", 1, count);
- }
-
- public void testMigrateWithDisplayNameFromGoogleToExchange1() {
- AccountType oldAccountType = new GoogleAccountType(getContext(), "");
- AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
-
- ContactsMockContext context = new ContactsMockContext(getContext());
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
- mockNameValues.put(StructuredName.PREFIX, "prefix");
- mockNameValues.put(StructuredName.GIVEN_NAME, "given");
- mockNameValues.put(StructuredName.MIDDLE_NAME, "middle");
- mockNameValues.put(StructuredName.FAMILY_NAME, "family");
- mockNameValues.put(StructuredName.SUFFIX, "suffix");
- mockNameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "PHONETIC_FAMILY");
- mockNameValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "PHONETIC_MIDDLE");
- mockNameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "PHONETIC_GIVEN");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
- List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
- assertEquals(1, list.size());
-
- ContentValues output = list.get(0).getAfter();
- assertEquals("prefix", output.getAsString(StructuredName.PREFIX));
- assertEquals("given", output.getAsString(StructuredName.GIVEN_NAME));
- assertEquals("middle", output.getAsString(StructuredName.MIDDLE_NAME));
- assertEquals("family", output.getAsString(StructuredName.FAMILY_NAME));
- assertEquals("suffix", output.getAsString(StructuredName.SUFFIX));
- // Phonetic middle name isn't supported by Exchange.
- assertEquals("PHONETIC_FAMILY", output.getAsString(StructuredName.PHONETIC_FAMILY_NAME));
- assertEquals("PHONETIC_GIVEN", output.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
- }
-
- public void testMigrateWithDisplayNameFromGoogleToExchange2() {
- AccountType oldAccountType = new GoogleAccountType(getContext(), "");
- AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
-
- ContactsMockContext context = new ContactsMockContext(getContext());
- MockContentProvider provider = context.getContactsProvider();
-
- String inputDisplayName = "prefix given middle family suffix";
- // The method will ask the provider to split/join StructuredName.
- Uri uriForBuildDisplayName =
- ContactsContract.AUTHORITY_URI
- .buildUpon()
- .appendPath("complete_name")
- .appendQueryParameter(StructuredName.DISPLAY_NAME, inputDisplayName)
- .build();
- provider.expectQuery(uriForBuildDisplayName)
- .returnRow("prefix", "given", "middle", "family", "suffix")
- .withProjection(StructuredName.PREFIX, StructuredName.GIVEN_NAME,
- StructuredName.MIDDLE_NAME, StructuredName.FAMILY_NAME,
- StructuredName.SUFFIX);
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
- mockNameValues.put(StructuredName.DISPLAY_NAME, inputDisplayName);
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
- List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
- assertEquals(1, list.size());
-
- ContentValues outputValues = list.get(0).getAfter();
- assertEquals("prefix", outputValues.getAsString(StructuredName.PREFIX));
- assertEquals("given", outputValues.getAsString(StructuredName.GIVEN_NAME));
- assertEquals("middle", outputValues.getAsString(StructuredName.MIDDLE_NAME));
- assertEquals("family", outputValues.getAsString(StructuredName.FAMILY_NAME));
- assertEquals("suffix", outputValues.getAsString(StructuredName.SUFFIX));
- }
-
- public void testMigrateWithStructuredNameFromExchangeToGoogle() {
- AccountType oldAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- AccountType newAccountType = new GoogleAccountType(getContext(), "");
- DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
-
- ContactsMockContext context = new ContactsMockContext(getContext());
- MockContentProvider provider = context.getContactsProvider();
-
- // The method will ask the provider to split/join StructuredName.
- Uri uriForBuildDisplayName =
- ContactsContract.AUTHORITY_URI
- .buildUpon()
- .appendPath("complete_name")
- .appendQueryParameter(StructuredName.PREFIX, "prefix")
- .appendQueryParameter(StructuredName.GIVEN_NAME, "given")
- .appendQueryParameter(StructuredName.MIDDLE_NAME, "middle")
- .appendQueryParameter(StructuredName.FAMILY_NAME, "family")
- .appendQueryParameter(StructuredName.SUFFIX, "suffix")
- .build();
- provider.expectQuery(uriForBuildDisplayName)
- .returnRow("prefix given middle family suffix")
- .withProjection(StructuredName.DISPLAY_NAME);
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
- mockNameValues.put(StructuredName.PREFIX, "prefix");
- mockNameValues.put(StructuredName.GIVEN_NAME, "given");
- mockNameValues.put(StructuredName.MIDDLE_NAME, "middle");
- mockNameValues.put(StructuredName.FAMILY_NAME, "family");
- mockNameValues.put(StructuredName.SUFFIX, "suffix");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
-
- List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
- assertNotNull(list);
- assertEquals(1, list.size());
- ContentValues outputValues = list.get(0).getAfter();
- assertEquals("prefix given middle family suffix",
- outputValues.getAsString(StructuredName.DISPLAY_NAME));
- }
-
- public void testMigratePostalFromGoogleToExchange() {
- AccountType oldAccountType = new GoogleAccountType(getContext(), "");
- AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
- mockNameValues.put(StructuredPostal.FORMATTED_ADDRESS, "formatted_address");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migratePostal(oldState, newState, kind);
-
- List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
- assertNotNull(list);
- assertEquals(1, list.size());
- ContentValues outputValues = list.get(0).getAfter();
- // FORMATTED_ADDRESS isn't supported by Exchange.
- assertNull(outputValues.getAsString(StructuredPostal.FORMATTED_ADDRESS));
- assertEquals("formatted_address", outputValues.getAsString(StructuredPostal.STREET));
- }
-
- public void testMigratePostalFromExchangeToGoogle() {
- AccountType oldAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- AccountType newAccountType = new GoogleAccountType(getContext(), "");
- DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
- mockNameValues.put(StructuredPostal.COUNTRY, "country");
- mockNameValues.put(StructuredPostal.POSTCODE, "postcode");
- mockNameValues.put(StructuredPostal.REGION, "region");
- mockNameValues.put(StructuredPostal.CITY, "city");
- mockNameValues.put(StructuredPostal.STREET, "street");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migratePostal(oldState, newState, kind);
-
- List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
- assertNotNull(list);
- assertEquals(1, list.size());
- ContentValues outputValues = list.get(0).getAfter();
-
- // Check FORMATTED_ADDRESS contains all info.
- String formattedAddress = outputValues.getAsString(StructuredPostal.FORMATTED_ADDRESS);
- assertNotNull(formattedAddress);
- assertTrue(formattedAddress.contains("country"));
- assertTrue(formattedAddress.contains("postcode"));
- assertTrue(formattedAddress.contains("region"));
- assertTrue(formattedAddress.contains("postcode"));
- assertTrue(formattedAddress.contains("city"));
- assertTrue(formattedAddress.contains("street"));
- }
-
- public void testMigrateEventFromGoogleToExchange1() {
- testMigrateEventCommon(new GoogleAccountType(getContext(), ""),
- new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE));
- }
-
- public void testMigrateEventFromExchangeToGoogle() {
- testMigrateEventCommon(new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE),
- new GoogleAccountType(getContext(), ""));
- }
-
- private void testMigrateEventCommon(AccountType oldAccountType, AccountType newAccountType) {
- DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
- mockNameValues.put(Event.START_DATE, "1972-02-08");
- mockNameValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
-
- List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
- assertNotNull(list);
- assertEquals(1, list.size()); // Anniversary should be dropped.
- ContentValues outputValues = list.get(0).getAfter();
-
- assertEquals("1972-02-08", outputValues.getAsString(Event.START_DATE));
- assertEquals(Event.TYPE_BIRTHDAY, outputValues.getAsInteger(Event.TYPE).intValue());
- }
-
- public void testMigrateEventFromGoogleToExchange2() {
- AccountType oldAccountType = new GoogleAccountType(getContext(), "");
- AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
- // No year format is not supported by Exchange.
- mockNameValues.put(Event.START_DATE, "--06-01");
- mockNameValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
- mockNameValues.put(Event.START_DATE, "1980-08-02");
- // Anniversary is not supported by Exchange
- mockNameValues.put(Event.TYPE, Event.TYPE_ANNIVERSARY);
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
-
- List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
- assertNotNull(list);
- assertEquals(1, list.size()); // Anniversary should be dropped.
- ContentValues outputValues = list.get(0).getAfter();
-
- // Default year should be used.
- assertEquals("1990-06-01", outputValues.getAsString(Event.START_DATE));
- assertEquals(Event.TYPE_BIRTHDAY, outputValues.getAsInteger(Event.TYPE).intValue());
- }
-
- public void testMigrateEmailFromGoogleToExchange() {
- AccountType oldAccountType = new GoogleAccountType(getContext(), "");
- AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- DataKind kind = newAccountType.getKindForMimetype(Email.CONTENT_ITEM_TYPE);
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
- mockNameValues.put(Email.TYPE, Email.TYPE_CUSTOM);
- mockNameValues.put(Email.LABEL, "custom_type");
- mockNameValues.put(Email.ADDRESS, "address1");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
- mockNameValues.put(Email.TYPE, Email.TYPE_HOME);
- mockNameValues.put(Email.ADDRESS, "address2");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
- mockNameValues.put(Email.TYPE, Email.TYPE_WORK);
- mockNameValues.put(Email.ADDRESS, "address3");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- // Exchange can have up to 3 email entries. This 4th entry should be dropped.
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
- mockNameValues.put(Email.TYPE, Email.TYPE_OTHER);
- mockNameValues.put(Email.ADDRESS, "address4");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
-
- List<ValuesDelta> list = newState.getMimeEntries(Email.CONTENT_ITEM_TYPE);
- assertNotNull(list);
- assertEquals(3, list.size());
-
- ContentValues outputValues = list.get(0).getAfter();
- assertEquals(Email.TYPE_CUSTOM, outputValues.getAsInteger(Email.TYPE).intValue());
- assertEquals("custom_type", outputValues.getAsString(Email.LABEL));
- assertEquals("address1", outputValues.getAsString(Email.ADDRESS));
-
- outputValues = list.get(1).getAfter();
- assertEquals(Email.TYPE_HOME, outputValues.getAsInteger(Email.TYPE).intValue());
- assertEquals("address2", outputValues.getAsString(Email.ADDRESS));
-
- outputValues = list.get(2).getAfter();
- assertEquals(Email.TYPE_WORK, outputValues.getAsInteger(Email.TYPE).intValue());
- assertEquals("address3", outputValues.getAsString(Email.ADDRESS));
- }
-
- public void testMigrateImFromGoogleToExchange() {
- AccountType oldAccountType = new GoogleAccountType(getContext(), "");
- AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- DataKind kind = newAccountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
- // Exchange doesn't support TYPE_HOME
- mockNameValues.put(Im.TYPE, Im.TYPE_HOME);
- mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_JABBER);
- mockNameValues.put(Im.DATA, "im1");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
- // Exchange doesn't support TYPE_WORK
- mockNameValues.put(Im.TYPE, Im.TYPE_WORK);
- mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_YAHOO);
- mockNameValues.put(Im.DATA, "im2");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
- mockNameValues.put(Im.TYPE, Im.TYPE_OTHER);
- mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM);
- mockNameValues.put(Im.CUSTOM_PROTOCOL, "custom_protocol");
- mockNameValues.put(Im.DATA, "im3");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- // Exchange can have up to 3 IM entries. This 4th entry should be dropped.
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
- mockNameValues.put(Im.TYPE, Im.TYPE_OTHER);
- mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
- mockNameValues.put(Im.DATA, "im4");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
-
- List<ValuesDelta> list = newState.getMimeEntries(Im.CONTENT_ITEM_TYPE);
- assertNotNull(list);
- assertEquals(3, list.size());
-
- assertNotNull(kind.defaultValues.getAsInteger(Im.TYPE));
-
- int defaultType = kind.defaultValues.getAsInteger(Im.TYPE);
-
- ContentValues outputValues = list.get(0).getAfter();
- // HOME should become default type.
- assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
- assertEquals(Im.PROTOCOL_JABBER, outputValues.getAsInteger(Im.PROTOCOL).intValue());
- assertEquals("im1", outputValues.getAsString(Im.DATA));
-
- outputValues = list.get(1).getAfter();
- assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
- assertEquals(Im.PROTOCOL_YAHOO, outputValues.getAsInteger(Im.PROTOCOL).intValue());
- assertEquals("im2", outputValues.getAsString(Im.DATA));
-
- outputValues = list.get(2).getAfter();
- assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
- assertEquals(Im.PROTOCOL_CUSTOM, outputValues.getAsInteger(Im.PROTOCOL).intValue());
- assertEquals("custom_protocol", outputValues.getAsString(Im.CUSTOM_PROTOCOL));
- assertEquals("im3", outputValues.getAsString(Im.DATA));
- }
-
- public void testMigratePhoneFromGoogleToExchange() {
- AccountType oldAccountType = new GoogleAccountType(getContext(), "");
- AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- DataKind kind = newAccountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
-
- // Create 5 numbers.
- // - "1" -- HOME
- // - "2" -- WORK
- // - "3" -- CUSTOM
- // - "4" -- WORK
- // - "5" -- WORK_MOBILE
- // Then we convert it to Exchange account type.
- // - "1" -- HOME
- // - "2" -- WORK
- // - "3" -- Because CUSTOM is not supported, it'll be changed to the default, MOBILE
- // - "4" -- WORK
- // - "5" -- WORK_MOBILE not suppoted again, so will be MOBILE.
- // But then, Exchange doesn't support multiple MOBILE numbers, so "5" will be removed.
- // i.e. the result will be:
- // - "1" -- HOME
- // - "2" -- WORK
- // - "3" -- MOBILE
- // - "4" -- WORK
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- mockNameValues.put(Phone.TYPE, Phone.TYPE_HOME);
- mockNameValues.put(Phone.NUMBER, "1");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK);
- mockNameValues.put(Phone.NUMBER, "2");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- // Exchange doesn't support this type. Default to MOBILE
- mockNameValues.put(Phone.TYPE, Phone.TYPE_CUSTOM);
- mockNameValues.put(Phone.LABEL, "custom_type");
- mockNameValues.put(Phone.NUMBER, "3");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK);
- mockNameValues.put(Phone.NUMBER, "4");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- mockNameValues = new ContentValues();
-
- mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
- mockNameValues.put(Phone.NUMBER, "5");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
-
- List<ValuesDelta> list = newState.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
- assertNotNull(list);
- assertEquals(4, list.size());
-
- int defaultType = Phone.TYPE_MOBILE;
-
- ContentValues outputValues = list.get(0).getAfter();
- assertEquals(Phone.TYPE_HOME, outputValues.getAsInteger(Phone.TYPE).intValue());
- assertEquals("1", outputValues.getAsString(Phone.NUMBER));
- outputValues = list.get(1).getAfter();
- assertEquals(Phone.TYPE_WORK, outputValues.getAsInteger(Phone.TYPE).intValue());
- assertEquals("2", outputValues.getAsString(Phone.NUMBER));
- outputValues = list.get(2).getAfter();
- assertEquals(defaultType, outputValues.getAsInteger(Phone.TYPE).intValue());
- assertNull(outputValues.getAsInteger(Phone.LABEL));
- assertEquals("3", outputValues.getAsString(Phone.NUMBER));
- outputValues = list.get(3).getAfter();
- assertEquals(Phone.TYPE_WORK, outputValues.getAsInteger(Phone.TYPE).intValue());
- assertEquals("4", outputValues.getAsString(Phone.NUMBER));
- }
-
- public void testMigrateOrganizationFromGoogleToExchange() {
- AccountType oldAccountType = new GoogleAccountType(getContext(), "");
- AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
- DataKind kind = newAccountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
-
- RawContactDelta oldState = new RawContactDelta();
- ContentValues mockNameValues = new ContentValues();
- mockNameValues.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
- mockNameValues.put(Organization.COMPANY, "company1");
- mockNameValues.put(Organization.DEPARTMENT, "department1");
- oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
-
- RawContactDelta newState = new RawContactDelta();
- RawContactModifier.migrateGenericWithoutTypeColumn(oldState, newState, kind);
-
- List<ValuesDelta> list = newState.getMimeEntries(Organization.CONTENT_ITEM_TYPE);
- assertNotNull(list);
- assertEquals(1, list.size());
-
- ContentValues outputValues = list.get(0).getAfter();
- assertEquals("company1", outputValues.getAsString(Organization.COMPANY));
- assertEquals("department1", outputValues.getAsString(Organization.DEPARTMENT));
- }
-}
diff --git a/tests/src/com/android/contacts/activities/PeopleActivityTest.java b/tests/src/com/android/contacts/activities/PeopleActivityTest.java
index 4ede006..d882da7 100644
--- a/tests/src/com/android/contacts/activities/PeopleActivityTest.java
+++ b/tests/src/com/android/contacts/activities/PeopleActivityTest.java
@@ -45,10 +45,10 @@
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.model.account.BaseAccountType;
-import com.android.contacts.test.InjectedServices;
-import com.android.contacts.tests.mocks.MockAccountTypeManager;
-import com.android.contacts.tests.mocks.MockContactPhotoManager;
-import com.android.contacts.tests.mocks.MockSharedPreferences;
+import com.android.contacts.common.test.InjectedServices;
+import com.android.contacts.common.test.mocks.MockAccountTypeManager;
+import com.android.contacts.common.test.mocks.MockContactPhotoManager;
+import com.android.contacts.common.test.mocks.MockSharedPreferences;
import com.android.contacts.util.PhoneCapabilityTester;
/**
diff --git a/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java b/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
index 1747add..9c52161 100644
--- a/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
+++ b/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
@@ -25,9 +25,9 @@
import android.test.suitebuilder.annotation.SmallTest;
import com.android.contacts.detail.ContactDetailFragment.DetailViewEntry;
-import com.android.contacts.model.dataitem.DataItem;
-import com.android.contacts.model.dataitem.EmailDataItem;
-import com.android.contacts.model.dataitem.ImDataItem;
+import com.android.contacts.common.model.dataitem.DataItem;
+import com.android.contacts.common.model.dataitem.EmailDataItem;
+import com.android.contacts.common.model.dataitem.ImDataItem;
/**
* Tests for {@link ContactDetailFragment}.
diff --git a/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java b/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
index 7f1ee02..abd4680 100644
--- a/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
+++ b/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
@@ -22,6 +22,7 @@
import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemEntryBuilder;
+
import com.google.common.collect.Lists;
import java.util.ArrayList;
diff --git a/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java b/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java
index 0d38c95..c41c836 100644
--- a/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java
+++ b/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java
@@ -22,7 +22,7 @@
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.tests.mocks.MockAccountTypeManager;
+import com.android.contacts.common.test.mocks.MockAccountTypeManager;
import com.google.common.collect.Sets;
import java.util.Collection;
diff --git a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
index 34f1e4b..bcaa398 100644
--- a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
@@ -34,8 +34,8 @@
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.BaseAccountType;
-import com.android.contacts.test.InjectedServices;
-import com.android.contacts.tests.mocks.MockAccountTypeManager;
+import com.android.contacts.common.test.InjectedServices;
+import com.android.contacts.common.test.mocks.MockAccountTypeManager;
/**
* Tests for {@link ContactDeletionInteraction}.
diff --git a/tests/src/com/android/contacts/model/ContactLoaderTest.java b/tests/src/com/android/contacts/model/ContactLoaderTest.java
deleted file mode 100644
index 60d6930..0000000
--- a/tests/src/com/android/contacts/model/ContactLoaderTest.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2010 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.model;
-
-import android.content.ContentUris;
-import android.net.Uri;
-import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.DisplayNameSources;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.StatusUpdates;
-import android.test.LoaderTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.test.mocks.ContactsMockContext;
-import com.android.contacts.common.test.mocks.MockContentProvider;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.common.model.account.BaseAccountType;
-import com.android.contacts.test.InjectedServices;
-import com.android.contacts.tests.mocks.MockAccountTypeManager;
-
-/**
- * Runs ContactLoader tests for the the contact-detail and editor view.
- */
-@LargeTest
-public class ContactLoaderTest extends LoaderTestCase {
- private ContactsMockContext mMockContext;
- private MockContentProvider mContactsProvider;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mMockContext = new ContactsMockContext(getContext());
- mContactsProvider = mMockContext.getContactsProvider();
-
- InjectedServices services = new InjectedServices();
- AccountType accountType = new BaseAccountType() {
- @Override
- public boolean areContactsWritable() {
- return false;
- }
- };
- accountType.accountType = "mockAccountType";
-
- AccountWithDataSet account =
- new AccountWithDataSet("mockAccountName", "mockAccountType", null);
-
- AccountTypeManager.setInstanceForTest(
- new MockAccountTypeManager(
- new AccountType[]{accountType}, new AccountWithDataSet[]{account}));
- }
-
- @Override
- protected void tearDown() throws Exception {
- mMockContext = null;
- mContactsProvider = null;
- super.tearDown();
- }
-
- private Contact assertLoadContact(Uri uri) {
- final ContactLoader loader = new ContactLoader(mMockContext, uri, true);
- return getLoaderResultSynchronously(loader);
- }
-
- public void testNullUri() {
- Contact result = assertLoadContact(null);
- assertTrue(result.isError());
- }
-
- public void testEmptyUri() {
- Contact result = assertLoadContact(Uri.EMPTY);
- assertTrue(result.isError());
- }
-
- public void testInvalidUri() {
- Contact result = assertLoadContact(Uri.parse("content://wtf"));
- assertTrue(result.isError());
- }
-
- public void testLoadContactWithContactIdUri() {
- // Use content Uris that only contain the ID
- final long contactId = 1;
- final long rawContactId = 11;
- final long dataId = 21;
-
- final String lookupKey = "aa%12%@!";
- final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
- final Uri entityUri = Uri.withAppendedPath(baseUri, Contacts.Entity.CONTENT_DIRECTORY);
- final Uri lookupUri = ContentUris.withAppendedId(
- Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey),
- contactId);
-
- ContactQueries queries = new ContactQueries();
- mContactsProvider.expectTypeQuery(baseUri, Contacts.CONTENT_ITEM_TYPE);
- queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
-
- Contact contact = assertLoadContact(baseUri);
-
- assertEquals(contactId, contact.getId());
- assertEquals(rawContactId, contact.getNameRawContactId());
- assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
- assertEquals(lookupKey, contact.getLookupKey());
- assertEquals(lookupUri, contact.getLookupUri());
- assertEquals(1, contact.getRawContacts().size());
- assertEquals(1, contact.getStatuses().size());
- mContactsProvider.verify();
- }
-
- public void testLoadContactWithOldStyleUri() {
- // Use content Uris that only contain the ID but use the format used in Donut
- final long contactId = 1;
- final long rawContactId = 11;
- final long dataId = 21;
-
- final String lookupKey = "aa%12%@!";
- final Uri legacyUri = ContentUris.withAppendedId(
- Uri.parse("content://contacts"), rawContactId);
- final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
- final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
- final Uri lookupUri = ContentUris.withAppendedId(
- Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey),
- contactId);
- final Uri entityUri = Uri.withAppendedPath(lookupUri, Contacts.Entity.CONTENT_DIRECTORY);
-
- ContactQueries queries = new ContactQueries();
- queries.fetchContactIdAndLookupFromRawContactUri(rawContactUri, contactId, lookupKey);
- queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
-
- Contact contact = assertLoadContact(legacyUri);
-
- assertEquals(contactId, contact.getId());
- assertEquals(rawContactId, contact.getNameRawContactId());
- assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
- assertEquals(lookupKey, contact.getLookupKey());
- assertEquals(lookupUri, contact.getLookupUri());
- assertEquals(1, contact.getRawContacts().size());
- assertEquals(1, contact.getStatuses().size());
- mContactsProvider.verify();
- }
-
- public void testLoadContactWithRawContactIdUri() {
- // Use content Uris that only contain the ID but use the format used in Donut
- final long contactId = 1;
- final long rawContactId = 11;
- final long dataId = 21;
-
- final String lookupKey = "aa%12%@!";
- final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
- final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
- final Uri lookupUri = ContentUris.withAppendedId(
- Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey),
- contactId);
- final Uri entityUri = Uri.withAppendedPath(lookupUri, Contacts.Entity.CONTENT_DIRECTORY);
-
- ContactQueries queries = new ContactQueries();
- mContactsProvider.expectTypeQuery(rawContactUri, RawContacts.CONTENT_ITEM_TYPE);
- queries.fetchContactIdAndLookupFromRawContactUri(rawContactUri, contactId, lookupKey);
- queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
-
- Contact contact = assertLoadContact(rawContactUri);
-
- assertEquals(contactId, contact.getId());
- assertEquals(rawContactId, contact.getNameRawContactId());
- assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
- assertEquals(lookupKey, contact.getLookupKey());
- assertEquals(lookupUri, contact.getLookupUri());
- assertEquals(1, contact.getRawContacts().size());
- assertEquals(1, contact.getStatuses().size());
- mContactsProvider.verify();
- }
-
- public void testLoadContactWithContactLookupUri() {
- // Use lookup-style Uris that do not contain the Contact-ID
-
- final long contactId = 1;
- final long rawContactId = 11;
- final long dataId = 21;
-
- final String lookupKey = "aa%12%@!";
- final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
- final Uri lookupNoIdUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey);
- final Uri lookupUri = ContentUris.withAppendedId(lookupNoIdUri, contactId);
- final Uri entityUri = Uri.withAppendedPath(lookupNoIdUri, Contacts.Entity.CONTENT_DIRECTORY);
-
- ContactQueries queries = new ContactQueries();
- mContactsProvider.expectTypeQuery(lookupNoIdUri, Contacts.CONTENT_ITEM_TYPE);
- queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
-
- Contact contact = assertLoadContact(lookupNoIdUri);
-
- assertEquals(contactId, contact.getId());
- assertEquals(rawContactId, contact.getNameRawContactId());
- assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
- assertEquals(lookupKey, contact.getLookupKey());
- assertEquals(lookupUri, contact.getLookupUri());
- assertEquals(1, contact.getRawContacts().size());
- assertEquals(1, contact.getStatuses().size());
- mContactsProvider.verify();
- }
-
- public void testLoadContactWithContactLookupAndIdUri() {
- // Use lookup-style Uris that also contain the Contact-ID
- final long contactId = 1;
- final long rawContactId = 11;
- final long dataId = 21;
-
- final String lookupKey = "aa%12%@!";
- final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
- final Uri lookupUri = ContentUris.withAppendedId(
- Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey),
- contactId);
- final Uri entityUri = Uri.withAppendedPath(lookupUri, Contacts.Entity.CONTENT_DIRECTORY);
-
- ContactQueries queries = new ContactQueries();
- mContactsProvider.expectTypeQuery(lookupUri, Contacts.CONTENT_ITEM_TYPE);
- queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
-
- Contact contact = assertLoadContact(lookupUri);
-
- assertEquals(contactId, contact.getId());
- assertEquals(rawContactId, contact.getNameRawContactId());
- assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
- assertEquals(lookupKey, contact.getLookupKey());
- assertEquals(lookupUri, contact.getLookupUri());
- assertEquals(1, contact.getRawContacts().size());
- assertEquals(1, contact.getStatuses().size());
- mContactsProvider.verify();
- }
-
- public void testLoadContactWithContactLookupWithIncorrectIdUri() {
- // Use lookup-style Uris that contain incorrect Contact-ID
- // (we want to ensure that still the correct contact is chosen)
-
- final long contactId = 1;
- final long wrongContactId = 2;
- final long rawContactId = 11;
- final long wrongRawContactId = 12;
- final long dataId = 21;
-
- final String lookupKey = "aa%12%@!";
- final String wrongLookupKey = "ab%12%@!";
- final Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
- final Uri wrongBaseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, wrongContactId);
- final Uri lookupUri = ContentUris.withAppendedId(
- Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey),
- contactId);
- final Uri lookupWithWrongIdUri = ContentUris.withAppendedId(
- Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey),
- wrongContactId);
- final Uri entityUri = Uri.withAppendedPath(lookupWithWrongIdUri,
- Contacts.Entity.CONTENT_DIRECTORY);
-
- ContactQueries queries = new ContactQueries();
- mContactsProvider.expectTypeQuery(lookupWithWrongIdUri, Contacts.CONTENT_ITEM_TYPE);
- queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
-
- Contact contact = assertLoadContact(lookupWithWrongIdUri);
-
- assertEquals(contactId, contact.getId());
- assertEquals(rawContactId, contact.getNameRawContactId());
- assertEquals(DisplayNameSources.STRUCTURED_NAME, contact.getDisplayNameSource());
- assertEquals(lookupKey, contact.getLookupKey());
- assertEquals(lookupUri, contact.getLookupUri());
- assertEquals(1, contact.getRawContacts().size());
- assertEquals(1, contact.getStatuses().size());
-
- mContactsProvider.verify();
- }
-
- class ContactQueries {
- public void fetchAllData(
- Uri baseUri, long contactId, long rawContactId, long dataId, String encodedLookup) {
- mContactsProvider.expectQuery(baseUri)
- .withProjection(new String[] {
- Contacts.NAME_RAW_CONTACT_ID, Contacts.DISPLAY_NAME_SOURCE,
- Contacts.LOOKUP_KEY, Contacts.DISPLAY_NAME,
- Contacts.DISPLAY_NAME_ALTERNATIVE, Contacts.PHONETIC_NAME,
- Contacts.PHOTO_ID, Contacts.STARRED, Contacts.CONTACT_PRESENCE,
- Contacts.CONTACT_STATUS, Contacts.CONTACT_STATUS_TIMESTAMP,
- Contacts.CONTACT_STATUS_RES_PACKAGE, Contacts.CONTACT_STATUS_LABEL,
-
- Contacts.Entity.CONTACT_ID,
- Contacts.Entity.RAW_CONTACT_ID,
-
- RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_TYPE,
- RawContacts.DATA_SET, RawContacts.ACCOUNT_TYPE_AND_DATA_SET,
- RawContacts.DIRTY, RawContacts.VERSION, RawContacts.SOURCE_ID,
- RawContacts.SYNC1, RawContacts.SYNC2, RawContacts.SYNC3, RawContacts.SYNC4,
- RawContacts.DELETED, RawContacts.NAME_VERIFIED,
-
- Contacts.Entity.DATA_ID,
-
- Data.DATA1, Data.DATA2, Data.DATA3, Data.DATA4, Data.DATA5,
- Data.DATA6, Data.DATA7, Data.DATA8, Data.DATA9, Data.DATA10,
- Data.DATA11, Data.DATA12, Data.DATA13, Data.DATA14, Data.DATA15,
- Data.SYNC1, Data.SYNC2, Data.SYNC3, Data.SYNC4,
- Data.DATA_VERSION, Data.IS_PRIMARY,
- Data.IS_SUPER_PRIMARY, Data.MIMETYPE, Data.RES_PACKAGE,
-
- GroupMembership.GROUP_SOURCE_ID,
-
- Data.PRESENCE, Data.CHAT_CAPABILITY,
- Data.STATUS, Data.STATUS_RES_PACKAGE, Data.STATUS_ICON,
- Data.STATUS_LABEL, Data.STATUS_TIMESTAMP,
-
- Contacts.PHOTO_URI,
-
- Contacts.SEND_TO_VOICEMAIL,
- Contacts.CUSTOM_RINGTONE,
- Contacts.IS_USER_PROFILE,
- })
- .withSortOrder(Contacts.Entity.RAW_CONTACT_ID)
- .returnRow(
- rawContactId, 40,
- "aa%12%@!", "John Doe", "Doe, John", "jdo",
- 0, 0, StatusUpdates.AVAILABLE,
- "Having lunch", 0,
- "mockPkg1", 10,
-
- contactId,
- rawContactId,
-
- "mockAccountName", "mockAccountType", null, "mockAccountType",
- 0, 1, 0,
- "sync1", "sync2", "sync3", "sync4",
- 0, 0,
-
- dataId,
-
- "dat1", "dat2", "dat3", "dat4", "dat5",
- "dat6", "dat7", "dat8", "dat9", "dat10",
- "dat11", "dat12", "dat13", "dat14", "dat15",
- "syn1", "syn2", "syn3", "syn4",
-
- 0, 0,
- 0, StructuredName.CONTENT_ITEM_TYPE, "mockPkg2",
-
- "groupId",
-
- StatusUpdates.INVISIBLE, null,
- "Having dinner", "mockPkg3", 0,
- 20, 0,
-
- "content:some.photo.uri",
-
- 0,
- null,
- 0
- );
- }
-
- void fetchLookupAndId(final Uri sourceUri, final long expectedContactId,
- final String expectedEncodedLookup) {
- mContactsProvider.expectQuery(sourceUri)
- .withProjection(Contacts.LOOKUP_KEY, Contacts._ID)
- .returnRow(expectedEncodedLookup, expectedContactId);
- }
-
- void fetchContactIdAndLookupFromRawContactUri(final Uri rawContactUri,
- final long expectedContactId, final String expectedEncodedLookup) {
- // TODO: use a lighter query by joining rawcontacts with contacts in provider
- // (See ContactContracts.java)
- final Uri dataUri = Uri.withAppendedPath(rawContactUri,
- RawContacts.Data.CONTENT_DIRECTORY);
- mContactsProvider.expectQuery(dataUri)
- .withProjection(RawContacts.CONTACT_ID, Contacts.LOOKUP_KEY)
- .returnRow(expectedContactId, expectedEncodedLookup);
- }
- }
-}
diff --git a/tests/src/com/android/contacts/model/RawContactTest.java b/tests/src/com/android/contacts/model/RawContactTest.java
deleted file mode 100644
index f09e64f..0000000
--- a/tests/src/com/android/contacts/model/RawContactTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2012 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.model;
-
-import android.content.ContentValues;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import junit.framework.TestCase;
-
-/**
- * Unit test for {@link RawContact}.
- */
-public class RawContactTest extends TestCase {
-
- private RawContact buildRawContact() {
- final ContentValues values = new ContentValues();
- values.put("key1", "value1");
- values.put("key2", "value2");
-
- final ContentValues dataItem = new ContentValues();
- dataItem.put("key3", "value3");
- dataItem.put("key4", "value4");
-
- final RawContact contact = new RawContact(values);
- contact.addDataItemValues(dataItem);
-
- return contact;
- }
-
- private RawContact buildRawContact2() {
- final ContentValues values = new ContentValues();
- values.put("key11", "value11");
- values.put("key22", "value22");
-
- final ContentValues dataItem = new ContentValues();
- dataItem.put("key33", "value33");
- dataItem.put("key44", "value44");
-
- final RawContact contact = new RawContact(values);
- contact.addDataItemValues(dataItem);
-
- return contact;
- }
-
- public void testNotEquals() {
- final RawContact one = buildRawContact();
- final RawContact two = buildRawContact2();
- assertFalse(one.equals(two));
- }
-
- public void testEquals() {
- assertEquals(buildRawContact(), buildRawContact());
- }
-
- public void testParcelable() {
- assertParcelableEquals(buildRawContact());
- }
-
- private RawContact.NamedDataItem buildNamedDataItem() {
- final ContentValues values = new ContentValues();
- values.put("key1", "value1");
- values.put("key2", "value2");
- final Uri uri = Uri.fromParts("content:", "ssp", "fragment");
-
- return new RawContact.NamedDataItem(uri, values);
- }
-
- private RawContact.NamedDataItem buildNamedDataItem2() {
- final ContentValues values = new ContentValues();
- values.put("key11", "value11");
- values.put("key22", "value22");
- final Uri uri = Uri.fromParts("content:", "blah", "blah");
-
- return new RawContact.NamedDataItem(uri, values);
- }
-
- public void testNamedDataItemEquals() {
- assertEquals(buildNamedDataItem(), buildNamedDataItem());
- }
-
- public void testNamedDataItemNotEquals() {
- assertFalse(buildNamedDataItem().equals(buildNamedDataItem2()));
- }
-
- public void testNamedDataItemParcelable() {
- assertParcelableEquals(buildNamedDataItem());
- }
-
- private void assertParcelableEquals(Parcelable parcelable) {
- final Parcel parcel = Parcel.obtain();
- try {
- parcel.writeParcelable(parcelable, 0);
- parcel.setDataPosition(0);
-
- Parcelable out = parcel.readParcelable(parcelable.getClass().getClassLoader());
- assertEquals(parcelable, out);
- } finally {
- parcel.recycle();
- }
- }
-}
diff --git a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
deleted file mode 100644
index 3357af3..0000000
--- a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2010 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.tests.mocks;
-
-import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountTypeWithDataSet;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A mock {@link AccountTypeManager} class.
- */
-public class MockAccountTypeManager extends AccountTypeManager {
-
- public AccountType[] mTypes;
- public AccountWithDataSet[] mAccounts;
-
- public MockAccountTypeManager(AccountType[] types, AccountWithDataSet[] accounts) {
- this.mTypes = types;
- this.mAccounts = accounts;
- }
-
- @Override
- public AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet) {
- for (AccountType type : mTypes) {
- if (Objects.equal(accountTypeWithDataSet.accountType, type.accountType)
- && Objects.equal(accountTypeWithDataSet.dataSet, type.dataSet)) {
- return type;
- }
- }
- return null;
- }
-
- @Override
- public List<AccountWithDataSet> getAccounts(boolean writableOnly) {
- return Arrays.asList(mAccounts);
- }
-
- @Override
- public List<AccountWithDataSet> getGroupWritableAccounts() {
- return Arrays.asList(mAccounts);
- }
-
- @Override
- public Map<AccountTypeWithDataSet, AccountType> getUsableInvitableAccountTypes() {
- return Maps.newHashMap(); // Always returns empty
- }
-
- @Override
- public List<AccountType> getAccountTypes(boolean writableOnly) {
- final List<AccountType> ret = Lists.newArrayList();
- synchronized (this) {
- for (AccountType type : mTypes) {
- if (!writableOnly || type.areContactsWritable()) {
- ret.add(type);
- }
- }
- }
- return ret;
- }
-}
diff --git a/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java b/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java
deleted file mode 100644
index f5f6084..0000000
--- a/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2011 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.tests.mocks;
-
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.widget.ImageView;
-
-import com.android.contacts.common.ContactPhotoManager;
-
-/**
- * A photo preloader that always uses the "no contact" picture and never executes any real
- * db queries
- */
-public class MockContactPhotoManager extends ContactPhotoManager {
- @Override
- public void loadThumbnail(ImageView view, long photoId, boolean darkTheme,
- DefaultImageProvider defaultProvider) {
- defaultProvider.applyDefaultImage(view, -1, darkTheme);
- }
-
- @Override
- public void loadPhoto(ImageView view, Uri photoUri, int requestedExtent, boolean darkTheme,
- DefaultImageProvider defaultProvider) {
- defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme);
- }
-
- @Override
- public void removePhoto(ImageView view) {
- view.setImageDrawable(null);
- }
-
- @Override
- public void pause() {
- }
-
- @Override
- public void resume() {
- }
-
- @Override
- public void refreshCache() {
- }
-
- @Override
- public void cacheBitmap(Uri photoUri, Bitmap bitmap, byte[] photoBytes) {
- }
-
- @Override
- public void preloadPhotosInBackground() {
- }
-}
diff --git a/tests/src/com/android/contacts/tests/mocks/MockSharedPreferences.java b/tests/src/com/android/contacts/tests/mocks/MockSharedPreferences.java
deleted file mode 100644
index 536ba7f..0000000
--- a/tests/src/com/android/contacts/tests/mocks/MockSharedPreferences.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2010 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.tests.mocks;
-
-import android.content.SharedPreferences;
-
-import com.google.common.collect.Maps;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-
-/**
- * A programmable mock content provider.
- */
-public class MockSharedPreferences implements SharedPreferences, SharedPreferences.Editor {
-
- private HashMap<String, Object> mValues = Maps.newHashMap();
- private HashMap<String, Object> mTempValues = Maps.newHashMap();
-
- public Editor edit() {
- return this;
- }
-
- public boolean contains(String key) {
- return mValues.containsKey(key);
- }
-
- public Map<String, ?> getAll() {
- return new HashMap<String, Object>(mValues);
- }
-
- public boolean getBoolean(String key, boolean defValue) {
- if (mValues.containsKey(key)) {
- return ((Boolean)mValues.get(key)).booleanValue();
- }
- return defValue;
- }
-
- public float getFloat(String key, float defValue) {
- if (mValues.containsKey(key)) {
- return ((Float)mValues.get(key)).floatValue();
- }
- return defValue;
- }
-
- public int getInt(String key, int defValue) {
- if (mValues.containsKey(key)) {
- return ((Integer)mValues.get(key)).intValue();
- }
- return defValue;
- }
-
- public long getLong(String key, long defValue) {
- if (mValues.containsKey(key)) {
- return ((Long)mValues.get(key)).longValue();
- }
- return defValue;
- }
-
- public String getString(String key, String defValue) {
- if (mValues.containsKey(key))
- return (String)mValues.get(key);
- return defValue;
- }
-
- @SuppressWarnings("unchecked")
- public Set<String> getStringSet(String key, Set<String> defValues) {
- if (mValues.containsKey(key)) {
- return (Set<String>) mValues.get(key);
- }
- return defValues;
- }
-
- public void registerOnSharedPreferenceChangeListener(
- OnSharedPreferenceChangeListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public void unregisterOnSharedPreferenceChangeListener(
- OnSharedPreferenceChangeListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public Editor putBoolean(String key, boolean value) {
- mTempValues.put(key, Boolean.valueOf(value));
- return this;
- }
-
- public Editor putFloat(String key, float value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putInt(String key, int value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putLong(String key, long value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putString(String key, String value) {
- mTempValues.put(key, value);
- return this;
- }
-
- public Editor putStringSet(String key, Set<String> values) {
- mTempValues.put(key, values);
- return this;
- }
-
- public Editor remove(String key) {
- mTempValues.remove(key);
- return this;
- }
-
- public Editor clear() {
- mTempValues.clear();
- return this;
- }
-
- @SuppressWarnings("unchecked")
- public boolean commit() {
- mValues = (HashMap<String, Object>)mTempValues.clone();
- return true;
- }
-
- public void apply() {
- commit();
- }
-}
diff --git a/tests/src/com/android/contacts/util/NameConverterTests.java b/tests/src/com/android/contacts/util/NameConverterTests.java
deleted file mode 100644
index e1773a7..0000000
--- a/tests/src/com/android/contacts/util/NameConverterTests.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2011 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.util;
-
-import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.text.TextUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Tests for {@link NameConverter}.
- */
-@SmallTest
-public class NameConverterTests extends AndroidTestCase {
-
- public void testStructuredNameToDisplayName() {
- Map<String, String> structuredName = new HashMap<String, String>();
- structuredName.put(StructuredName.PREFIX, "Mr.");
- structuredName.put(StructuredName.GIVEN_NAME, "John");
- structuredName.put(StructuredName.MIDDLE_NAME, "Quincy");
- structuredName.put(StructuredName.FAMILY_NAME, "Adams");
- structuredName.put(StructuredName.SUFFIX, "Esquire");
-
- assertEquals("Mr. John Quincy Adams, Esquire",
- NameConverter.structuredNameToDisplayName(mContext, structuredName));
-
- structuredName.remove(StructuredName.SUFFIX);
- assertEquals("Mr. John Quincy Adams",
- NameConverter.structuredNameToDisplayName(mContext, structuredName));
-
- structuredName.remove(StructuredName.MIDDLE_NAME);
- assertEquals("Mr. John Adams",
- NameConverter.structuredNameToDisplayName(mContext, structuredName));
- }
-
- public void testDisplayNameToStructuredName() {
- assertStructuredName("Mr. John Quincy Adams, Esquire",
- "Mr.", "John", "Quincy", "Adams", "Esquire");
- assertStructuredName("John Doe", null, "John", null, "Doe", null);
- assertStructuredName("Ms. Jane Eyre", "Ms.", "Jane", null, "Eyre", null);
- assertStructuredName("Dr Leo Spaceman, PhD", "Dr", "Leo", null, "Spaceman", "PhD");
- }
-
- /**
- * Helper method to check whether a given display name parses out to the other parameters.
- * @param displayName Display name to break into a structured name.
- * @param prefix Expected prefix (null if not expected).
- * @param givenName Expected given name (null if not expected).
- * @param middleName Expected middle name (null if not expected).
- * @param familyName Expected family name (null if not expected).
- * @param suffix Expected suffix (null if not expected).
- */
- private void assertStructuredName(String displayName, String prefix,
- String givenName, String middleName, String familyName, String suffix) {
- Map<String, String> structuredName = NameConverter.displayNameToStructuredName(mContext,
- displayName);
- checkNameComponent(StructuredName.PREFIX, prefix, structuredName);
- checkNameComponent(StructuredName.GIVEN_NAME, givenName, structuredName);
- checkNameComponent(StructuredName.MIDDLE_NAME, middleName, structuredName);
- checkNameComponent(StructuredName.FAMILY_NAME, familyName, structuredName);
- checkNameComponent(StructuredName.SUFFIX, suffix, structuredName);
- assertEquals(0, structuredName.size());
- }
-
- /**
- * Checks that the given field and value are present in the structured name map (or not present
- * if the given value is null). If the value is present and matches, the key is removed from
- * the map - once all components of the name are checked, the map should be empty.
- * @param field Field to check.
- * @param value Expected value for the field (null if it is not expected to be populated).
- * @param structuredName The map of structured field names to values.
- */
- private void checkNameComponent(String field, String value,
- Map<String, String> structuredName) {
- if (TextUtils.isEmpty(value)) {
- assertNull(structuredName.get(field));
- } else {
- assertEquals(value, structuredName.get(field));
- }
- structuredName.remove(field);
- }
-}